1 /**********************************************************************
2 * Copyright (c) 2005, 2014 IBM Corporation, Ericsson
3 * All rights reserved. This program and the accompanying materials
4 * are made available under the terms of the Eclipse Public License v1.0
5 * which accompanies this distribution, and is available at
6 * http://www.eclipse.org/legal/epl-v10.html
9 * IBM - Initial API and implementation
10 * Bernd Hufmann - Updated for TMF
11 **********************************************************************/
13 package org
.eclipse
.tracecompass
.tmf
.ui
.views
.uml2sd
.core
;
15 import java
.util
.ArrayList
;
16 import java
.util
.Arrays
;
17 import java
.util
.Iterator
;
18 import java
.util
.List
;
20 import org
.eclipse
.tracecompass
.tmf
.core
.timestamp
.ITmfTimestamp
;
21 import org
.eclipse
.tracecompass
.tmf
.ui
.views
.uml2sd
.drawings
.IColor
;
22 import org
.eclipse
.tracecompass
.tmf
.ui
.views
.uml2sd
.drawings
.IGC
;
23 import org
.eclipse
.tracecompass
.tmf
.ui
.views
.uml2sd
.preferences
.SDViewPref
;
24 import org
.eclipse
.tracecompass
.tmf
.ui
.views
.uml2sd
.util
.TimeEventComparator
;
27 * The Frame class is the base sequence diagram graph nodes container.<br>
28 * For instance, only one frame can be drawn in the View.<br>
29 * Lifelines, Messages and Stop which are supposed to represent a Sequence diagram are drawn in a Frame.<br>
30 * Only the graph node added to their representing list will be drawn.
32 * The lifelines are appended along the X axsis when added in a frame.<br>
33 * The syncMessages are ordered along the Y axsis depending on the event occurrence they are attached to.<br>
35 * @see org.eclipse.tracecompass.tmf.ui.views.uml2sd.core.Lifeline Lifeline for more event occurence details
39 public class Frame
extends BasicFrame
{
41 // ------------------------------------------------------------------------
43 // ------------------------------------------------------------------------
45 * The lifeline that is current highlighted.
47 private Lifeline fHighlightLifeline
= null;
49 * The value of the start event.
51 private int fStartEvent
= 0;
53 * The number of events in the frame.
55 private int fNbEvent
= 0;
57 * The color for highlighting.
59 private IColor fHighlightColor
= null;
61 * The list of time events of the corresponding execution occurrences.
63 private List
<SDTimeEvent
> fExecutionOccurrencesWithTime
;
65 * The Array of lifeline categories.
67 private LifelineCategories
[] fLifelineCategories
= null;
69 // ------------------------------------------------------------------------
71 // ------------------------------------------------------------------------
74 * Returns a list of all lifelines known by this frame. Known lifelines are the only one which can be displayed on
77 * @return the lifelines list
79 protected List
<GraphNode
> getLifelines() {
83 return getNodeMap().get(Lifeline
.LIFELINE_TAG
);
87 * Returns the number of lifelines stored in the frame
89 * @return the number of lifelines
91 public int lifeLinesCount() {
92 List
<GraphNode
> lifelines
= getLifelines();
93 if (lifelines
!= null) {
94 return lifelines
.size();
100 * Returns the lifeline at the given index in the lifelines array
102 * @param index the position in the lifeline array
103 * @return the lifeline or <code>null</code>
105 public Lifeline
getLifeline(int index
) {
106 if ((getLifelines() != null) && (index
>= 0) && (index
< lifeLinesCount())) {
107 return (Lifeline
) getLifelines().get(index
);
113 * Returns a list of syncMessages known by this frame. Known syncMessages are the only on which can be displayed on
116 * @return the syncMessages list
118 protected List
<GraphNode
> getSyncMessages() {
119 if (!hasChildren()) {
122 return getNodeMap().get(SyncMessage
.SYNC_MESS_TAG
);
126 * Returns the number of syncMessages stored in the frame
128 * @return the number of syncMessage
130 public int syncMessageCount() {
131 if (getSyncMessages() != null) {
132 return getSyncMessages().size();
138 * Returns the syncMessage at the given index in the syncMessages array
140 * @param index the position in the syncMessages array
141 * @return the syncMessage or <code>null</code>
143 public SyncMessage
getSyncMessage(int index
) {
144 if ((getSyncMessages() != null) && (index
>= 0) && (index
< getSyncMessages().size())) {
145 return (SyncMessage
) getSyncMessages().get(index
);
151 * Returns a list of asyncMessages known by this frame. Known asyncMessages are the only on which can be displayed
154 * @return the asyncMessages list or <code>null</code>
156 protected List
<GraphNode
> getAsyncMessages() {
157 if (!hasChildren()) {
160 return getNodeMap().get(AsyncMessage
.ASYNC_MESS_TAG
);
164 * Returns the number of asyncMessage stored in the frame
166 * @return the number of asyncMessage
168 public int asyncMessageCount() {
169 if (getAsyncMessages() != null) {
170 return getAsyncMessages().size();
176 * Returns the asyncMessage at the given index in the asyncMessage array
178 * @param index the position in the asyncMessage array
179 * @return the asyncMessage or <code>null</code>
181 public AsyncMessage
getAsyncMessage(int index
) {
182 if ((getAsyncMessages() != null) && (index
>= 0) && (index
< getAsyncMessages().size())) {
183 return (AsyncMessage
) getAsyncMessages().get(index
);
189 * Returns a list of syncMessages return known by this frame. Known syncMessages return are the only on which can be
190 * displayed on screen
192 * @return the syncMessages return list or <code>null</code>
194 protected List
<GraphNode
> getSyncMessagesReturn() {
195 if (!hasChildren()) {
198 return getNodeMap().get(SyncMessageReturn
.SYNC_MESS_RET_TAG
);
202 * Returns the number of syncMessageReturn stored in the frame
204 * @return the number of syncMessageReturn
206 public int syncMessageReturnCount() {
207 if (getSyncMessagesReturn() != null) {
208 return getSyncMessagesReturn().size();
214 * Returns the syncMessageReturn at the given index in the syncMessageReturn array
216 * @param index the position in the syncMessageReturn array
217 * @return the syncMessageReturn or <code>null</code>
219 public SyncMessageReturn
getSyncMessageReturn(int index
) {
220 if ((getSyncMessagesReturn() != null) && (index
>= 0) && (index
< getSyncMessagesReturn().size())) {
221 return (SyncMessageReturn
) getSyncMessagesReturn().get(index
);
227 * Returns a list of asyncMessageRetun known by this frame. Known asyncMessageRetun are the only on which can be
228 * displayed on screen
230 * @return the asyncMessageRetun list or <code>null</code>
232 protected List
<GraphNode
> getAsyncMessagesReturn() {
233 if (!hasChildren()) {
236 return getNodeMap().get(AsyncMessageReturn
.ASYNC_MESS_RET_TAG
);
240 * Returns the number of asyncMessageReturn stored in the frame
242 * @return the number of asyncMessageReturn
244 public int asyncMessageReturnCount() {
245 if (getAsyncMessagesReturn() != null) {
246 return getAsyncMessagesReturn().size();
252 * Returns the asyncMessageReturn at the given index in the asyncMessageReturn array
254 * @param index the position in the asyncMessageReturn array
255 * @return the asyncMessageReturn or <code>null</code>
257 public AsyncMessageReturn
getAsyncMessageReturn(int index
) {
258 if ((getAsyncMessagesReturn() != null) && (index
>= 0) && (index
< getAsyncMessagesReturn().size())) {
259 return (AsyncMessageReturn
) getAsyncMessagesReturn().get(index
);
265 * Adds a lifeline to the frame lifelines list. The lifeline X drawing order depends on the lifeline addition order
266 * into the frame lifelines list.
268 * @param lifeline the lifeline to add
270 public void addLifeLine(Lifeline lifeline
) {
271 setComputeMinMax(true);
272 if (lifeline
== null) {
275 // set the lifeline parent frame
276 lifeline
.setFrame(this);
277 // Increate the frame lifeline counter
278 // and set the lifeline drawing order
279 lifeline
.setIndex(getNewHorizontalIndex());
280 if (lifeline
.hasTimeInfo()) {
281 setHasTimeInfo(true);
283 // add the lifeline to the lifelines list
288 * Returns the first visible lifeline drawn in the view
290 * @return the first visible lifeline index
292 public int getFirstVisibleLifeline() {
293 if (!hasChildren()) {
295 } else if (getIndexes().get(Lifeline
.LIFELINE_TAG
) != null) {
296 return getIndexes().get(Lifeline
.LIFELINE_TAG
).intValue();
302 * Returns the first visible synchronous message drawn in the view
304 * @return the first visible synchronous message index
306 public int getFirstVisibleSyncMessage() {
307 if (!hasChildren()) {
309 } else if (getIndexes().get(SyncMessage
.SYNC_MESS_TAG
) != null) {
310 return getIndexes().get(SyncMessage
.SYNC_MESS_TAG
).intValue();
316 * Returns the first visible synchronous message return drawn in the view
318 * @return the first visible synchronous message return index
320 public int getFirstVisibleSyncMessageReturn() {
321 if (!hasChildren()) {
323 } else if (getIndexes().get(SyncMessageReturn
.SYNC_MESS_RET_TAG
) != null) {
324 return getIndexes().get(SyncMessageReturn
.SYNC_MESS_RET_TAG
).intValue();
330 * Returns the first visible synchronous message drawn in the view
332 * @return the first visible synchronous message index
334 public int getFirstVisibleAsyncMessage() {
335 if (!hasChildren()) {
337 } else if (getIndexes().get(AsyncMessage
.ASYNC_MESS_TAG
) != null) {
338 return getIndexes().get(AsyncMessage
.ASYNC_MESS_TAG
).intValue();
344 * Returns the first visible synchronous message return drawn in the view
346 * @return the first visible synchronous message return index
348 public int getFirstVisibleAsyncMessageReturn() {
349 if (!hasChildren()) {
351 } else if (getIndexes().get(AsyncMessageReturn
.ASYNC_MESS_RET_TAG
) != null) {
352 return getIndexes().get(AsyncMessageReturn
.ASYNC_MESS_RET_TAG
).intValue();
358 * Returns the list of execution occurrences.
360 * @return the list of execution occurrences
362 public List
<SDTimeEvent
> getExecutionOccurrencesWithTime() {
363 return fExecutionOccurrencesWithTime
;
367 * Inserts a lifeline after a given lifeline.
369 * @param toInsert A lifeline to insert
370 * @param after A lifelife the toInsert-lifeline will be inserted after.
372 public void insertLifelineAfter(Lifeline toInsert
, Lifeline after
) {
373 if ((toInsert
== null)) {
376 if (toInsert
== after
) {
381 insertPoint
= after
.getIndex();
383 int removePoint
= toInsert
.getIndex() - 1;
384 if (removePoint
>= insertPoint
) {
385 getLifelines().remove(removePoint
);
387 getLifelines().add(insertPoint
, toInsert
);
388 if (removePoint
< insertPoint
) {
389 getLifelines().remove(removePoint
);
392 if (removePoint
>= insertPoint
) {
393 toInsert
.setIndex(insertPoint
+ 1);
395 toInsert
.setIndex(insertPoint
- 1);
399 if (removePoint
>= insertPoint
) {
400 for (int i
= insertPoint
; i
< getLifelines().size(); i
++) {
401 getLifeline(i
).setIndex(i
+ 1);
404 for (int i
= 0; i
< insertPoint
&& i
< getLifelines().size(); i
++) {
405 getLifeline(i
).setIndex(i
+ 1);
411 * Inserts a lifeline before a given lifeline.
414 * A lifeline to insert
416 * A lifeline the toInsert-lifeline will be inserted before.
418 public void insertLifelineBefore(Lifeline toInsert
, Lifeline before
) {
419 if ((toInsert
== null)) {
422 if (toInsert
== before
) {
426 if (before
!= null) {
427 insertPoint
= before
.getIndex() - 1;
429 int removePoint
= toInsert
.getIndex() - 1;
430 if (removePoint
>= insertPoint
) {
431 getLifelines().remove(removePoint
);
433 getLifelines().add(insertPoint
, toInsert
);
434 if (removePoint
< insertPoint
) {
435 getLifelines().remove(removePoint
);
438 if (removePoint
>= insertPoint
) {
439 toInsert
.setIndex(insertPoint
+ 1);
441 toInsert
.setIndex(insertPoint
- 1);
445 if (removePoint
>= insertPoint
) {
446 for (int i
= insertPoint
; i
< getLifelines().size(); i
++) {
447 getLifeline(i
).setIndex(i
+ 1);
450 for (int i
= 0; i
< insertPoint
&& i
< getLifelines().size(); i
++) {
451 getLifeline(i
).setIndex(i
+ 1);
457 * Gets the closer life line to the given x-coordinate.
459 * @param x A x coordinate
460 * @return the closer lifeline
462 public Lifeline
getCloserLifeline(int x
) {
463 int index
= (x
- Metrics
.FRAME_H_MARGIN
+ Metrics
.LIFELINE_H_MAGIN
) / Metrics
.swimmingLaneWidth() - 1;
467 if (index
>= getLifelines().size()) {
468 index
= getLifelines().size() - 1;
470 Lifeline node1
, node2
, node3
;
471 int dist1
, dist2
, dist3
;
472 node1
= node2
= node3
= getLifeline(index
);
473 dist1
= dist2
= dist3
= Math
.abs(node1
.getX() + node1
.getWidth() / 2 - x
);
475 node2
= getLifeline(index
- 1);
476 dist2
= Math
.abs(node2
.getX() + node2
.getWidth() / 2 - x
);
478 if (index
< getLifelines().size() - 1) {
479 node3
= getLifeline(index
+ 1);
480 dist3
= Math
.abs(node3
.getX() + node3
.getWidth() / 2 - x
);
482 if (dist1
<= dist2
&& dist1
<= dist3
) {
484 } else if (dist2
<= dist1
&& dist2
<= dist3
) {
491 * Re-orders the given list of lifelines.
493 * @param list A list of lifelines to reorder.
495 public void reorder(List
<?
> list
) {
496 for (int i
= 0; i
< list
.size(); i
++) {
497 if (list
.get(i
) instanceof Lifeline
[]) {
498 Lifeline temp
[] = (Lifeline
[]) list
.get(i
);
499 if (temp
.length
== 2) {
500 if (temp
[1] == null) {
501 insertLifelineAfter(temp
[0], getLifeline(lifeLinesCount() - 1));
503 insertLifelineBefore(temp
[0], temp
[1]);
511 * Resets the time compression information.
513 public void resetTimeCompression() {
514 fHighlightLifeline
= null;
515 this.fStartEvent
= 0;
517 fHighlightColor
= null;
521 protected void computeMinMax() {
522 List
<SDTimeEvent
> timeArray
= buildTimeArray();
523 if ((timeArray
== null) || timeArray
.isEmpty()) {
526 for (int i
= 0; i
< timeArray
.size() - 1; i
++) {
527 SDTimeEvent m1
= timeArray
.get(i
);
528 SDTimeEvent m2
= timeArray
.get(i
+ 1);
529 if (SDViewPref
.getInstance().excludeExternalTime() && ((m1
.getGraphNode() instanceof BaseMessage
) && (m2
.getGraphNode() instanceof BaseMessage
))) {
530 BaseMessage mes1
= (BaseMessage
) m1
.getGraphNode();
531 BaseMessage mes2
= (BaseMessage
) m2
.getGraphNode();
532 if ((mes2
.getStartLifeline() == null) || (mes1
.getEndLifeline() == null)) {
537 updateMinMax(m1
, m2
);
542 * Find the two graph nodes that are closest to this date, one just earlier, second just later. If date is before
543 * any graph node, bounds[0] is null and bounds[1] is the earliest. If date is after any graph node, bounds[1] is
544 * null and bounds[0] is the latest.
546 * @param dateToFind date to be found
547 * @param bounds a two items array that will receive bounds if found
548 * @return true if both bounds not null
550 public boolean findDateBounds(ITmfTimestamp dateToFind
, ITimeRange bounds
[]) {
552 List
<SDTimeEvent
> timeArray
= buildTimeArray();
554 if ((timeArray
== null) || timeArray
.isEmpty()) {
560 for (int i
= 0; i
< timeArray
.size(); i
++) {
561 SDTimeEvent m
= timeArray
.get(i
);
562 if (m
.getTime().compareTo(dateToFind
) > 0) {
563 bounds
[1] = m
.getGraphNode();
565 bounds
[0] = timeArray
.get(i
- 1).getGraphNode();
571 bounds
[0] = timeArray
.get(timeArray
.size() - 1).getGraphNode();
577 * Highlights the time compression.
579 * @param lifeline A lifeline to highlight
580 * @param startEvent A start event number
581 * @param nbEvent A number of events
582 * @param color A color for highlighting
584 public void highlightTimeCompression(Lifeline lifeline
, int startEvent
, int nbEvent
, IColor color
) {
585 fHighlightLifeline
= lifeline
;
586 this.fStartEvent
= startEvent
;
587 this.fNbEvent
= nbEvent
;
588 fHighlightColor
= color
;
592 * Set the lifeline categories which will be use during the lifelines creation
594 * @see Lifeline#setCategory(int)
595 * @param categories the lifeline categories array
597 public void setLifelineCategories(LifelineCategories
[] categories
) {
598 fLifelineCategories
= Arrays
.copyOf(categories
, categories
.length
);
602 * Returns the lifeline categories array set for the this frame
604 * @return the lifeline categories array or null if not set
606 public LifelineCategories
[] getLifelineCategories() {
607 return Arrays
.copyOf(fLifelineCategories
, fLifelineCategories
.length
);
611 * Adds a message to the Frame message list. Four kinds of syncMessages can be added:<br>
612 * - synchronous syncMessages<br>
613 * - synchronous syncMessages return<br>
614 * - asynchronous syncMessages<br>
615 * - asynchronous syncMessages return<br>
616 * For drawing performance reason, it is recommended to add synchronous syncMessages in the same order they should
617 * appear along the Y axis in the Frame.
619 * @param message the message to add
621 public void addMessage(BaseMessage message
) {
626 public void draw(IGC context
) {
628 if (!hasChildren()) {
632 if (fHighlightLifeline
!= null) {
633 IColor backupColor
= context
.getBackground();
634 context
.setBackground(SDViewPref
.getInstance().getTimeCompressionSelectionColor());
635 int gy
= fHighlightLifeline
.getY() + fHighlightLifeline
.getHeight() + (Metrics
.getMessageFontHeigth() + Metrics
.getMessagesSpacing()) * fStartEvent
;
636 context
.fillRectangle(Metrics
.FRAME_H_MARGIN
+ 1, gy
, fHighlightLifeline
.getX() + Metrics
.getLifelineWidth() / 2 - Metrics
.FRAME_H_MARGIN
, (Metrics
.getMessageFontHeigth() + Metrics
.getMessagesSpacing()) * fNbEvent
);
637 context
.setBackground(backupColor
);
639 super.draw(context
, false);
640 int lifelineArryStep
= 1;
641 if (Metrics
.swimmingLaneWidth() * context
.getZoom() < Metrics
.LIFELINE_SIGNIFICANT_HSPACING
) {
642 lifelineArryStep
= Math
.round(Metrics
.LIFELINE_SIGNIFICANT_HSPACING
/ (Metrics
.swimmingLaneWidth() * context
.getZoom()));
644 if (getIndexes().size() == 0) {
647 int lifeLineDrawIndex
= getIndexes().get(Lifeline
.LIFELINE_TAG
).intValue();
648 for (int i
= lifeLineDrawIndex
; i
< getNodeMap().get(Lifeline
.LIFELINE_TAG
).size(); i
= i
+ lifelineArryStep
) {
649 Lifeline toDraw
= (Lifeline
) getNodeMap().get(Lifeline
.LIFELINE_TAG
).get(i
);
650 if (toDraw
.getX() - Metrics
.LIFELINE_SPACING
/ 2 > context
.getContentsX() + context
.getVisibleWidth()) {
653 toDraw
.drawName(context
);
655 if (fHighlightLifeline
!= null) {
656 if (toDraw
== fHighlightLifeline
) {
657 toDraw
.highlightExecOccurrenceRegion(context
, fStartEvent
, fNbEvent
, fHighlightColor
);
658 } else if ((toDraw
.getIndex() < fHighlightLifeline
.getIndex()) || ((toDraw
.getIndex() < fHighlightLifeline
.getIndex()))) {
660 int acIndex
= toDraw
.getExecOccurrenceDrawIndex();
661 // acIndex = first visible execution occurrence
662 // for drawing speed reason with only search on the visible subset
663 if (toDraw
.getExecutions() != null) {
664 for (int index
= acIndex
; index
< toDraw
.getExecutions().size(); index
++) {
665 BasicExecutionOccurrence exec
= (BasicExecutionOccurrence
) toDraw
.getExecutions().get(index
);
666 int tempEvent
= fStartEvent
;
667 for (int j
= 0; j
< fNbEvent
; j
++) {
668 if (((tempEvent
>= exec
.getStartOccurrence()) && (tempEvent
<= exec
.getEndOccurrence()) && (tempEvent
+ 1 >= exec
.getStartOccurrence()) && (tempEvent
+ 1 <= exec
.getEndOccurrence()))) {
669 toDraw
.highlightExecOccurrenceRegion(context
, tempEvent
, 1, SDViewPref
.getInstance().getTimeCompressionSelectionColor());
671 tempEvent
= tempEvent
+ 1;
673 // if we are outside the visible area we stop right now
674 // This works because execution occurrences are ordered along the Y axis
675 if (exec
.getY() > getY()) {
686 protected List
<SDTimeEvent
> buildTimeArray() {
688 if (!hasChildren()) {
689 return new ArrayList
<>();
692 List
<SDTimeEvent
> timeArray
= super.buildTimeArray();
693 fExecutionOccurrencesWithTime
= null;
694 if (getLifelines() != null) {
695 for (int i
= 0; i
< getNodeMap().get(Lifeline
.LIFELINE_TAG
).size(); i
++) {
696 Lifeline lifeline
= (Lifeline
) getNodeMap().get(Lifeline
.LIFELINE_TAG
).get(i
);
697 if (lifeline
.hasTimeInfo() && lifeline
.getExecutions() != null) {
698 for (Iterator
<GraphNode
> j
= lifeline
.getExecutions().iterator(); j
.hasNext();) {
699 GraphNode o
= j
.next();
700 if (o
instanceof ExecutionOccurrence
) {
701 ExecutionOccurrence eo
= (ExecutionOccurrence
) o
;
702 if (eo
.hasTimeInfo()) {
703 int event
= eo
.getStartOccurrence();
704 ITmfTimestamp time
= eo
.getStartTime();
705 SDTimeEvent f
= new SDTimeEvent(time
, event
, eo
);
707 if (fExecutionOccurrencesWithTime
== null) {
708 fExecutionOccurrencesWithTime
= new ArrayList
<>();
710 fExecutionOccurrencesWithTime
.add(f
);
711 event
= eo
.getEndOccurrence();
712 time
= eo
.getEndTime();
713 f
= new SDTimeEvent(time
, event
, eo
);
715 fExecutionOccurrencesWithTime
.add(f
);
723 if (fExecutionOccurrencesWithTime
!= null) {
724 SDTimeEvent
[] temp
= fExecutionOccurrencesWithTime
.toArray(new SDTimeEvent
[fExecutionOccurrencesWithTime
.size()]);
725 Arrays
.sort(temp
, new TimeEventComparator());
726 fExecutionOccurrencesWithTime
= Arrays
.asList(temp
);
728 SDTimeEvent
[] temp
= timeArray
.toArray(new SDTimeEvent
[timeArray
.size()]);
729 Arrays
.sort(temp
, new TimeEventComparator());
730 timeArray
= Arrays
.asList(temp
);
735 * Get the closer leaving message.
737 * @param lifeline A lifeline reference
738 * @param message A message reference
739 * @param list A list of graph nodes
740 * @param smallerEvent A smaller event flag
741 * @return the closer leaving message.
743 protected GraphNode
getCloserLeavingMessage(Lifeline lifeline
, BaseMessage message
, List
<GraphNode
> list
, boolean smallerEvent
) {
750 if (message
!= null) {
751 event
= message
.getEventOccurrence();
753 for (int i
= 0; i
< list
.size(); i
++) {
754 GraphNode node
= list
.get(i
);
755 if (node
instanceof SyncMessage
) {
756 SyncMessage syncNode
= (SyncMessage
) node
;
757 if ((syncNode
.getEventOccurrence() > event
) && (syncNode
.getStartLifeline() == lifeline
) && !syncNode
.isSameAs(message
)) {
760 } else if (node
instanceof AsyncMessage
) {
761 AsyncMessage asyncNode
= (AsyncMessage
) node
;
762 if ((asyncNode
.getStartOccurrence() > event
) && (asyncNode
.getStartLifeline() == lifeline
) && !asyncNode
.isSameAs(message
)) {
768 int event
= getMaxEventOccurrence();
769 if (message
!= null) {
770 if (message
instanceof AsyncMessage
) {
771 event
= ((AsyncMessage
) message
).getStartOccurrence();
773 event
= message
.getEventOccurrence();
776 for (int i
= list
.size() - 1; i
>= 0; i
--) {
777 GraphNode node
= list
.get(i
);
778 if (node
instanceof SyncMessage
) {
779 SyncMessage syncNode
= (SyncMessage
) node
;
780 if ((syncNode
.getEventOccurrence() < event
) && (syncNode
.getStartLifeline() == lifeline
) && !syncNode
.isSameAs(message
)) {
783 } else if (node
instanceof AsyncMessage
) {
784 AsyncMessage asyncNode
= (AsyncMessage
) node
;
785 if ((asyncNode
.getStartOccurrence() < event
) && (asyncNode
.getStartLifeline() == lifeline
) && !asyncNode
.isSameAs(message
)) {
796 * Get the closer entering message.
798 * @param lifeline A lifeline reference
799 * @param message A message reference
800 * @param list A list of graph nodes
801 * @param smallerEvent A smaller event flag
802 * @return the closer entering message.
804 protected GraphNode
getCloserEnteringMessage(Lifeline lifeline
, BaseMessage message
, List
<GraphNode
> list
, boolean smallerEvent
) {
810 if (message
!= null) {
811 event
= message
.getEventOccurrence();
813 for (int i
= 0; i
< list
.size(); i
++) {
814 GraphNode node
= list
.get(i
);
815 if (node
instanceof SyncMessage
) {
816 SyncMessage syncNode
= (SyncMessage
) node
;
817 if ((syncNode
.getEventOccurrence() > event
) && (syncNode
.getEndLifeline() == lifeline
) && !syncNode
.isSameAs(message
)) {
820 } else if (node
instanceof AsyncMessage
) {
821 AsyncMessage asyncNode
= (AsyncMessage
) node
;
822 if ((asyncNode
.getStartOccurrence() > event
) && (asyncNode
.getEndLifeline() == lifeline
) && !asyncNode
.isSameAs(message
)) {
828 int event
= getMaxEventOccurrence();
829 if (message
!= null) {
830 if (message
instanceof AsyncMessage
) {
831 event
= ((AsyncMessage
) message
).getStartOccurrence();
833 event
= message
.getEventOccurrence();
836 for (int i
= list
.size() - 1; i
>= 0; i
--) {
837 GraphNode node
= list
.get(i
);
838 if (node
instanceof SyncMessage
) {
839 SyncMessage syncNode
= (SyncMessage
) node
;
840 if ((syncNode
.getEventOccurrence() < event
) && (syncNode
.getEndLifeline() == lifeline
) && !syncNode
.isSameAs(message
)) {
843 } else if (node
instanceof AsyncMessage
) {
844 AsyncMessage asyncNode
= (AsyncMessage
) node
;
845 if ((asyncNode
.getStartOccurrence() < event
) && (asyncNode
.getEndLifeline() == lifeline
) && !asyncNode
.isSameAs(message
)) {
855 * Get distance of given event from given graph node.
857 * @param node A graph node reference.
858 * @param event A event number to check.
859 * @return distance of event from graph node.
861 protected int distanceFromEvent(GraphNode node
, int event
) {
863 if (node
instanceof SyncMessage
) {
864 distance
= ((SyncMessage
) node
).getEventOccurrence() - event
;
865 } else if (node
instanceof AsyncMessage
) {
866 int start
= ((AsyncMessage
) node
).getStartOccurrence();
867 int end
= ((AsyncMessage
) node
).getEndOccurrence();
868 if ((start
- event
) < (end
- event
)) {
869 distance
= start
- event
;
871 distance
= end
- event
;
874 return Math
.abs(distance
);
878 * Get node from 2 given nodes that is close to event.
880 * @param node1 A first graph node
881 * @param node2 A second graph node
882 * @param event A event to check.
883 * @return graph node that is closer or <code>null</code>
885 protected GraphNode
getCloserToEvent(GraphNode node1
, GraphNode node2
, int event
) {
886 if ((node1
!= null) && (node2
!= null)) {
887 if (distanceFromEvent(node1
, event
) < distanceFromEvent(node2
, event
)) {
891 } else if (node1
!= null) {
893 } else if (node2
!= null) {
900 * Get called message based on given start message.
902 * @param startMessage A start message to check.
903 * @return called message (graph node) or <code>null</code>
905 public GraphNode
getCalledMessage(BaseMessage startMessage
) {
907 GraphNode result
= null;
908 Lifeline lifeline
= null;
909 if (startMessage
!= null) {
910 event
= startMessage
.getEventOccurrence();
911 lifeline
= startMessage
.getEndLifeline();
912 if (lifeline
== null) {
913 lifeline
= startMessage
.getStartLifeline();
916 if (lifeline
== null) {
919 GraphNode message
= getCloserLeavingMessage(lifeline
, startMessage
, getSyncMessages(), false);
920 GraphNode messageReturn
= getCloserLeavingMessage(lifeline
, startMessage
, getSyncMessagesReturn(), false);
921 result
= getCloserToEvent(message
, messageReturn
, event
);
922 message
= getCloserLeavingMessage(lifeline
, startMessage
, getAsyncMessages(), false);
923 result
= getCloserToEvent(result
, message
, event
);
924 messageReturn
= getCloserLeavingMessage(lifeline
, startMessage
, getAsyncMessagesReturn(), false);
925 result
= getCloserToEvent(result
, messageReturn
, event
);
930 * Get caller message based on given start message.
932 * @param startMessage A start message to check.
933 * @return called message (graph node) or <code>null</code>
935 public GraphNode
getCallerMessage(BaseMessage startMessage
) {
936 int event
= getMaxEventOccurrence();
937 GraphNode result
= null;
938 Lifeline lifeline
= null;
939 if (startMessage
!= null) {
940 event
= startMessage
.getEventOccurrence();
941 lifeline
= startMessage
.getStartLifeline();
942 if (lifeline
== null) {
943 lifeline
= startMessage
.getEndLifeline();
946 if (lifeline
== null) {
949 GraphNode message
= getCloserEnteringMessage(lifeline
, startMessage
, getSyncMessages(), true);
950 GraphNode messageReturn
= getCloserEnteringMessage(lifeline
, startMessage
, getSyncMessagesReturn(), true);
951 result
= getCloserToEvent(message
, messageReturn
, event
);
952 message
= getCloserEnteringMessage(lifeline
, startMessage
, getAsyncMessages(), true);
953 result
= getCloserToEvent(result
, message
, event
);
954 messageReturn
= getCloserEnteringMessage(lifeline
, startMessage
, getAsyncMessagesReturn(), true);
955 result
= getCloserToEvent(result
, messageReturn
, event
);
960 * Get next lifeline based on given message.
962 * @param lifeline A lifeline reference
963 * @param startMessage A start message to check
964 * @return next lifeline or <code>null</code>
966 public GraphNode
getNextLifelineMessage(Lifeline lifeline
, BaseMessage startMessage
) {
968 if (startMessage
!= null) {
969 event
= startMessage
.getEventOccurrence();
971 if (lifeline
== null) {
974 GraphNode message
= getCloserLeavingMessage(lifeline
, startMessage
, getSyncMessages(), false);
975 GraphNode messageReturn
= getCloserLeavingMessage(lifeline
, startMessage
, getSyncMessagesReturn(), false);
976 GraphNode result
= getCloserToEvent(message
, messageReturn
, event
);
977 message
= getCloserLeavingMessage(lifeline
, startMessage
, getAsyncMessages(), false);
978 result
= getCloserToEvent(result
, message
, event
);
979 messageReturn
= getCloserLeavingMessage(lifeline
, startMessage
, getAsyncMessagesReturn(), false);
980 result
= getCloserToEvent(result
, messageReturn
, event
);
985 * Get previous lifeline based on given message.
987 * @param lifeline A lifeline reference
988 * @param startMessage A start message to check.
989 * @return previous lifeline or <code>null</code>
991 public GraphNode
getPrevLifelineMessage(Lifeline lifeline
, BaseMessage startMessage
) {
992 int event
= getMaxEventOccurrence();
993 if (startMessage
!= null) {
994 if (startMessage
instanceof AsyncMessage
) {
995 event
= ((AsyncMessage
) startMessage
).getStartOccurrence();
997 event
= startMessage
.getEventOccurrence();
1000 if (lifeline
== null) {
1003 GraphNode message
= getCloserLeavingMessage(lifeline
, startMessage
, getSyncMessages(), true);
1004 GraphNode messageReturn
= getCloserLeavingMessage(lifeline
, startMessage
, getSyncMessagesReturn(), true);
1005 GraphNode result
= getCloserToEvent(message
, messageReturn
, event
);
1006 message
= getCloserLeavingMessage(lifeline
, startMessage
, getAsyncMessages(), true);
1007 result
= getCloserToEvent(result
, message
, event
);
1008 messageReturn
= getCloserLeavingMessage(lifeline
, startMessage
, getAsyncMessagesReturn(), true);
1009 result
= getCloserToEvent(result
, messageReturn
, event
);
1014 * Get the first execution occurrence.
1016 * @param lifeline A lifeline reference
1017 * @return the first execution occurrence of lifeline or <code>null</code>.
1019 public BasicExecutionOccurrence
getFirstExecution(Lifeline lifeline
) {
1020 if (lifeline
== null) {
1023 List
<GraphNode
> list
= lifeline
.getExecutions();
1025 if ((list
== null) || (list
.isEmpty())) {
1029 BasicExecutionOccurrence result
= (BasicExecutionOccurrence
) list
.get(0);
1030 for (int i
= 0; i
< list
.size(); i
++) {
1031 BasicExecutionOccurrence e
= (BasicExecutionOccurrence
) list
.get(i
);
1032 if ((e
.getStartOccurrence() < result
.getEndOccurrence())) {
1040 * Get the previous execution occurrence relative to a given execution occurrence.
1042 * @param exec A execution occurrence reference.
1043 * @return the previous execution occurrence of lifeline or <code>null</code>.
1045 public BasicExecutionOccurrence
getPrevExecOccurrence(BasicExecutionOccurrence exec
) {
1049 Lifeline lifeline
= exec
.getLifeline();
1050 if (lifeline
== null) {
1053 List
<GraphNode
> list
= lifeline
.getExecutions();
1057 BasicExecutionOccurrence result
= null;
1058 for (int i
= 0; i
< list
.size(); i
++) {
1059 BasicExecutionOccurrence e
= (BasicExecutionOccurrence
) list
.get(i
);
1060 if ((e
.getStartOccurrence() < exec
.getStartOccurrence()) && (result
== null)) {
1063 if ((e
.getStartOccurrence() < exec
.getStartOccurrence()) && (result
!= null) && (e
.getStartOccurrence() >= result
.getEndOccurrence())) {
1071 * Get the next execution occurrence relative to a given execution occurrence.
1073 * @param exec A execution occurrence reference.
1074 * @return the next execution occurrence of lifeline or <code>null</code>.
1076 public BasicExecutionOccurrence
getNextExecOccurrence(BasicExecutionOccurrence exec
) {
1080 Lifeline lifeline
= exec
.getLifeline();
1081 if (lifeline
== null) {
1084 List
<GraphNode
> list
= lifeline
.getExecutions();
1088 BasicExecutionOccurrence result
= null;
1089 for (int i
= 0; i
< list
.size(); i
++) {
1090 BasicExecutionOccurrence e
= (BasicExecutionOccurrence
) list
.get(i
);
1091 if ((e
.getStartOccurrence() > exec
.getStartOccurrence()) && (result
== null)) {
1094 if ((e
.getStartOccurrence() > exec
.getStartOccurrence()) && (result
!= null) && (e
.getStartOccurrence() <= result
.getEndOccurrence())) {
1102 * Get the last execution occurrence.
1104 * @param lifeline A lifeline reference.
1105 * @return the last execution occurrence of lifeline or <code>null</code>.
1107 public BasicExecutionOccurrence
getLastExecOccurrence(Lifeline lifeline
) {
1108 if (lifeline
== null) {
1111 List
<GraphNode
> list
= lifeline
.getExecutions();
1115 BasicExecutionOccurrence result
= null;
1116 for (int i
= 0; i
< list
.size(); i
++) {
1117 BasicExecutionOccurrence e
= (BasicExecutionOccurrence
) list
.get(i
);
1118 if (result
== null) {
1121 if (e
.getStartOccurrence() > result
.getEndOccurrence()) {
1129 * @return highlighted life line if set else null.
1131 protected Lifeline
getHighlightLifeline() {
1132 return fHighlightLifeline
;
1136 * @return the start event value.
1138 protected int getStartEvent() {
1143 * Returns the number of events
1145 * @return the number of events
1147 protected int getNumberOfEvents() {
1152 * Returns the highlight color.
1154 * @return the highlight color
1156 protected IColor
getHighlightColor() {
1157 return fHighlightColor
;
1161 * Set the highlighted life line.
1164 * The highlighted life line if set else null
1166 protected void setHighlightLifeline(Lifeline lifeline
) {
1167 fHighlightLifeline
= lifeline
;
1171 * Sets the start event value
1174 * the start event value.
1176 protected void setStartEvent(int startEvent
) {
1177 fStartEvent
= startEvent
;
1181 * Sets the number of events
1184 * The number of events
1186 protected void setNumberOfEvents(int nbEvents
) {
1187 fNbEvent
= nbEvents
;
1191 * Sets the highlight color.
1194 * the highlight color
1196 protected void setHighlightColor(IColor color
) {
1197 fHighlightColor
= color
;
1201 * sets the list of execution occurrences.
1204 * the list of execution occurrences
1206 protected void setExecutionOccurrencesWithTime(List
<SDTimeEvent
> occurences
) {
1207 fExecutionOccurrencesWithTime
= occurences
;