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 static org
.eclipse
.tracecompass
.common
.core
.NonNullUtils
.checkNotNull
;
17 import java
.util
.ArrayList
;
18 import java
.util
.Arrays
;
19 import java
.util
.Iterator
;
20 import java
.util
.List
;
22 import org
.eclipse
.tracecompass
.tmf
.core
.timestamp
.ITmfTimestamp
;
23 import org
.eclipse
.tracecompass
.tmf
.ui
.views
.uml2sd
.drawings
.IColor
;
24 import org
.eclipse
.tracecompass
.tmf
.ui
.views
.uml2sd
.drawings
.IGC
;
25 import org
.eclipse
.tracecompass
.tmf
.ui
.views
.uml2sd
.preferences
.SDViewPref
;
26 import org
.eclipse
.tracecompass
.tmf
.ui
.views
.uml2sd
.util
.TimeEventComparator
;
29 * The Frame class is the base sequence diagram graph nodes container.<br>
30 * For instance, only one frame can be drawn in the View.<br>
31 * Lifelines, Messages and Stop which are supposed to represent a Sequence diagram are drawn in a Frame.<br>
32 * Only the graph node added to their representing list will be drawn.
34 * The lifelines are appended along the X axsis when added in a frame.<br>
35 * The syncMessages are ordered along the Y axsis depending on the event occurrence they are attached to.<br>
37 * @see org.eclipse.tracecompass.tmf.ui.views.uml2sd.core.Lifeline Lifeline for more event occurence details
41 public class Frame
extends BasicFrame
{
43 // ------------------------------------------------------------------------
45 // ------------------------------------------------------------------------
47 * The lifeline that is current highlighted.
49 private Lifeline fHighlightLifeline
= null;
51 * The value of the start event.
53 private int fStartEvent
= 0;
55 * The number of events in the frame.
57 private int fNbEvent
= 0;
59 * The color for highlighting.
61 private IColor fHighlightColor
= null;
63 * The list of time events of the corresponding execution occurrences.
65 private List
<SDTimeEvent
> fExecutionOccurrencesWithTime
;
67 * The Array of lifeline categories.
69 private LifelineCategories
[] fLifelineCategories
= null;
71 // ------------------------------------------------------------------------
73 // ------------------------------------------------------------------------
76 * Returns a list of all lifelines known by this frame. Known lifelines are the only one which can be displayed on
79 * @return the lifelines list
81 protected List
<GraphNode
> getLifelines() {
85 return getNodeMap().get(Lifeline
.LIFELINE_TAG
);
89 * Returns the number of lifelines stored in the frame
91 * @return the number of lifelines
93 public int lifeLinesCount() {
94 List
<GraphNode
> lifelines
= getLifelines();
95 if (lifelines
!= null) {
96 return lifelines
.size();
102 * Returns the lifeline at the given index in the lifelines array
104 * @param index the position in the lifeline array
105 * @return the lifeline or <code>null</code>
107 public Lifeline
getLifeline(int index
) {
108 if ((getLifelines() != null) && (index
>= 0) && (index
< lifeLinesCount())) {
109 return (Lifeline
) getLifelines().get(index
);
115 * Returns a list of syncMessages known by this frame. Known syncMessages are the only on which can be displayed on
118 * @return the syncMessages list
120 protected List
<GraphNode
> getSyncMessages() {
121 if (!hasChildren()) {
124 return getNodeMap().get(SyncMessage
.SYNC_MESS_TAG
);
128 * Returns the number of syncMessages stored in the frame
130 * @return the number of syncMessage
132 public int syncMessageCount() {
133 if (getSyncMessages() != null) {
134 return getSyncMessages().size();
140 * Returns the syncMessage at the given index in the syncMessages array
142 * @param index the position in the syncMessages array
143 * @return the syncMessage or <code>null</code>
145 public SyncMessage
getSyncMessage(int index
) {
146 if ((getSyncMessages() != null) && (index
>= 0) && (index
< getSyncMessages().size())) {
147 return (SyncMessage
) getSyncMessages().get(index
);
153 * Returns a list of asyncMessages known by this frame. Known asyncMessages are the only on which can be displayed
156 * @return the asyncMessages list or <code>null</code>
158 protected List
<GraphNode
> getAsyncMessages() {
159 if (!hasChildren()) {
162 return getNodeMap().get(AsyncMessage
.ASYNC_MESS_TAG
);
166 * Returns the number of asyncMessage stored in the frame
168 * @return the number of asyncMessage
170 public int asyncMessageCount() {
171 if (getAsyncMessages() != null) {
172 return getAsyncMessages().size();
178 * Returns the asyncMessage at the given index in the asyncMessage array
180 * @param index the position in the asyncMessage array
181 * @return the asyncMessage or <code>null</code>
183 public AsyncMessage
getAsyncMessage(int index
) {
184 if ((getAsyncMessages() != null) && (index
>= 0) && (index
< getAsyncMessages().size())) {
185 return (AsyncMessage
) getAsyncMessages().get(index
);
191 * Returns a list of syncMessages return known by this frame. Known syncMessages return are the only on which can be
192 * displayed on screen
194 * @return the syncMessages return list or <code>null</code>
196 protected List
<GraphNode
> getSyncMessagesReturn() {
197 if (!hasChildren()) {
200 return getNodeMap().get(SyncMessageReturn
.SYNC_MESS_RET_TAG
);
204 * Returns the number of syncMessageReturn stored in the frame
206 * @return the number of syncMessageReturn
208 public int syncMessageReturnCount() {
209 if (getSyncMessagesReturn() != null) {
210 return getSyncMessagesReturn().size();
216 * Returns the syncMessageReturn at the given index in the syncMessageReturn array
218 * @param index the position in the syncMessageReturn array
219 * @return the syncMessageReturn or <code>null</code>
221 public SyncMessageReturn
getSyncMessageReturn(int index
) {
222 if ((getSyncMessagesReturn() != null) && (index
>= 0) && (index
< getSyncMessagesReturn().size())) {
223 return (SyncMessageReturn
) getSyncMessagesReturn().get(index
);
229 * Returns a list of asyncMessageRetun known by this frame. Known asyncMessageRetun are the only on which can be
230 * displayed on screen
232 * @return the asyncMessageRetun list or <code>null</code>
234 protected List
<GraphNode
> getAsyncMessagesReturn() {
235 if (!hasChildren()) {
238 return getNodeMap().get(AsyncMessageReturn
.ASYNC_MESS_RET_TAG
);
242 * Returns the number of asyncMessageReturn stored in the frame
244 * @return the number of asyncMessageReturn
246 public int asyncMessageReturnCount() {
247 if (getAsyncMessagesReturn() != null) {
248 return getAsyncMessagesReturn().size();
254 * Returns the asyncMessageReturn at the given index in the asyncMessageReturn array
256 * @param index the position in the asyncMessageReturn array
257 * @return the asyncMessageReturn or <code>null</code>
259 public AsyncMessageReturn
getAsyncMessageReturn(int index
) {
260 if ((getAsyncMessagesReturn() != null) && (index
>= 0) && (index
< getAsyncMessagesReturn().size())) {
261 return (AsyncMessageReturn
) getAsyncMessagesReturn().get(index
);
267 * Adds a lifeline to the frame lifelines list. The lifeline X drawing order depends on the lifeline addition order
268 * into the frame lifelines list.
270 * @param lifeline the lifeline to add
272 public void addLifeLine(Lifeline lifeline
) {
273 setComputeMinMax(true);
274 if (lifeline
== null) {
277 // set the lifeline parent frame
278 lifeline
.setFrame(this);
279 // Increate the frame lifeline counter
280 // and set the lifeline drawing order
281 lifeline
.setIndex(getNewHorizontalIndex());
282 if (lifeline
.hasTimeInfo()) {
283 setHasTimeInfo(true);
285 // add the lifeline to the lifelines list
290 * Returns the first visible lifeline drawn in the view
292 * @return the first visible lifeline index
294 public int getFirstVisibleLifeline() {
295 if (!hasChildren()) {
298 Integer ret
= getIndexes().get(Lifeline
.LIFELINE_TAG
);
299 return (ret
== null ?
0 : ret
.intValue());
303 * Returns the first visible synchronous message drawn in the view
305 * @return the first visible synchronous message index
307 public int getFirstVisibleSyncMessage() {
308 if (!hasChildren()) {
311 Integer ret
= getIndexes().get(SyncMessage
.SYNC_MESS_TAG
);
312 return (ret
== null ?
0 : ret
.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()) {
324 Integer ret
= getIndexes().get(SyncMessageReturn
.SYNC_MESS_RET_TAG
);
325 return (ret
== null ?
0 : ret
.intValue());
329 * Returns the first visible synchronous message drawn in the view
331 * @return the first visible synchronous message index
333 public int getFirstVisibleAsyncMessage() {
334 if (!hasChildren()) {
337 Integer ret
= getIndexes().get(AsyncMessage
.ASYNC_MESS_TAG
);
338 return (ret
== null ?
0 : ret
.intValue());
342 * Returns the first visible synchronous message return drawn in the view
344 * @return the first visible synchronous message return index
346 public int getFirstVisibleAsyncMessageReturn() {
347 if (!hasChildren()) {
350 Integer ret
= getIndexes().get(AsyncMessageReturn
.ASYNC_MESS_RET_TAG
);
351 return (ret
== null ?
0 : ret
.intValue());
355 * Returns the list of execution occurrences.
357 * @return the list of execution occurrences
359 public List
<SDTimeEvent
> getExecutionOccurrencesWithTime() {
360 return fExecutionOccurrencesWithTime
;
364 * Inserts a lifeline after a given lifeline.
366 * @param toInsert A lifeline to insert
367 * @param after A lifelife the toInsert-lifeline will be inserted after.
369 public void insertLifelineAfter(Lifeline toInsert
, Lifeline after
) {
370 if ((toInsert
== null)) {
373 if (toInsert
== after
) {
378 insertPoint
= after
.getIndex();
380 int removePoint
= toInsert
.getIndex() - 1;
381 if (removePoint
>= insertPoint
) {
382 getLifelines().remove(removePoint
);
384 getLifelines().add(insertPoint
, toInsert
);
385 if (removePoint
< insertPoint
) {
386 getLifelines().remove(removePoint
);
389 if (removePoint
>= insertPoint
) {
390 toInsert
.setIndex(insertPoint
+ 1);
392 toInsert
.setIndex(insertPoint
- 1);
396 if (removePoint
>= insertPoint
) {
397 for (int i
= insertPoint
; i
< getLifelines().size(); i
++) {
398 getLifeline(i
).setIndex(i
+ 1);
401 for (int i
= 0; i
< insertPoint
&& i
< getLifelines().size(); i
++) {
402 getLifeline(i
).setIndex(i
+ 1);
408 * Inserts a lifeline before a given lifeline.
411 * A lifeline to insert
413 * A lifeline the toInsert-lifeline will be inserted before.
415 public void insertLifelineBefore(Lifeline toInsert
, Lifeline before
) {
416 if ((toInsert
== null)) {
419 if (toInsert
== before
) {
423 if (before
!= null) {
424 insertPoint
= before
.getIndex() - 1;
426 int removePoint
= toInsert
.getIndex() - 1;
427 if (removePoint
>= insertPoint
) {
428 getLifelines().remove(removePoint
);
430 getLifelines().add(insertPoint
, toInsert
);
431 if (removePoint
< insertPoint
) {
432 getLifelines().remove(removePoint
);
435 if (removePoint
>= insertPoint
) {
436 toInsert
.setIndex(insertPoint
+ 1);
438 toInsert
.setIndex(insertPoint
- 1);
442 if (removePoint
>= insertPoint
) {
443 for (int i
= insertPoint
; i
< getLifelines().size(); i
++) {
444 getLifeline(i
).setIndex(i
+ 1);
447 for (int i
= 0; i
< insertPoint
&& i
< getLifelines().size(); i
++) {
448 getLifeline(i
).setIndex(i
+ 1);
454 * Gets the closer life line to the given x-coordinate.
456 * @param x A x coordinate
457 * @return the closer lifeline
459 public Lifeline
getCloserLifeline(int x
) {
460 int index
= (x
- Metrics
.FRAME_H_MARGIN
+ Metrics
.LIFELINE_H_MAGIN
) / Metrics
.swimmingLaneWidth() - 1;
464 if (index
>= getLifelines().size()) {
465 index
= getLifelines().size() - 1;
467 Lifeline node1
, node2
, node3
;
468 int dist1
, dist2
, dist3
;
469 node1
= node2
= node3
= getLifeline(index
);
470 dist1
= dist2
= dist3
= Math
.abs(node1
.getX() + node1
.getWidth() / 2 - x
);
472 node2
= getLifeline(index
- 1);
473 dist2
= Math
.abs(node2
.getX() + node2
.getWidth() / 2 - x
);
475 if (index
< getLifelines().size() - 1) {
476 node3
= getLifeline(index
+ 1);
477 dist3
= Math
.abs(node3
.getX() + node3
.getWidth() / 2 - x
);
479 if (dist1
<= dist2
&& dist1
<= dist3
) {
481 } else if (dist2
<= dist1
&& dist2
<= dist3
) {
488 * Re-orders the given list of lifelines.
490 * @param list A list of lifelines to reorder.
492 public void reorder(List
<?
> list
) {
493 for (int i
= 0; i
< list
.size(); i
++) {
494 Object o
= list
.get(i
);
495 if (o
instanceof Lifeline
[]) {
496 Lifeline temp
[] = (Lifeline
[]) o
;
497 if (temp
.length
== 2) {
498 if (temp
[1] == null) {
499 insertLifelineAfter(temp
[0], getLifeline(lifeLinesCount() - 1));
501 insertLifelineBefore(temp
[0], temp
[1]);
509 * Resets the time compression information.
511 public void resetTimeCompression() {
512 fHighlightLifeline
= null;
513 this.fStartEvent
= 0;
515 fHighlightColor
= null;
519 protected void computeMinMax() {
520 List
<SDTimeEvent
> timeArray
= buildTimeArray();
521 if ((timeArray
== null) || timeArray
.isEmpty()) {
524 for (int i
= 0; i
< timeArray
.size() - 1; i
++) {
525 SDTimeEvent m1
= timeArray
.get(i
);
526 SDTimeEvent m2
= timeArray
.get(i
+ 1);
527 if (SDViewPref
.getInstance().excludeExternalTime() && ((m1
.getGraphNode() instanceof BaseMessage
) && (m2
.getGraphNode() instanceof BaseMessage
))) {
528 BaseMessage mes1
= (BaseMessage
) m1
.getGraphNode();
529 BaseMessage mes2
= (BaseMessage
) m2
.getGraphNode();
530 if ((mes2
.getStartLifeline() == null) || (mes1
.getEndLifeline() == null)) {
535 updateMinMax(m1
, m2
);
540 * Find the two graph nodes that are closest to this date, one just earlier, second just later. If date is before
541 * any graph node, bounds[0] is null and bounds[1] is the earliest. If date is after any graph node, bounds[1] is
542 * null and bounds[0] is the latest.
544 * @param dateToFind date to be found
545 * @param bounds a two items array that will receive bounds if found
546 * @return true if both bounds not null
548 public boolean findDateBounds(ITmfTimestamp dateToFind
, ITimeRange bounds
[]) {
550 List
<SDTimeEvent
> timeArray
= buildTimeArray();
552 if ((timeArray
== null) || timeArray
.isEmpty()) {
558 for (int i
= 0; i
< timeArray
.size(); i
++) {
559 SDTimeEvent m
= timeArray
.get(i
);
560 if (m
.getTime().compareTo(dateToFind
) > 0) {
561 bounds
[1] = m
.getGraphNode();
563 bounds
[0] = timeArray
.get(i
- 1).getGraphNode();
569 bounds
[0] = timeArray
.get(timeArray
.size() - 1).getGraphNode();
575 * Highlights the time compression.
577 * @param lifeline A lifeline to highlight
578 * @param startEvent A start event number
579 * @param nbEvent A number of events
580 * @param color A color for highlighting
582 public void highlightTimeCompression(Lifeline lifeline
, int startEvent
, int nbEvent
, IColor color
) {
583 fHighlightLifeline
= lifeline
;
584 this.fStartEvent
= startEvent
;
585 this.fNbEvent
= nbEvent
;
586 fHighlightColor
= color
;
590 * Set the lifeline categories which will be use during the lifelines creation
592 * @see Lifeline#setCategory(int)
593 * @param categories the lifeline categories array
595 public void setLifelineCategories(LifelineCategories
[] categories
) {
596 fLifelineCategories
= Arrays
.copyOf(categories
, categories
.length
);
600 * Returns the lifeline categories array set for the this frame
602 * @return the lifeline categories array or null if not set
604 public LifelineCategories
[] getLifelineCategories() {
605 return Arrays
.copyOf(fLifelineCategories
, fLifelineCategories
.length
);
609 * Adds a message to the Frame message list. Four kinds of syncMessages can be added:<br>
610 * - synchronous syncMessages<br>
611 * - synchronous syncMessages return<br>
612 * - asynchronous syncMessages<br>
613 * - asynchronous syncMessages return<br>
614 * For drawing performance reason, it is recommended to add synchronous syncMessages in the same order they should
615 * appear along the Y axis in the Frame.
617 * @param message the message to add
619 public void addMessage(BaseMessage message
) {
624 public void draw(IGC context
) {
626 if (!hasChildren()) {
630 if (fHighlightLifeline
!= null) {
631 IColor backupColor
= context
.getBackground();
632 context
.setBackground(SDViewPref
.getInstance().getTimeCompressionSelectionColor());
633 int gy
= fHighlightLifeline
.getY() + fHighlightLifeline
.getHeight() + (Metrics
.getMessageFontHeigth() + Metrics
.getMessagesSpacing()) * fStartEvent
;
634 context
.fillRectangle(Metrics
.FRAME_H_MARGIN
+ 1, gy
, fHighlightLifeline
.getX() + Metrics
.getLifelineWidth() / 2 - Metrics
.FRAME_H_MARGIN
, (Metrics
.getMessageFontHeigth() + Metrics
.getMessagesSpacing()) * fNbEvent
);
635 context
.setBackground(backupColor
);
637 super.draw(context
, false);
638 int lifelineArryStep
= 1;
639 if (Metrics
.swimmingLaneWidth() * context
.getZoom() < Metrics
.LIFELINE_SIGNIFICANT_HSPACING
) {
640 lifelineArryStep
= Math
.round(Metrics
.LIFELINE_SIGNIFICANT_HSPACING
/ (Metrics
.swimmingLaneWidth() * context
.getZoom()));
642 if (getIndexes().size() == 0) {
645 int lifeLineDrawIndex
= checkNotNull(getIndexes().get(Lifeline
.LIFELINE_TAG
)).intValue();
646 List
<GraphNode
> nodeList
= checkNotNull(getNodeMap().get(Lifeline
.LIFELINE_TAG
));
647 for (int i
= lifeLineDrawIndex
; i
< nodeList
.size(); i
= i
+ lifelineArryStep
) {
648 Lifeline toDraw
= (Lifeline
) nodeList
.get(i
);
649 if (toDraw
.getX() - Metrics
.LIFELINE_SPACING
/ 2 > context
.getContentsX() + context
.getVisibleWidth()) {
652 toDraw
.drawName(context
);
654 if (fHighlightLifeline
!= null) {
655 if (toDraw
== fHighlightLifeline
) {
656 toDraw
.highlightExecOccurrenceRegion(context
, fStartEvent
, fNbEvent
, fHighlightColor
);
657 } else if (toDraw
.getIndex() < fHighlightLifeline
.getIndex()) {
658 int acIndex
= toDraw
.getExecOccurrenceDrawIndex();
659 // acIndex = first visible execution occurrence
660 // for drawing speed reason with only search on the visible subset
661 if (toDraw
.getExecutions() != null) {
662 for (int index
= acIndex
; index
< toDraw
.getExecutions().size(); index
++) {
663 BasicExecutionOccurrence exec
= (BasicExecutionOccurrence
) toDraw
.getExecutions().get(index
);
664 int tempEvent
= fStartEvent
;
665 for (int j
= 0; j
< fNbEvent
; j
++) {
666 if (((tempEvent
>= exec
.getStartOccurrence()) && (tempEvent
<= exec
.getEndOccurrence()) && (tempEvent
+ 1 >= exec
.getStartOccurrence()) && (tempEvent
+ 1 <= exec
.getEndOccurrence()))) {
667 toDraw
.highlightExecOccurrenceRegion(context
, tempEvent
, 1, SDViewPref
.getInstance().getTimeCompressionSelectionColor());
669 tempEvent
= tempEvent
+ 1;
671 // if we are outside the visible area we stop right now
672 // This works because execution occurrences are ordered along the Y axis
673 if (exec
.getY() > getY()) {
684 protected List
<SDTimeEvent
> buildTimeArray() {
686 if (!hasChildren()) {
687 return new ArrayList
<>();
690 List
<SDTimeEvent
> timeArray
= super.buildTimeArray();
691 fExecutionOccurrencesWithTime
= null;
692 if (getLifelines() != null) {
693 List
<GraphNode
> nodeList
= checkNotNull(getNodeMap().get(Lifeline
.LIFELINE_TAG
));
694 for (int i
= 0; i
< nodeList
.size(); i
++) {
695 Lifeline lifeline
= (Lifeline
) nodeList
.get(i
);
696 if (lifeline
.hasTimeInfo() && lifeline
.getExecutions() != null) {
697 for (Iterator
<GraphNode
> j
= lifeline
.getExecutions().iterator(); j
.hasNext();) {
698 GraphNode o
= j
.next();
699 if (o
instanceof ExecutionOccurrence
) {
700 ExecutionOccurrence eo
= (ExecutionOccurrence
) o
;
701 if (eo
.hasTimeInfo()) {
702 int event
= eo
.getStartOccurrence();
703 ITmfTimestamp time
= eo
.getStartTime();
704 SDTimeEvent f
= new SDTimeEvent(time
, event
, eo
);
706 if (fExecutionOccurrencesWithTime
== null) {
707 fExecutionOccurrencesWithTime
= new ArrayList
<>();
709 fExecutionOccurrencesWithTime
.add(f
);
710 event
= eo
.getEndOccurrence();
711 time
= eo
.getEndTime();
712 f
= new SDTimeEvent(time
, event
, eo
);
714 fExecutionOccurrencesWithTime
.add(f
);
722 if (fExecutionOccurrencesWithTime
!= null) {
723 SDTimeEvent
[] temp
= fExecutionOccurrencesWithTime
.toArray(new SDTimeEvent
[fExecutionOccurrencesWithTime
.size()]);
724 Arrays
.sort(temp
, new TimeEventComparator());
725 fExecutionOccurrencesWithTime
= Arrays
.asList(temp
);
727 SDTimeEvent
[] temp
= timeArray
.toArray(new SDTimeEvent
[timeArray
.size()]);
728 Arrays
.sort(temp
, new TimeEventComparator());
729 timeArray
= Arrays
.asList(temp
);
734 * Get the closer leaving message.
736 * @param lifeline A lifeline reference
737 * @param message A message reference
738 * @param list A list of graph nodes
739 * @param smallerEvent A smaller event flag
740 * @return the closer leaving message.
742 protected GraphNode
getCloserLeavingMessage(Lifeline lifeline
, BaseMessage message
, List
<GraphNode
> list
, boolean smallerEvent
) {
749 if (message
!= null) {
750 event
= message
.getEventOccurrence();
752 for (int i
= 0; i
< list
.size(); i
++) {
753 GraphNode node
= list
.get(i
);
754 if (node
instanceof SyncMessage
) {
755 SyncMessage syncNode
= (SyncMessage
) node
;
756 if ((syncNode
.getEventOccurrence() > event
) && (syncNode
.getStartLifeline() == lifeline
) && !syncNode
.isSameAs(message
)) {
759 } else if (node
instanceof AsyncMessage
) {
760 AsyncMessage asyncNode
= (AsyncMessage
) node
;
761 if ((asyncNode
.getStartOccurrence() > event
) && (asyncNode
.getStartLifeline() == lifeline
) && !asyncNode
.isSameAs(message
)) {
767 int event
= getMaxEventOccurrence();
768 if (message
!= null) {
769 if (message
instanceof AsyncMessage
) {
770 event
= ((AsyncMessage
) message
).getStartOccurrence();
772 event
= message
.getEventOccurrence();
775 for (int i
= list
.size() - 1; i
>= 0; i
--) {
776 GraphNode node
= list
.get(i
);
777 if (node
instanceof SyncMessage
) {
778 SyncMessage syncNode
= (SyncMessage
) node
;
779 if ((syncNode
.getEventOccurrence() < event
) && (syncNode
.getStartLifeline() == lifeline
) && !syncNode
.isSameAs(message
)) {
782 } else if (node
instanceof AsyncMessage
) {
783 AsyncMessage asyncNode
= (AsyncMessage
) node
;
784 if ((asyncNode
.getStartOccurrence() < event
) && (asyncNode
.getStartLifeline() == lifeline
) && !asyncNode
.isSameAs(message
)) {
795 * Get the closer entering message.
797 * @param lifeline A lifeline reference
798 * @param message A message reference
799 * @param list A list of graph nodes
800 * @param smallerEvent A smaller event flag
801 * @return the closer entering message.
803 protected GraphNode
getCloserEnteringMessage(Lifeline lifeline
, BaseMessage message
, List
<GraphNode
> list
, boolean smallerEvent
) {
809 if (message
!= null) {
810 event
= message
.getEventOccurrence();
812 for (int i
= 0; i
< list
.size(); i
++) {
813 GraphNode node
= list
.get(i
);
814 if (node
instanceof SyncMessage
) {
815 SyncMessage syncNode
= (SyncMessage
) node
;
816 if ((syncNode
.getEventOccurrence() > event
) && (syncNode
.getEndLifeline() == lifeline
) && !syncNode
.isSameAs(message
)) {
819 } else if (node
instanceof AsyncMessage
) {
820 AsyncMessage asyncNode
= (AsyncMessage
) node
;
821 if ((asyncNode
.getStartOccurrence() > event
) && (asyncNode
.getEndLifeline() == lifeline
) && !asyncNode
.isSameAs(message
)) {
827 int event
= getMaxEventOccurrence();
828 if (message
!= null) {
829 if (message
instanceof AsyncMessage
) {
830 event
= ((AsyncMessage
) message
).getStartOccurrence();
832 event
= message
.getEventOccurrence();
835 for (int i
= list
.size() - 1; i
>= 0; i
--) {
836 GraphNode node
= list
.get(i
);
837 if (node
instanceof SyncMessage
) {
838 SyncMessage syncNode
= (SyncMessage
) node
;
839 if ((syncNode
.getEventOccurrence() < event
) && (syncNode
.getEndLifeline() == lifeline
) && !syncNode
.isSameAs(message
)) {
842 } else if (node
instanceof AsyncMessage
) {
843 AsyncMessage asyncNode
= (AsyncMessage
) node
;
844 if ((asyncNode
.getStartOccurrence() < event
) && (asyncNode
.getEndLifeline() == lifeline
) && !asyncNode
.isSameAs(message
)) {
854 * Get distance of given event from given graph node.
856 * @param node A graph node reference.
857 * @param event A event number to check.
858 * @return distance of event from graph node.
860 protected int distanceFromEvent(GraphNode node
, int event
) {
862 if (node
instanceof SyncMessage
) {
863 distance
= ((SyncMessage
) node
).getEventOccurrence() - event
;
864 } else if (node
instanceof AsyncMessage
) {
865 int start
= ((AsyncMessage
) node
).getStartOccurrence();
866 int end
= ((AsyncMessage
) node
).getEndOccurrence();
867 if ((start
- event
) < (end
- event
)) {
868 distance
= start
- event
;
870 distance
= end
- event
;
873 return Math
.abs(distance
);
877 * Get node from 2 given nodes that is close to event.
879 * @param node1 A first graph node
880 * @param node2 A second graph node
881 * @param event A event to check.
882 * @return graph node that is closer or <code>null</code>
884 protected GraphNode
getCloserToEvent(GraphNode node1
, GraphNode node2
, int event
) {
885 if ((node1
!= null) && (node2
!= null)) {
886 if (distanceFromEvent(node1
, event
) < distanceFromEvent(node2
, event
)) {
890 } else if (node1
!= null) {
892 } else if (node2
!= null) {
899 * Get called message based on given start message.
901 * @param startMessage A start message to check.
902 * @return called message (graph node) or <code>null</code>
904 public GraphNode
getCalledMessage(BaseMessage startMessage
) {
906 GraphNode result
= null;
907 Lifeline lifeline
= null;
908 if (startMessage
!= null) {
909 event
= startMessage
.getEventOccurrence();
910 lifeline
= startMessage
.getEndLifeline();
911 if (lifeline
== null) {
912 lifeline
= startMessage
.getStartLifeline();
915 if (lifeline
== null) {
918 GraphNode message
= getCloserLeavingMessage(lifeline
, startMessage
, getSyncMessages(), false);
919 GraphNode messageReturn
= getCloserLeavingMessage(lifeline
, startMessage
, getSyncMessagesReturn(), false);
920 result
= getCloserToEvent(message
, messageReturn
, event
);
921 message
= getCloserLeavingMessage(lifeline
, startMessage
, getAsyncMessages(), false);
922 result
= getCloserToEvent(result
, message
, event
);
923 messageReturn
= getCloserLeavingMessage(lifeline
, startMessage
, getAsyncMessagesReturn(), false);
924 result
= getCloserToEvent(result
, messageReturn
, event
);
929 * Get caller message based on given start message.
931 * @param startMessage A start message to check.
932 * @return called message (graph node) or <code>null</code>
934 public GraphNode
getCallerMessage(BaseMessage startMessage
) {
935 int event
= getMaxEventOccurrence();
936 GraphNode result
= null;
937 Lifeline lifeline
= null;
938 if (startMessage
!= null) {
939 event
= startMessage
.getEventOccurrence();
940 lifeline
= startMessage
.getStartLifeline();
941 if (lifeline
== null) {
942 lifeline
= startMessage
.getEndLifeline();
945 if (lifeline
== null) {
948 GraphNode message
= getCloserEnteringMessage(lifeline
, startMessage
, getSyncMessages(), true);
949 GraphNode messageReturn
= getCloserEnteringMessage(lifeline
, startMessage
, getSyncMessagesReturn(), true);
950 result
= getCloserToEvent(message
, messageReturn
, event
);
951 message
= getCloserEnteringMessage(lifeline
, startMessage
, getAsyncMessages(), true);
952 result
= getCloserToEvent(result
, message
, event
);
953 messageReturn
= getCloserEnteringMessage(lifeline
, startMessage
, getAsyncMessagesReturn(), true);
954 result
= getCloserToEvent(result
, messageReturn
, event
);
959 * Get next lifeline based on given message.
961 * @param lifeline A lifeline reference
962 * @param startMessage A start message to check
963 * @return next lifeline or <code>null</code>
965 public GraphNode
getNextLifelineMessage(Lifeline lifeline
, BaseMessage startMessage
) {
967 if (startMessage
!= null) {
968 event
= startMessage
.getEventOccurrence();
970 if (lifeline
== null) {
973 GraphNode message
= getCloserLeavingMessage(lifeline
, startMessage
, getSyncMessages(), false);
974 GraphNode messageReturn
= getCloserLeavingMessage(lifeline
, startMessage
, getSyncMessagesReturn(), false);
975 GraphNode result
= getCloserToEvent(message
, messageReturn
, event
);
976 message
= getCloserLeavingMessage(lifeline
, startMessage
, getAsyncMessages(), false);
977 result
= getCloserToEvent(result
, message
, event
);
978 messageReturn
= getCloserLeavingMessage(lifeline
, startMessage
, getAsyncMessagesReturn(), false);
979 result
= getCloserToEvent(result
, messageReturn
, event
);
984 * Get previous lifeline based on given message.
986 * @param lifeline A lifeline reference
987 * @param startMessage A start message to check.
988 * @return previous lifeline or <code>null</code>
990 public GraphNode
getPrevLifelineMessage(Lifeline lifeline
, BaseMessage startMessage
) {
991 int event
= getMaxEventOccurrence();
992 if (startMessage
!= null) {
993 if (startMessage
instanceof AsyncMessage
) {
994 event
= ((AsyncMessage
) startMessage
).getStartOccurrence();
996 event
= startMessage
.getEventOccurrence();
999 if (lifeline
== null) {
1002 GraphNode message
= getCloserLeavingMessage(lifeline
, startMessage
, getSyncMessages(), true);
1003 GraphNode messageReturn
= getCloserLeavingMessage(lifeline
, startMessage
, getSyncMessagesReturn(), true);
1004 GraphNode result
= getCloserToEvent(message
, messageReturn
, event
);
1005 message
= getCloserLeavingMessage(lifeline
, startMessage
, getAsyncMessages(), true);
1006 result
= getCloserToEvent(result
, message
, event
);
1007 messageReturn
= getCloserLeavingMessage(lifeline
, startMessage
, getAsyncMessagesReturn(), true);
1008 result
= getCloserToEvent(result
, messageReturn
, event
);
1013 * Get the first execution occurrence.
1015 * @param lifeline A lifeline reference
1016 * @return the first execution occurrence of lifeline or <code>null</code>.
1018 public BasicExecutionOccurrence
getFirstExecution(Lifeline lifeline
) {
1019 if (lifeline
== null) {
1022 List
<GraphNode
> list
= lifeline
.getExecutions();
1024 if ((list
== null) || (list
.isEmpty())) {
1028 BasicExecutionOccurrence result
= (BasicExecutionOccurrence
) list
.get(0);
1029 for (int i
= 0; i
< list
.size(); i
++) {
1030 BasicExecutionOccurrence e
= (BasicExecutionOccurrence
) list
.get(i
);
1031 if ((e
.getStartOccurrence() < result
.getEndOccurrence())) {
1039 * Get the previous execution occurrence relative to a given execution occurrence.
1041 * @param exec A execution occurrence reference.
1042 * @return the previous execution occurrence of lifeline or <code>null</code>.
1044 public BasicExecutionOccurrence
getPrevExecOccurrence(BasicExecutionOccurrence exec
) {
1048 Lifeline lifeline
= exec
.getLifeline();
1049 if (lifeline
== null) {
1052 List
<GraphNode
> list
= lifeline
.getExecutions();
1056 BasicExecutionOccurrence result
= null;
1057 for (int i
= 0; i
< list
.size(); i
++) {
1058 BasicExecutionOccurrence e
= (BasicExecutionOccurrence
) list
.get(i
);
1059 if ((e
.getStartOccurrence() < exec
.getStartOccurrence()) && (result
== null)) {
1062 if ((e
.getStartOccurrence() < exec
.getStartOccurrence()) && (result
!= null) && (e
.getStartOccurrence() >= result
.getEndOccurrence())) {
1070 * Get the next execution occurrence relative to a given execution occurrence.
1072 * @param exec A execution occurrence reference.
1073 * @return the next execution occurrence of lifeline or <code>null</code>.
1075 public BasicExecutionOccurrence
getNextExecOccurrence(BasicExecutionOccurrence exec
) {
1079 Lifeline lifeline
= exec
.getLifeline();
1080 if (lifeline
== null) {
1083 List
<GraphNode
> list
= lifeline
.getExecutions();
1087 BasicExecutionOccurrence result
= null;
1088 for (int i
= 0; i
< list
.size(); i
++) {
1089 BasicExecutionOccurrence e
= (BasicExecutionOccurrence
) list
.get(i
);
1090 if ((e
.getStartOccurrence() > exec
.getStartOccurrence()) && (result
== null)) {
1093 if ((e
.getStartOccurrence() > exec
.getStartOccurrence()) && (result
!= null) && (e
.getStartOccurrence() <= result
.getEndOccurrence())) {
1101 * Get the last execution occurrence.
1103 * @param lifeline A lifeline reference.
1104 * @return the last execution occurrence of lifeline or <code>null</code>.
1106 public BasicExecutionOccurrence
getLastExecOccurrence(Lifeline lifeline
) {
1107 if (lifeline
== null) {
1110 List
<GraphNode
> list
= lifeline
.getExecutions();
1114 BasicExecutionOccurrence result
= null;
1115 for (int i
= 0; i
< list
.size(); i
++) {
1116 BasicExecutionOccurrence e
= (BasicExecutionOccurrence
) list
.get(i
);
1117 if (result
== null) {
1120 if (e
.getStartOccurrence() > result
.getEndOccurrence()) {
1128 * @return highlighted life line if set else null.
1130 protected Lifeline
getHighlightLifeline() {
1131 return fHighlightLifeline
;
1135 * @return the start event value.
1137 protected int getStartEvent() {
1142 * Returns the number of events
1144 * @return the number of events
1146 protected int getNumberOfEvents() {
1151 * Returns the highlight color.
1153 * @return the highlight color
1155 protected IColor
getHighlightColor() {
1156 return fHighlightColor
;
1160 * Set the highlighted life line.
1163 * The highlighted life line if set else null
1165 protected void setHighlightLifeline(Lifeline lifeline
) {
1166 fHighlightLifeline
= lifeline
;
1170 * Sets the start event value
1173 * the start event value.
1175 protected void setStartEvent(int startEvent
) {
1176 fStartEvent
= startEvent
;
1180 * Sets the number of events
1183 * The number of events
1185 protected void setNumberOfEvents(int nbEvents
) {
1186 fNbEvent
= nbEvents
;
1190 * Sets the highlight color.
1193 * the highlight color
1195 protected void setHighlightColor(IColor color
) {
1196 fHighlightColor
= color
;
1200 * sets the list of execution occurrences.
1203 * the list of execution occurrences
1205 protected void setExecutionOccurrencesWithTime(List
<SDTimeEvent
> occurences
) {
1206 fExecutionOccurrencesWithTime
= occurences
;