1 /**********************************************************************
2 * Copyright (c) 2005, 2008 IBM Corporation and others.
3 * Copyright (c) 2011, 2012 Ericsson.
5 * All rights reserved. This program and the accompanying materials
6 * are made available under the terms of the Eclipse Public License v1.0
7 * which accompanies this distribution, and is available at
8 * http://www.eclipse.org/legal/epl-v10.html
11 * IBM - Initial API and implementation
12 * Bernd Hufmann - Updated for TMF
13 **********************************************************************/
14 package org
.eclipse
.linuxtools
.tmf
.ui
.views
.uml2sd
.core
;
16 import java
.util
.ArrayList
;
17 import java
.util
.Arrays
;
18 import java
.util
.Iterator
;
19 import java
.util
.List
;
21 import org
.eclipse
.linuxtools
.tmf
.core
.event
.ITmfTimestamp
;
22 import org
.eclipse
.linuxtools
.tmf
.ui
.views
.uml2sd
.drawings
.IColor
;
23 import org
.eclipse
.linuxtools
.tmf
.ui
.views
.uml2sd
.drawings
.IGC
;
24 import org
.eclipse
.linuxtools
.tmf
.ui
.views
.uml2sd
.preferences
.SDViewPref
;
25 import org
.eclipse
.linuxtools
.tmf
.ui
.views
.uml2sd
.util
.TimeEventComparator
;
28 * The Frame class is the base sequence diagram graph nodes container.<br>
29 * For instance, only one frame can be drawn in the View.<br>
30 * Lifelines, Messages and Stop which are supposed to represent a Sequence diagram are drawn in a Frame.<br>
31 * Only the graph node added to their representing list will be drawn.
33 * The lifelines are appended along the X axsis when added in a frame.<br>
34 * The syncMessages are ordered along the Y axsis depending on the event occurrence they are attached to.<br>
36 * @see org.eclipse.linuxtools.tmf.ui.views.uml2sd.core.Lifeline Lifeline for more event occurence details
40 public class Frame
extends BasicFrame
{
42 // ------------------------------------------------------------------------
44 // ------------------------------------------------------------------------
46 * The lifeline that is current highlighted.
48 protected Lifeline highlightLifeline
= null;
50 * The value of the start event.
52 protected int startEvent
= 0;
54 * The nubmer of events in the frame.
56 protected int nbEvent
= 0;
58 * The color for highlighting.
60 protected IColor highlightColor
= null;
62 * The list of time events of the corresponding execution occurrences.
64 protected List
<SDTimeEvent
> executionOccurrencesWithTime
;
66 * The Array of lifeline categories.
68 protected LifelineCategories
[] lifelineCategories
= null;
70 // ------------------------------------------------------------------------
72 // ------------------------------------------------------------------------
75 * Returns a list of all lifelines known by this frame. Known lifelines are the only one which can be displayed on
78 * @return the lifelines list
80 protected List
<GraphNode
> getLifelines() {
84 return (List
<GraphNode
>) nodes
.get(Lifeline
.LIFELINE_TAG
);
88 * Returns the number of lifelines stored in the frame
90 * @return the number of lifelines
92 public int lifeLinesCount() {
93 List
<GraphNode
> lifelines
= getLifelines();
94 if (lifelines
!= null) {
95 return lifelines
.size();
101 * Returns the lifeline at the given index in the lifelines array
103 * @param index the position in the lifeline array
104 * @return the lifeline or <code>null</code>
106 public Lifeline
getLifeline(int index
) {
107 if ((getLifelines() != null) && (index
>= 0) && (index
< lifeLinesCount())) {
108 return (Lifeline
) getLifelines().get(index
);
114 * Returns a list of syncMessages known by this frame. Known syncMessages are the only on which can be displayed on
117 * @return the syncMessages list
119 protected List
<GraphNode
> getSyncMessages() {
123 return (List
<GraphNode
>) nodes
.get(SyncMessage
.SYNC_MESS_TAG
);
127 * Returns the number of syncMessages stored in the frame
129 * @return the number of syncMessage
131 public int syncMessageCount() {
132 if (getSyncMessages() != null) {
133 return getSyncMessages().size();
139 * Returns the syncMessage at the given index in the syncMessages array
141 * @param index the position in the syncMessages array
142 * @return the syncMessage or <code>null</code>
144 public SyncMessage
getSyncMessage(int index
) {
145 if ((getSyncMessages() != null) && (index
>= 0) && (index
< getSyncMessages().size())) {
146 return (SyncMessage
) getSyncMessages().get(index
);
152 * Returns a list of asyncMessages known by this frame. Known asyncMessages are the only on which can be displayed
155 * @return the asyncMessages list or <code>null</code>
157 protected List
<GraphNode
> getAsyncMessages() {
161 return (List
<GraphNode
>) nodes
.get(AsyncMessage
.ASYNC_MESS_TAG
);
165 * Returns the number of asyncMessage stored in the frame
167 * @return the number of asyncMessage
169 public int asyncMessageCount() {
170 if (getAsyncMessages() != null) {
171 return getAsyncMessages().size();
177 * Returns the asyncMessage at the given index in the asyncMessage array
179 * @param index the position in the asyncMessage array
180 * @return the asyncMessage or <code>null</code>
182 public AsyncMessage
getAsyncMessage(int index
) {
183 if ((getAsyncMessages() != null) && (index
>= 0) && (index
< getAsyncMessages().size())) {
184 return (AsyncMessage
) getAsyncMessages().get(index
);
190 * Returns a list of syncMessages return known by this frame. Known syncMessages return are the only on which can be
191 * displayed on screen
193 * @return the syncMessages return list or <code>null</code>
195 protected List
<GraphNode
> getSyncMessagesReturn() {
199 return (List
<GraphNode
>) nodes
.get(SyncMessageReturn
.SYNC_MESS_RET_TAG
);
203 * Returns the number of syncMessageReturn stored in the frame
205 * @return the number of syncMessageReturn
207 public int syncMessageReturnCount() {
208 if (getSyncMessagesReturn() != null) {
209 return getSyncMessagesReturn().size();
215 * Returns the syncMessageReturn at the given index in the syncMessageReturn array
217 * @param index the position in the syncMessageReturn array
218 * @return the syncMessageReturn or <code>null</code>
220 public SyncMessageReturn
getSyncMessageReturn(int index
) {
221 if ((getSyncMessagesReturn() != null) && (index
>= 0) && (index
< getSyncMessagesReturn().size())) {
222 return (SyncMessageReturn
) getSyncMessagesReturn().get(index
);
228 * Returns a list of asyncMessageRetun known by this frame. Known asyncMessageRetun are the only on which can be
229 * displayed on screen
231 * @return the asyncMessageRetun list or <code>null</code>
233 protected List
<GraphNode
> getAsyncMessagesReturn() {
237 return (List
<GraphNode
>) nodes
.get(AsyncMessageReturn
.ASYNC_MESS_RET_TAG
);
241 * Returns the number of asyncMessageReturn stored in the frame
243 * @return the number of asyncMessageReturn
245 public int asyncMessageReturnCount() {
246 if (getAsyncMessagesReturn() != null) {
247 return getAsyncMessagesReturn().size();
253 * Returns the asyncMessageReturn at the given index in the asyncMessageReturn array
255 * @param index the position in the asyncMessageReturn array
256 * @return the asyncMessageReturn or <code>null</code>
258 public AsyncMessageReturn
getAsyncMessageReturn(int index
) {
259 if ((getAsyncMessagesReturn() != null) && (index
>= 0) && (index
< getAsyncMessagesReturn().size())) {
260 return (AsyncMessageReturn
) getAsyncMessagesReturn().get(index
);
266 * Adds a lifeline to the frame lifelines list. The lifeline X drawing order depends on the lifeline addition order
267 * into the frame lifelines list.
269 * @param lifeline the lifeline to add
271 public void addLifeLine(Lifeline lifeline
) {
272 computeMinMax
= true;
273 if (lifeline
== null) {
276 // set the lifeline parent frame
277 lifeline
.setFrame(this);
278 // Increate the frame lifeline counter
279 // and set the lifeline drawing order
280 lifeline
.setIndex(getNewHorizontalIndex());
281 if (lifeline
.hasTimeInfo()) {
284 // add the lifeline to the lifelines list
289 * Returns the first visible lifeline drawn in the view
291 * @return the first visible lifeline index
293 public int getFirstVisibleLifeline() {
296 } else if (indexes
.get(Lifeline
.LIFELINE_TAG
) != null) {
297 return ((Integer
) indexes
.get(Lifeline
.LIFELINE_TAG
)).intValue();
303 * Returns the first visible synchronous message drawn in the view
305 * @return the first visible synchronous message index
307 public int getFirstVisibleSyncMessage() {
310 } else if (indexes
.get(SyncMessage
.SYNC_MESS_TAG
) != null) {
311 return ((Integer
) indexes
.get(SyncMessage
.SYNC_MESS_TAG
)).intValue();
317 * Returns the first visible synchronous message return drawn in the view
319 * @return the first visible synchronous message return index
321 public int getFirstVisibleSyncMessageReturn() {
324 } else if (indexes
.get(SyncMessageReturn
.SYNC_MESS_RET_TAG
) != null) {
325 return ((Integer
) indexes
.get(SyncMessageReturn
.SYNC_MESS_RET_TAG
)).intValue();
331 * Returns the first visible synchronous message drawn in the view
333 * @return the first visible synchronous message index
335 public int getFirstVisibleAsyncMessage() {
338 } else if (indexes
.get(AsyncMessage
.ASYNC_MESS_TAG
) != null) {
339 return ((Integer
) indexes
.get(AsyncMessage
.ASYNC_MESS_TAG
)).intValue();
345 * Returns the first visible synchronous message return drawn in the view
347 * @return the first visible synchronous message return index
349 public int getFirstVisibleAsyncMessageReturn() {
352 } else if (indexes
.get(AsyncMessageReturn
.ASYNC_MESS_RET_TAG
) != null) {
353 return ((Integer
) indexes
.get(AsyncMessageReturn
.ASYNC_MESS_RET_TAG
)).intValue();
359 * Returns the list of execution occurrences.
361 * @return the list of execution occurrences
363 public List
<SDTimeEvent
> getExecutionOccurrencesWithTime() {
364 return executionOccurrencesWithTime
;
368 * Inserts a lifeline after a given lifeline.
370 * @param toInsert A lifeline to insert
371 * @param after A lifelife the toInsert-lifeline will be inserted after.
373 public void insertLifelineAfter(Lifeline toInsert
, Lifeline after
) {
374 if ((toInsert
== null)) {
377 if (toInsert
== after
) {
382 insertPoint
= after
.getIndex();
384 int removePoint
= toInsert
.getIndex() - 1;
385 if (removePoint
>= insertPoint
) {
386 getLifelines().remove(removePoint
);
388 getLifelines().add(insertPoint
, toInsert
);
389 if (removePoint
< insertPoint
) {
390 getLifelines().remove(removePoint
);
393 if (removePoint
>= insertPoint
) {
394 toInsert
.setIndex(insertPoint
+ 1);
396 toInsert
.setIndex(insertPoint
- 1);
400 if (removePoint
>= insertPoint
) {
401 for (int i
= insertPoint
; i
< getLifelines().size(); i
++) {
402 getLifeline(i
).setIndex(i
+ 1);
405 for (int i
= 0; i
< insertPoint
&& i
< getLifelines().size(); i
++) {
406 getLifeline(i
).setIndex(i
+ 1);
412 * Inserts a lifeline before a given lifeline.
414 * @param toInsert A lifeline to insert
415 * @param after A lifelife the toInsert-lifeline will be inserted before.
417 public void insertLifelineBefore(Lifeline toInsert
, Lifeline before
) {
418 if ((toInsert
== null)) {
421 if (toInsert
== before
) {
425 if (before
!= null) {
426 insertPoint
= before
.getIndex() - 1;
428 int removePoint
= toInsert
.getIndex() - 1;
429 if (removePoint
>= insertPoint
) {
430 getLifelines().remove(removePoint
);
432 getLifelines().add(insertPoint
, toInsert
);
433 if (removePoint
< insertPoint
) {
434 getLifelines().remove(removePoint
);
437 if (removePoint
>= insertPoint
) {
438 toInsert
.setIndex(insertPoint
+ 1);
440 toInsert
.setIndex(insertPoint
- 1);
444 if (removePoint
>= insertPoint
) {
445 for (int i
= insertPoint
; i
< getLifelines().size(); i
++) {
446 getLifeline(i
).setIndex(i
+ 1);
449 for (int i
= 0; i
< insertPoint
&& i
< getLifelines().size(); i
++) {
450 getLifeline(i
).setIndex(i
+ 1);
456 * Gets the closer life line to the given x-coordinate.
458 * @param x A x coordinate
459 * @return the closer lifeline
461 public Lifeline
getCloserLifeline(int x
) {
462 int index
= (x
- Metrics
.FRAME_H_MARGIN
+ Metrics
.LIFELINE_H_MAGIN
) / Metrics
.swimmingLaneWidth() - 1;
466 if (index
>= getLifelines().size()) {
467 index
= getLifelines().size() - 1;
469 Lifeline node1
, node2
, node3
;
470 int dist1
, dist2
, dist3
;
471 node1
= node2
= node3
= getLifeline(index
);
472 dist1
= dist2
= dist3
= Math
.abs(node1
.getX() + node1
.getWidth() / 2 - x
);
474 node2
= getLifeline(index
- 1);
475 dist2
= Math
.abs(node2
.getX() + node2
.getWidth() / 2 - x
);
477 if (index
< getLifelines().size() - 1) {
478 node3
= getLifeline(index
+ 1);
479 dist3
= Math
.abs(node3
.getX() + node3
.getWidth() / 2 - x
);
481 if (dist1
<= dist2
&& dist1
<= dist3
) {
483 } else if (dist2
<= dist1
&& dist2
<= dist3
) {
490 * Re-orders the given list of lifelines.
492 * @param list A list of lifelines to reorder.
494 public void reorder(ArrayList
<?
> list
) {
495 for (int i
= 0; i
< list
.size(); i
++) {
496 if (list
.get(i
) instanceof Lifeline
[]) {
497 Lifeline temp
[] = (Lifeline
[]) list
.get(i
);
498 if (temp
.length
== 2) {
499 if (temp
[1] == null) {
500 insertLifelineAfter(temp
[0], getLifeline(lifeLinesCount() - 1));
502 insertLifelineBefore(temp
[0], temp
[1]);
510 * Resets the time compression information.
512 public void resetTimeCompression() {
513 highlightLifeline
= null;
516 highlightColor
= null;
521 * @see org.eclipse.linuxtools.tmf.ui.views.uml2sd.core.BasicFrame#computeMinMax()
524 protected void computeMinMax() {
525 List
<SDTimeEvent
> timeArray
= buildTimeArray();
526 if (timeArray
== null) {
529 for (int i
= 0; i
< timeArray
.size() - 1; i
++) {
530 SDTimeEvent m1
= (SDTimeEvent
) timeArray
.get(i
);
531 SDTimeEvent m2
= (SDTimeEvent
) timeArray
.get(i
+ 1);
532 if (SDViewPref
.getInstance().excludeExternalTime())
533 if ((m1
.getGraphNode() instanceof BaseMessage
) && (m2
.getGraphNode() instanceof BaseMessage
)) {
534 BaseMessage mes1
= (BaseMessage
) m1
.getGraphNode();
535 BaseMessage mes2
= (BaseMessage
) m2
.getGraphNode();
536 if ((mes2
.startLifeline
== null) || (mes1
.endLifeline
== null)) {
541 updateMinMax(m1
, m2
);
546 * Find the two graph nodes that are closest to this date, one just earlier, second just later. If date is before
547 * any graph node, bounds[0] is null and bounds[1] is the earliest. If date is after any graph node, bounds[1] is
548 * null and bounds[0] is the latest.
550 * @param dateToFind date to be found
551 * @param bounds a two items array that will receive bounds if found
552 * @return true if both bounds not null
554 public boolean findDateBounds(ITmfTimestamp dateToFind
, ITimeRange bounds
[]) {
556 List
<SDTimeEvent
> timeArray
= buildTimeArray();
559 for (int i
= 0; i
< timeArray
.size(); i
++) {
560 SDTimeEvent m
= (SDTimeEvent
) timeArray
.get(i
);
561 if (m
.getTime().compareTo(dateToFind
, true) > 0) {
562 bounds
[1] = m
.getGraphNode();
564 bounds
[0] = ((SDTimeEvent
) timeArray
.get(i
- 1)).getGraphNode();
570 bounds
[0] = ((SDTimeEvent
) timeArray
.get(timeArray
.size() - 1)).getGraphNode();
576 * Set whether time information is available or not
578 * @param value <code>true</code> for has time information else <code>false</code>
580 protected void setHasTimeInfo(boolean value
) {
585 * Returns whether frame has time info or not.
587 * @return <code>true</code> whether frame has time info else <code>false</code>
589 public boolean hasTimeInfo() {
594 * Highlights the time compression.
596 * @param lifeline A lifeline to highlight
597 * @param startEvent A start event number
598 * @param nbEvent A number of events
599 * @param color A color for highlighting
601 public void highlightTimeCompression(Lifeline lifeline
, int startEvent
, int nbEvent
, IColor color
) {
602 highlightLifeline
= lifeline
;
603 this.startEvent
= startEvent
;
604 this.nbEvent
= nbEvent
;
605 highlightColor
= color
;
609 * Set the lifeline categories which will be use during the lifelines creation
611 * @see Lifeline#setCategory(int)
612 * @param categories the lifeline categories array
614 public void setLifelineCategories(LifelineCategories
[] categories
) {
615 lifelineCategories
= Arrays
.copyOf(categories
, categories
.length
);
619 * Returns the lifeline categories array set for the this frame
621 * @return the lifeline categories array or null if not set
623 public LifelineCategories
[] getLifelineCategories() {
624 return Arrays
.copyOf(lifelineCategories
, lifelineCategories
.length
);
628 * Adds a message to the Frame message list. Four kinds of syncMessages can be added:<br>
629 * - synchronous syncMessages<br>
630 * - synchronous syncMessages return<br>
631 * - asynchronous syncMessages<br>
632 * - asynchronous syncMessages return<br>
633 * For drawing performance reason, it is recommended to add synchronous syncMessages in the same order they should
634 * appear along the Y axis in the Frame.
636 * @param message the message to add
638 public void addMessage(BaseMessage message
) {
644 * @see org.eclipse.linuxtools.tmf.ui.views.uml2sd.core.BasicFrame#draw(org.eclipse.linuxtools.tmf.ui.views.uml2sd.drawings.IGC)
647 public void draw(IGC context
) {
653 if (highlightLifeline
!= null) {
654 IColor backupColor
= context
.getBackground();
655 context
.setBackground(Frame
.getUserPref().getTimeCompressionSelectionColor());
656 int gy
= highlightLifeline
.getY() + highlightLifeline
.getHeight() + (Metrics
.getMessageFontHeigth() + Metrics
.getMessagesSpacing()) * startEvent
;
657 context
.fillRectangle(Metrics
.FRAME_H_MARGIN
+ 1, gy
, highlightLifeline
.getX() + Metrics
.getLifelineWidth() / 2 - Metrics
.FRAME_H_MARGIN
, (Metrics
.getMessageFontHeigth() + Metrics
.getMessagesSpacing()) * nbEvent
);
658 context
.setBackground(backupColor
);
660 super.draw(context
, false);
661 int lifelineArryStep
= 1;
662 if (Metrics
.swimmingLaneWidth() * context
.getZoom() < Metrics
.LIFELINE_SIGNIFICANT_HSPACING
) {
663 lifelineArryStep
= Math
.round(Metrics
.LIFELINE_SIGNIFICANT_HSPACING
/ (Metrics
.swimmingLaneWidth() * context
.getZoom()));
665 if (indexes
.size() == 0) {
668 int lifeLineDrawIndex
= ((Integer
) indexes
.get(Lifeline
.LIFELINE_TAG
)).intValue();
669 for (int i
= lifeLineDrawIndex
; i
< ((List
<GraphNode
>) nodes
.get(Lifeline
.LIFELINE_TAG
)).size(); i
= i
+ lifelineArryStep
) {
670 Lifeline toDraw
= (Lifeline
) ((List
<GraphNode
>) nodes
.get(Lifeline
.LIFELINE_TAG
)).get(i
);
671 if (toDraw
.getX() - Metrics
.LIFELINE_SPACING
/ 2 > context
.getContentsX() + context
.getVisibleWidth()) {
674 toDraw
.drawName(context
);
676 if (highlightLifeline
!= null) {
677 if (toDraw
== highlightLifeline
) {
678 toDraw
.highlightExecOccurrenceRegion(context
, startEvent
, nbEvent
, highlightColor
);
679 } else if ((toDraw
.getIndex() < highlightLifeline
.getIndex()) || ((toDraw
.getIndex() < highlightLifeline
.getIndex()))) {
681 int acIndex
= toDraw
.getExecOccurrenceDrawIndex();
682 // acIndex = first visible execution occurrence
683 // for drawing speed reason with only search on the visible subset
684 if (toDraw
.getExecutions() != null) {
685 for (int index
= acIndex
; index
< toDraw
.getExecutions().size(); index
++) {
686 BasicExecutionOccurrence exec
= (BasicExecutionOccurrence
) toDraw
.getExecutions().get(index
);
687 int tempEvent
= startEvent
;
688 for (int j
= 0; j
< nbEvent
; j
++) {
689 if (((tempEvent
>= exec
.startEventOccurrence
) && (tempEvent
<= exec
.endEventOccurrence
) && (tempEvent
+ 1 >= exec
.startEventOccurrence
) && (tempEvent
+ 1 <= exec
.endEventOccurrence
))) {
690 toDraw
.highlightExecOccurrenceRegion(context
, tempEvent
, 1, Frame
.getUserPref().getTimeCompressionSelectionColor());
692 tempEvent
= tempEvent
+ 1;
694 // if we are outside the visible area we stop right now
695 // This works because execution occurrences are ordered along the Y axis
696 if (exec
.getY() > getY()) {
708 * @see org.eclipse.linuxtools.tmf.ui.views.uml2sd.core.BasicFrame#buildTimeArray()
711 protected List
<SDTimeEvent
> buildTimeArray() {
716 List
<SDTimeEvent
> timeArray
= super.buildTimeArray();
717 executionOccurrencesWithTime
= null;
718 if (getLifelines() != null) {
719 for (int i
= 0; i
< ((List
<GraphNode
>) nodes
.get(Lifeline
.LIFELINE_TAG
)).size(); i
++) {
720 Lifeline l
= (Lifeline
) ((List
<GraphNode
>) nodes
.get(Lifeline
.LIFELINE_TAG
)).get(i
);
721 if (l
.hasTimeInfo() && l
.getExecutions() != null) {
722 for (Iterator
<GraphNode
> j
= l
.getExecutions().iterator(); j
.hasNext();) {
723 GraphNode o
= j
.next();
724 if (o
instanceof ExecutionOccurrence
) {
725 ExecutionOccurrence eo
= (ExecutionOccurrence
) o
;
726 if (eo
.hasTimeInfo()) {
727 int event
= eo
.getStartOccurrence();
728 ITmfTimestamp time
= eo
.getStartTime();
729 SDTimeEvent f
= new SDTimeEvent(time
, event
, eo
);
731 if (executionOccurrencesWithTime
== null) {
732 executionOccurrencesWithTime
= new ArrayList
<SDTimeEvent
>();
734 executionOccurrencesWithTime
.add(f
);
735 event
= eo
.getEndOccurrence();
736 time
= eo
.getEndTime();
737 f
= new SDTimeEvent(time
, event
, eo
);
739 executionOccurrencesWithTime
.add(f
);
747 if (executionOccurrencesWithTime
!= null) {
748 SDTimeEvent
[] temp
= executionOccurrencesWithTime
.toArray(new SDTimeEvent
[0]);
749 Arrays
.sort(temp
, new TimeEventComparator());
750 executionOccurrencesWithTime
= Arrays
.asList(temp
);
752 SDTimeEvent
[] temp
= timeArray
.toArray(new SDTimeEvent
[0]);
753 Arrays
.sort(temp
, new TimeEventComparator());
754 timeArray
= Arrays
.asList(temp
);
756 } catch (Exception e
) {
764 * Get the closer leaving message.
766 * @param lifeline A lifeline reference
767 * @param message A message reference
768 * @param list A list of graph nodes
769 * @param smallerEvent A smaller event flag
770 * @return the closer leaving message.
772 protected GraphNode
getCloserLeavingMessage(Lifeline lifeline
, BaseMessage message
, List
<GraphNode
> list
, boolean smallerEvent
) {
777 if (smallerEvent
== false) {
779 if (message
!= null) {
780 event
= message
.getEventOccurrence();
782 for (int i
= 0; i
< list
.size(); i
++) {
783 GraphNode node
= (GraphNode
) list
.get(i
);
784 if (node
instanceof SyncMessage
) {
785 SyncMessage syncNode
= (SyncMessage
) node
;
786 if ((syncNode
.getEventOccurrence() > event
) && (syncNode
.getStartLifeline() == lifeline
) && !syncNode
.isSameAs(message
)) {
789 } else if (node
instanceof AsyncMessage
) {
790 AsyncMessage asyncNode
= (AsyncMessage
) node
;
791 if ((asyncNode
.getStartOccurrence() > event
) && (asyncNode
.getStartLifeline() == lifeline
) && !asyncNode
.isSameAs(message
)) {
797 int event
= getMaxEventOccurrence();
798 if (message
!= null) {
799 if (message
instanceof AsyncMessage
) {
800 event
= ((AsyncMessage
) message
).getStartOccurrence();
802 event
= message
.getEventOccurrence();
805 for (int i
= list
.size() - 1; i
>= 0; i
--) {
806 GraphNode node
= (GraphNode
) list
.get(i
);
807 if (node
instanceof SyncMessage
) {
808 SyncMessage syncNode
= (SyncMessage
) node
;
809 if ((syncNode
.getEventOccurrence() < event
) && (syncNode
.getStartLifeline() == lifeline
) && !syncNode
.isSameAs(message
)) {
812 } else if (node
instanceof AsyncMessage
) {
813 AsyncMessage asyncNode
= (AsyncMessage
) node
;
814 if ((asyncNode
.getStartOccurrence() < event
) && (asyncNode
.getStartLifeline() == lifeline
) && !asyncNode
.isSameAs(message
)) {
825 * Get the closer entering message.
827 * @param lifeline A lifeline reference
828 * @param message A message reference
829 * @param list A list of graph nodes
830 * @param smallerEvent A smaller event flag
831 * @return the closer entering message.
833 protected GraphNode
getCloserEnteringMessage(Lifeline lifeline
, BaseMessage message
, List
<GraphNode
> list
, boolean smallerEvent
) {
837 if (smallerEvent
== false) {
839 if (message
!= null) {
840 event
= message
.getEventOccurrence();
842 for (int i
= 0; i
< list
.size(); i
++) {
843 GraphNode node
= (GraphNode
) list
.get(i
);
844 if (node
instanceof SyncMessage
) {
845 SyncMessage syncNode
= (SyncMessage
) node
;
846 if ((syncNode
.getEventOccurrence() > event
) && (syncNode
.getEndLifeline() == lifeline
) && !syncNode
.isSameAs(message
)) {
849 } else if (node
instanceof AsyncMessage
) {
850 AsyncMessage asyncNode
= (AsyncMessage
) node
;
851 if ((asyncNode
.getStartOccurrence() > event
) && (asyncNode
.getEndLifeline() == lifeline
) && !asyncNode
.isSameAs(message
)) {
857 int event
= getMaxEventOccurrence();
859 if (message
instanceof AsyncMessage
) {
860 event
= ((AsyncMessage
) message
).getStartOccurrence();
862 event
= message
.getEventOccurrence();
864 for (int i
= list
.size() - 1; i
>= 0; i
--) {
865 GraphNode node
= (GraphNode
) list
.get(i
);
866 if (node
instanceof SyncMessage
) {
867 SyncMessage syncNode
= (SyncMessage
) node
;
868 if ((syncNode
.getEventOccurrence() < event
) && (syncNode
.getEndLifeline() == lifeline
) && !syncNode
.isSameAs(message
)) {
871 } else if (node
instanceof AsyncMessage
) {
872 AsyncMessage asyncNode
= (AsyncMessage
) node
;
873 if ((asyncNode
.getStartOccurrence() < event
) && (asyncNode
.getEndLifeline() == lifeline
) && !asyncNode
.isSameAs(message
)) {
883 * Get distance of given event from given graph node.
885 * @param node A graph node reference.
886 * @param event A event number to check.
887 * @return distance of event from graph node.
889 protected int distanceFromEvent(GraphNode node
, int event
) {
891 if (node
instanceof SyncMessage
) {
892 distance
= ((SyncMessage
) node
).getEventOccurrence() - event
;
893 } else if (node
instanceof AsyncMessage
) {
894 int start
= ((AsyncMessage
) node
).getStartOccurrence();
895 int end
= ((AsyncMessage
) node
).getEndOccurrence();
896 if ((start
- event
) < (end
- event
)) {
897 distance
= start
- event
;
899 distance
= end
- event
;
902 return Math
.abs(distance
);
906 * Get node from 2 given nodes that is close to event.
908 * @param node1 A first graph node
909 * @param node2 A second graph node
910 * @param event A event to check.
911 * @return graph node that is closer or <code>null</code>
913 protected GraphNode
getCloserToEvent(GraphNode node1
, GraphNode node2
, int event
) {
914 if ((node1
!= null) && (node2
!= null)) {
915 if (distanceFromEvent(node1
, event
) < distanceFromEvent(node2
, event
)) {
920 } else if (node1
!= null) {
922 } else if (node2
!= null) {
929 * Get called 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
getCalledMessage(BaseMessage startMessage
) {
936 GraphNode result
= null;
937 Lifeline lifeline
= null;
938 if (startMessage
!= null) {
939 event
= ((BaseMessage
) startMessage
).getEventOccurrence();
940 lifeline
= ((BaseMessage
) startMessage
).getEndLifeline();
941 if (lifeline
== null) {
942 lifeline
= ((BaseMessage
) startMessage
).getStartLifeline();
945 if (lifeline
== null) {
948 GraphNode message
= getCloserLeavingMessage(lifeline
, startMessage
, getSyncMessages(), false);
949 GraphNode messageReturn
= getCloserLeavingMessage(lifeline
, startMessage
, getSyncMessagesReturn(), false);
950 result
= getCloserToEvent(message
, messageReturn
, event
);
951 message
= getCloserLeavingMessage(lifeline
, startMessage
, getAsyncMessages(), false);
952 result
= getCloserToEvent(result
, message
, event
);
953 messageReturn
= getCloserLeavingMessage(lifeline
, startMessage
, getAsyncMessagesReturn(), false);
954 result
= getCloserToEvent(result
, messageReturn
, event
);
959 * Get caller message based on given start message.
961 * @param startMessage A start message to check.
962 * @return called message (graph node) or <code>null</code>
964 public GraphNode
getCallerMessage(BaseMessage startMessage
) {
965 int event
= getMaxEventOccurrence();
966 GraphNode result
= null;
967 Lifeline lifeline
= null;
968 if (startMessage
!= null) {
969 event
= ((BaseMessage
) startMessage
).getEventOccurrence();
970 lifeline
= ((BaseMessage
) startMessage
).getStartLifeline();
971 if (lifeline
== null) {
972 lifeline
= ((BaseMessage
) startMessage
).getEndLifeline();
975 if (lifeline
== null) {
978 GraphNode message
= getCloserEnteringMessage(lifeline
, startMessage
, getSyncMessages(), true);
979 GraphNode messageReturn
= getCloserEnteringMessage(lifeline
, startMessage
, getSyncMessagesReturn(), true);
980 result
= getCloserToEvent(message
, messageReturn
, event
);
981 message
= getCloserEnteringMessage(lifeline
, startMessage
, getAsyncMessages(), true);
982 result
= getCloserToEvent(result
, message
, event
);
983 messageReturn
= getCloserEnteringMessage(lifeline
, startMessage
, getAsyncMessagesReturn(), true);
984 result
= getCloserToEvent(result
, messageReturn
, event
);
989 * Get next lifeline based on given message.
991 * @param lifeline A lifeline reference
992 * @param startMessage A start message to check
993 * @return next lifeline or <code>null</code>
995 public GraphNode
getNextLifelineMessage(Lifeline lifeline
, BaseMessage startMessage
) {
997 if (startMessage
!= null) {
998 event
= ((BaseMessage
) startMessage
).getEventOccurrence();
1000 if (lifeline
== null) {
1003 GraphNode message
= getCloserLeavingMessage(lifeline
, startMessage
, getSyncMessages(), false);
1004 GraphNode messageReturn
= getCloserLeavingMessage(lifeline
, startMessage
, getSyncMessagesReturn(), false);
1005 GraphNode result
= getCloserToEvent(message
, messageReturn
, event
);
1006 message
= getCloserLeavingMessage(lifeline
, startMessage
, getAsyncMessages(), false);
1007 result
= getCloserToEvent(result
, message
, event
);
1008 messageReturn
= getCloserLeavingMessage(lifeline
, startMessage
, getAsyncMessagesReturn(), false);
1009 result
= getCloserToEvent(result
, messageReturn
, event
);
1014 * Get previous lifeline based on given message.
1016 * @param lifeline A lifeline reference
1017 * @param startMessage A start message to check.
1018 * @return previous lifeline or <code>null</code>
1020 public GraphNode
getPrevLifelineMessage(Lifeline lifeline
, BaseMessage startMessage
) {
1021 int event
= getMaxEventOccurrence();
1022 if (startMessage
!= null)
1023 if (startMessage
instanceof AsyncMessage
) {
1024 event
= ((AsyncMessage
) startMessage
).getStartOccurrence();
1026 event
= startMessage
.getEventOccurrence();
1028 if (lifeline
== null) {
1031 GraphNode message
= getCloserLeavingMessage(lifeline
, startMessage
, getSyncMessages(), true);
1032 GraphNode messageReturn
= getCloserLeavingMessage(lifeline
, startMessage
, getSyncMessagesReturn(), true);
1033 GraphNode result
= getCloserToEvent(message
, messageReturn
, event
);
1034 message
= getCloserLeavingMessage(lifeline
, startMessage
, getAsyncMessages(), true);
1035 result
= getCloserToEvent(result
, message
, event
);
1036 messageReturn
= getCloserLeavingMessage(lifeline
, startMessage
, getAsyncMessagesReturn(), true);
1037 result
= getCloserToEvent(result
, messageReturn
, event
);
1042 * Get the first execution occurrence.
1044 * @param lifeline A lifeline reference
1045 * @return the first execution occurrence of lifeline or <code>null</code>.
1047 public BasicExecutionOccurrence
getFirstExecution(Lifeline lifeline
) {
1048 if (lifeline
== null) {
1051 List
<GraphNode
> list
= lifeline
.getExecutions();
1055 if (list
.size() == 0) {
1058 BasicExecutionOccurrence result
= (BasicExecutionOccurrence
) list
.get(0);
1059 for (int i
= 0; i
< list
.size(); i
++) {
1060 BasicExecutionOccurrence e
= (BasicExecutionOccurrence
) list
.get(i
);
1061 if ((e
.getStartOccurrence() < result
.getEndOccurrence())) {
1069 * Get the previous execution occurrence relative to a given execution occurrence.
1071 * @param exec A execution occurrence reference.
1072 * @return the previous execution occurrence of lifeline or <code>null</code>.
1074 public BasicExecutionOccurrence
getPrevExecOccurrence(BasicExecutionOccurrence exec
) {
1078 Lifeline lifeline
= exec
.getLifeline();
1079 if (lifeline
== null) {
1082 List
<GraphNode
> list
= lifeline
.getExecutions();
1086 BasicExecutionOccurrence result
= null;
1087 for (int i
= 0; i
< list
.size(); i
++) {
1088 BasicExecutionOccurrence e
= (BasicExecutionOccurrence
) list
.get(i
);
1089 if ((e
.getStartOccurrence() < exec
.startEventOccurrence
) && (result
== null)) {
1092 if ((e
.getStartOccurrence() < exec
.startEventOccurrence
) && (e
.getStartOccurrence() >= result
.getEndOccurrence())) {
1100 * Get the next execution occurrence relative to a given execution occurrence.
1102 * @param exec A execution occurrence reference.
1103 * @return the next execution occurrence of lifeline or <code>null</code>.
1105 public BasicExecutionOccurrence
getNextExecOccurrence(BasicExecutionOccurrence exec
) {
1109 Lifeline lifeline
= exec
.getLifeline();
1110 if (lifeline
== null) {
1113 List
<GraphNode
> list
= lifeline
.getExecutions();
1117 BasicExecutionOccurrence result
= null;
1118 for (int i
= 0; i
< list
.size(); i
++) {
1119 BasicExecutionOccurrence e
= (BasicExecutionOccurrence
) list
.get(i
);
1120 if ((e
.getStartOccurrence() > exec
.startEventOccurrence
) && (result
== null)) {
1123 if ((e
.getStartOccurrence() > exec
.startEventOccurrence
) && (e
.getStartOccurrence() <= result
.getEndOccurrence())) {
1131 * Get the last execution occurrence.
1133 * @param lifeline A lifeline reference.
1134 * @return the last execution occurrence of lifeline or <code>null</code>.
1136 public BasicExecutionOccurrence
getLastExecOccurrence(Lifeline lifeline
) {
1137 if (lifeline
== null) {
1140 List
<GraphNode
> list
= lifeline
.getExecutions();
1144 BasicExecutionOccurrence result
= null;
1145 for (int i
= 0; i
< list
.size(); i
++) {
1146 BasicExecutionOccurrence e
= (BasicExecutionOccurrence
) list
.get(i
);
1147 if (result
== null) {
1150 if (e
.getStartOccurrence() > result
.getEndOccurrence()) {