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
.core
.runtime
.IStatus
;
22 import org
.eclipse
.core
.runtime
.Status
;
23 import org
.eclipse
.linuxtools
.internal
.tmf
.ui
.TmfUiPlugin
;
24 import org
.eclipse
.linuxtools
.tmf
.core
.event
.ITmfTimestamp
;
25 import org
.eclipse
.linuxtools
.tmf
.ui
.views
.uml2sd
.drawings
.IColor
;
26 import org
.eclipse
.linuxtools
.tmf
.ui
.views
.uml2sd
.drawings
.IGC
;
27 import org
.eclipse
.linuxtools
.tmf
.ui
.views
.uml2sd
.preferences
.SDViewPref
;
28 import org
.eclipse
.linuxtools
.tmf
.ui
.views
.uml2sd
.util
.TimeEventComparator
;
31 * The Frame class is the base sequence diagram graph nodes container.<br>
32 * For instance, only one frame can be drawn in the View.<br>
33 * Lifelines, Messages and Stop which are supposed to represent a Sequence diagram are drawn in a Frame.<br>
34 * Only the graph node added to their representing list will be drawn.
36 * The lifelines are appended along the X axsis when added in a frame.<br>
37 * The syncMessages are ordered along the Y axsis depending on the event occurrence they are attached to.<br>
39 * @see org.eclipse.linuxtools.tmf.ui.views.uml2sd.core.Lifeline Lifeline for more event occurence details
43 public class Frame
extends BasicFrame
{
45 // ------------------------------------------------------------------------
47 // ------------------------------------------------------------------------
49 * The lifeline that is current highlighted.
51 protected Lifeline fHighlightLifeline
= null;
53 * The value of the start event.
55 protected int fStartEvent
= 0;
57 * The nubmer of events in the frame.
59 protected int fNbEvent
= 0;
61 * The color for highlighting.
63 protected IColor fHighlightColor
= null;
65 * The list of time events of the corresponding execution occurrences.
67 protected List
<SDTimeEvent
> fExecutionOccurrencesWithTime
;
69 * The Array of lifeline categories.
71 protected LifelineCategories
[] fLifelineCategories
= null;
73 // ------------------------------------------------------------------------
75 // ------------------------------------------------------------------------
78 * Returns a list of all lifelines known by this frame. Known lifelines are the only one which can be displayed on
81 * @return the lifelines list
83 protected List
<GraphNode
> getLifelines() {
87 return (List
<GraphNode
>) fNodes
.get(Lifeline
.LIFELINE_TAG
);
91 * Returns the number of lifelines stored in the frame
93 * @return the number of lifelines
95 public int lifeLinesCount() {
96 List
<GraphNode
> lifelines
= getLifelines();
97 if (lifelines
!= null) {
98 return lifelines
.size();
104 * Returns the lifeline at the given index in the lifelines array
106 * @param index the position in the lifeline array
107 * @return the lifeline or <code>null</code>
109 public Lifeline
getLifeline(int index
) {
110 if ((getLifelines() != null) && (index
>= 0) && (index
< lifeLinesCount())) {
111 return (Lifeline
) getLifelines().get(index
);
117 * Returns a list of syncMessages known by this frame. Known syncMessages are the only on which can be displayed on
120 * @return the syncMessages list
122 protected List
<GraphNode
> getSyncMessages() {
126 return (List
<GraphNode
>) fNodes
.get(SyncMessage
.SYNC_MESS_TAG
);
130 * Returns the number of syncMessages stored in the frame
132 * @return the number of syncMessage
134 public int syncMessageCount() {
135 if (getSyncMessages() != null) {
136 return getSyncMessages().size();
142 * Returns the syncMessage at the given index in the syncMessages array
144 * @param index the position in the syncMessages array
145 * @return the syncMessage or <code>null</code>
147 public SyncMessage
getSyncMessage(int index
) {
148 if ((getSyncMessages() != null) && (index
>= 0) && (index
< getSyncMessages().size())) {
149 return (SyncMessage
) getSyncMessages().get(index
);
155 * Returns a list of asyncMessages known by this frame. Known asyncMessages are the only on which can be displayed
158 * @return the asyncMessages list or <code>null</code>
160 protected List
<GraphNode
> getAsyncMessages() {
164 return (List
<GraphNode
>) fNodes
.get(AsyncMessage
.ASYNC_MESS_TAG
);
168 * Returns the number of asyncMessage stored in the frame
170 * @return the number of asyncMessage
172 public int asyncMessageCount() {
173 if (getAsyncMessages() != null) {
174 return getAsyncMessages().size();
180 * Returns the asyncMessage at the given index in the asyncMessage array
182 * @param index the position in the asyncMessage array
183 * @return the asyncMessage or <code>null</code>
185 public AsyncMessage
getAsyncMessage(int index
) {
186 if ((getAsyncMessages() != null) && (index
>= 0) && (index
< getAsyncMessages().size())) {
187 return (AsyncMessage
) getAsyncMessages().get(index
);
193 * Returns a list of syncMessages return known by this frame. Known syncMessages return are the only on which can be
194 * displayed on screen
196 * @return the syncMessages return list or <code>null</code>
198 protected List
<GraphNode
> getSyncMessagesReturn() {
202 return (List
<GraphNode
>) fNodes
.get(SyncMessageReturn
.SYNC_MESS_RET_TAG
);
206 * Returns the number of syncMessageReturn stored in the frame
208 * @return the number of syncMessageReturn
210 public int syncMessageReturnCount() {
211 if (getSyncMessagesReturn() != null) {
212 return getSyncMessagesReturn().size();
218 * Returns the syncMessageReturn at the given index in the syncMessageReturn array
220 * @param index the position in the syncMessageReturn array
221 * @return the syncMessageReturn or <code>null</code>
223 public SyncMessageReturn
getSyncMessageReturn(int index
) {
224 if ((getSyncMessagesReturn() != null) && (index
>= 0) && (index
< getSyncMessagesReturn().size())) {
225 return (SyncMessageReturn
) getSyncMessagesReturn().get(index
);
231 * Returns a list of asyncMessageRetun known by this frame. Known asyncMessageRetun are the only on which can be
232 * displayed on screen
234 * @return the asyncMessageRetun list or <code>null</code>
236 protected List
<GraphNode
> getAsyncMessagesReturn() {
240 return (List
<GraphNode
>) fNodes
.get(AsyncMessageReturn
.ASYNC_MESS_RET_TAG
);
244 * Returns the number of asyncMessageReturn stored in the frame
246 * @return the number of asyncMessageReturn
248 public int asyncMessageReturnCount() {
249 if (getAsyncMessagesReturn() != null) {
250 return getAsyncMessagesReturn().size();
256 * Returns the asyncMessageReturn at the given index in the asyncMessageReturn array
258 * @param index the position in the asyncMessageReturn array
259 * @return the asyncMessageReturn or <code>null</code>
261 public AsyncMessageReturn
getAsyncMessageReturn(int index
) {
262 if ((getAsyncMessagesReturn() != null) && (index
>= 0) && (index
< getAsyncMessagesReturn().size())) {
263 return (AsyncMessageReturn
) getAsyncMessagesReturn().get(index
);
269 * Adds a lifeline to the frame lifelines list. The lifeline X drawing order depends on the lifeline addition order
270 * into the frame lifelines list.
272 * @param lifeline the lifeline to add
274 public void addLifeLine(Lifeline lifeline
) {
275 fComputeMinMax
= true;
276 if (lifeline
== null) {
279 // set the lifeline parent frame
280 lifeline
.setFrame(this);
281 // Increate the frame lifeline counter
282 // and set the lifeline drawing order
283 lifeline
.setIndex(getNewHorizontalIndex());
284 if (lifeline
.hasTimeInfo()) {
287 // add the lifeline to the lifelines list
292 * Returns the first visible lifeline drawn in the view
294 * @return the first visible lifeline index
296 public int getFirstVisibleLifeline() {
299 } else if (fIndexes
.get(Lifeline
.LIFELINE_TAG
) != null) {
300 return ((Integer
) fIndexes
.get(Lifeline
.LIFELINE_TAG
)).intValue();
306 * Returns the first visible synchronous message drawn in the view
308 * @return the first visible synchronous message index
310 public int getFirstVisibleSyncMessage() {
313 } else if (fIndexes
.get(SyncMessage
.SYNC_MESS_TAG
) != null) {
314 return ((Integer
) fIndexes
.get(SyncMessage
.SYNC_MESS_TAG
)).intValue();
320 * Returns the first visible synchronous message return drawn in the view
322 * @return the first visible synchronous message return index
324 public int getFirstVisibleSyncMessageReturn() {
327 } else if (fIndexes
.get(SyncMessageReturn
.SYNC_MESS_RET_TAG
) != null) {
328 return ((Integer
) fIndexes
.get(SyncMessageReturn
.SYNC_MESS_RET_TAG
)).intValue();
334 * Returns the first visible synchronous message drawn in the view
336 * @return the first visible synchronous message index
338 public int getFirstVisibleAsyncMessage() {
341 } else if (fIndexes
.get(AsyncMessage
.ASYNC_MESS_TAG
) != null) {
342 return ((Integer
) fIndexes
.get(AsyncMessage
.ASYNC_MESS_TAG
)).intValue();
348 * Returns the first visible synchronous message return drawn in the view
350 * @return the first visible synchronous message return index
352 public int getFirstVisibleAsyncMessageReturn() {
355 } else if (fIndexes
.get(AsyncMessageReturn
.ASYNC_MESS_RET_TAG
) != null) {
356 return ((Integer
) fIndexes
.get(AsyncMessageReturn
.ASYNC_MESS_RET_TAG
)).intValue();
362 * Returns the list of execution occurrences.
364 * @return the list of execution occurrences
366 public List
<SDTimeEvent
> getExecutionOccurrencesWithTime() {
367 return fExecutionOccurrencesWithTime
;
371 * Inserts a lifeline after a given lifeline.
373 * @param toInsert A lifeline to insert
374 * @param after A lifelife the toInsert-lifeline will be inserted after.
376 public void insertLifelineAfter(Lifeline toInsert
, Lifeline after
) {
377 if ((toInsert
== null)) {
380 if (toInsert
== after
) {
385 insertPoint
= after
.getIndex();
387 int removePoint
= toInsert
.getIndex() - 1;
388 if (removePoint
>= insertPoint
) {
389 getLifelines().remove(removePoint
);
391 getLifelines().add(insertPoint
, toInsert
);
392 if (removePoint
< insertPoint
) {
393 getLifelines().remove(removePoint
);
396 if (removePoint
>= insertPoint
) {
397 toInsert
.setIndex(insertPoint
+ 1);
399 toInsert
.setIndex(insertPoint
- 1);
403 if (removePoint
>= insertPoint
) {
404 for (int i
= insertPoint
; i
< getLifelines().size(); i
++) {
405 getLifeline(i
).setIndex(i
+ 1);
408 for (int i
= 0; i
< insertPoint
&& i
< getLifelines().size(); i
++) {
409 getLifeline(i
).setIndex(i
+ 1);
415 * Inserts a lifeline before a given lifeline.
417 * @param toInsert A lifeline to insert
418 * @param after A lifelife the toInsert-lifeline will be inserted before.
420 public void insertLifelineBefore(Lifeline toInsert
, Lifeline before
) {
421 if ((toInsert
== null)) {
424 if (toInsert
== before
) {
428 if (before
!= null) {
429 insertPoint
= before
.getIndex() - 1;
431 int removePoint
= toInsert
.getIndex() - 1;
432 if (removePoint
>= insertPoint
) {
433 getLifelines().remove(removePoint
);
435 getLifelines().add(insertPoint
, toInsert
);
436 if (removePoint
< insertPoint
) {
437 getLifelines().remove(removePoint
);
440 if (removePoint
>= insertPoint
) {
441 toInsert
.setIndex(insertPoint
+ 1);
443 toInsert
.setIndex(insertPoint
- 1);
447 if (removePoint
>= insertPoint
) {
448 for (int i
= insertPoint
; i
< getLifelines().size(); i
++) {
449 getLifeline(i
).setIndex(i
+ 1);
452 for (int i
= 0; i
< insertPoint
&& i
< getLifelines().size(); i
++) {
453 getLifeline(i
).setIndex(i
+ 1);
459 * Gets the closer life line to the given x-coordinate.
461 * @param x A x coordinate
462 * @return the closer lifeline
464 public Lifeline
getCloserLifeline(int x
) {
465 int index
= (x
- Metrics
.FRAME_H_MARGIN
+ Metrics
.LIFELINE_H_MAGIN
) / Metrics
.swimmingLaneWidth() - 1;
469 if (index
>= getLifelines().size()) {
470 index
= getLifelines().size() - 1;
472 Lifeline node1
, node2
, node3
;
473 int dist1
, dist2
, dist3
;
474 node1
= node2
= node3
= getLifeline(index
);
475 dist1
= dist2
= dist3
= Math
.abs(node1
.getX() + node1
.getWidth() / 2 - x
);
477 node2
= getLifeline(index
- 1);
478 dist2
= Math
.abs(node2
.getX() + node2
.getWidth() / 2 - x
);
480 if (index
< getLifelines().size() - 1) {
481 node3
= getLifeline(index
+ 1);
482 dist3
= Math
.abs(node3
.getX() + node3
.getWidth() / 2 - x
);
484 if (dist1
<= dist2
&& dist1
<= dist3
) {
486 } else if (dist2
<= dist1
&& dist2
<= dist3
) {
493 * Re-orders the given list of lifelines.
495 * @param list A list of lifelines to reorder.
497 public void reorder(List
<?
> list
) {
498 for (int i
= 0; i
< list
.size(); i
++) {
499 if (list
.get(i
) instanceof Lifeline
[]) {
500 Lifeline temp
[] = (Lifeline
[]) list
.get(i
);
501 if (temp
.length
== 2) {
502 if (temp
[1] == null) {
503 insertLifelineAfter(temp
[0], getLifeline(lifeLinesCount() - 1));
505 insertLifelineBefore(temp
[0], temp
[1]);
513 * Resets the time compression information.
515 public void resetTimeCompression() {
516 fHighlightLifeline
= null;
517 this.fStartEvent
= 0;
519 fHighlightColor
= null;
524 * @see org.eclipse.linuxtools.tmf.ui.views.uml2sd.core.BasicFrame#computeMinMax()
527 protected void computeMinMax() {
528 List
<SDTimeEvent
> timeArray
= buildTimeArray();
529 if (timeArray
== null) {
532 for (int i
= 0; i
< timeArray
.size() - 1; i
++) {
533 SDTimeEvent m1
= (SDTimeEvent
) timeArray
.get(i
);
534 SDTimeEvent m2
= (SDTimeEvent
) timeArray
.get(i
+ 1);
535 if (SDViewPref
.getInstance().excludeExternalTime() && ((m1
.getGraphNode() instanceof BaseMessage
) && (m2
.getGraphNode() instanceof BaseMessage
))) {
536 BaseMessage mes1
= (BaseMessage
) m1
.getGraphNode();
537 BaseMessage mes2
= (BaseMessage
) m2
.getGraphNode();
538 if ((mes2
.fStartLifeline
== null) || (mes1
.fEndLifeline
== null)) {
543 updateMinMax(m1
, m2
);
548 * Find the two graph nodes that are closest to this date, one just earlier, second just later. If date is before
549 * any graph node, bounds[0] is null and bounds[1] is the earliest. If date is after any graph node, bounds[1] is
550 * null and bounds[0] is the latest.
552 * @param dateToFind date to be found
553 * @param bounds a two items array that will receive bounds if found
554 * @return true if both bounds not null
556 public boolean findDateBounds(ITmfTimestamp dateToFind
, ITimeRange bounds
[]) {
558 List
<SDTimeEvent
> timeArray
= buildTimeArray();
561 for (int i
= 0; i
< timeArray
.size(); i
++) {
562 SDTimeEvent m
= (SDTimeEvent
) timeArray
.get(i
);
563 if (m
.getTime().compareTo(dateToFind
, true) > 0) {
564 bounds
[1] = m
.getGraphNode();
566 bounds
[0] = ((SDTimeEvent
) timeArray
.get(i
- 1)).getGraphNode();
572 bounds
[0] = ((SDTimeEvent
) timeArray
.get(timeArray
.size() - 1)).getGraphNode();
578 * Set whether time information is available or not
580 * @param value <code>true</code> for has time information else <code>false</code>
582 protected void setHasTimeInfo(boolean value
) {
583 fHasTimeInfo
= value
;
587 * Returns whether frame has time info or not.
589 * @return <code>true</code> whether frame has time info else <code>false</code>
591 public boolean hasTimeInfo() {
596 * Highlights the time compression.
598 * @param lifeline A lifeline to highlight
599 * @param startEvent A start event number
600 * @param nbEvent A number of events
601 * @param color A color for highlighting
603 public void highlightTimeCompression(Lifeline lifeline
, int startEvent
, int nbEvent
, IColor color
) {
604 fHighlightLifeline
= lifeline
;
605 this.fStartEvent
= startEvent
;
606 this.fNbEvent
= nbEvent
;
607 fHighlightColor
= color
;
611 * Set the lifeline categories which will be use during the lifelines creation
613 * @see Lifeline#setCategory(int)
614 * @param categories the lifeline categories array
616 public void setLifelineCategories(LifelineCategories
[] categories
) {
617 fLifelineCategories
= Arrays
.copyOf(categories
, categories
.length
);
621 * Returns the lifeline categories array set for the this frame
623 * @return the lifeline categories array or null if not set
625 public LifelineCategories
[] getLifelineCategories() {
626 return Arrays
.copyOf(fLifelineCategories
, fLifelineCategories
.length
);
630 * Adds a message to the Frame message list. Four kinds of syncMessages can be added:<br>
631 * - synchronous syncMessages<br>
632 * - synchronous syncMessages return<br>
633 * - asynchronous syncMessages<br>
634 * - asynchronous syncMessages return<br>
635 * For drawing performance reason, it is recommended to add synchronous syncMessages in the same order they should
636 * appear along the Y axis in the Frame.
638 * @param message the message to add
640 public void addMessage(BaseMessage message
) {
646 * @see org.eclipse.linuxtools.tmf.ui.views.uml2sd.core.BasicFrame#draw(org.eclipse.linuxtools.tmf.ui.views.uml2sd.drawings.IGC)
649 public void draw(IGC context
) {
655 if (fHighlightLifeline
!= null) {
656 IColor backupColor
= context
.getBackground();
657 context
.setBackground(Frame
.getUserPref().getTimeCompressionSelectionColor());
658 int gy
= fHighlightLifeline
.getY() + fHighlightLifeline
.getHeight() + (Metrics
.getMessageFontHeigth() + Metrics
.getMessagesSpacing()) * fStartEvent
;
659 context
.fillRectangle(Metrics
.FRAME_H_MARGIN
+ 1, gy
, fHighlightLifeline
.getX() + Metrics
.getLifelineWidth() / 2 - Metrics
.FRAME_H_MARGIN
, (Metrics
.getMessageFontHeigth() + Metrics
.getMessagesSpacing()) * fNbEvent
);
660 context
.setBackground(backupColor
);
662 super.draw(context
, false);
663 int lifelineArryStep
= 1;
664 if (Metrics
.swimmingLaneWidth() * context
.getZoom() < Metrics
.LIFELINE_SIGNIFICANT_HSPACING
) {
665 lifelineArryStep
= Math
.round(Metrics
.LIFELINE_SIGNIFICANT_HSPACING
/ (Metrics
.swimmingLaneWidth() * context
.getZoom()));
667 if (fIndexes
.size() == 0) {
670 int lifeLineDrawIndex
= ((Integer
) fIndexes
.get(Lifeline
.LIFELINE_TAG
)).intValue();
671 for (int i
= lifeLineDrawIndex
; i
< ((List
<GraphNode
>) fNodes
.get(Lifeline
.LIFELINE_TAG
)).size(); i
= i
+ lifelineArryStep
) {
672 Lifeline toDraw
= (Lifeline
) ((List
<GraphNode
>) fNodes
.get(Lifeline
.LIFELINE_TAG
)).get(i
);
673 if (toDraw
.getX() - Metrics
.LIFELINE_SPACING
/ 2 > context
.getContentsX() + context
.getVisibleWidth()) {
676 toDraw
.drawName(context
);
678 if (fHighlightLifeline
!= null) {
679 if (toDraw
== fHighlightLifeline
) {
680 toDraw
.highlightExecOccurrenceRegion(context
, fStartEvent
, fNbEvent
, fHighlightColor
);
681 } else if ((toDraw
.getIndex() < fHighlightLifeline
.getIndex()) || ((toDraw
.getIndex() < fHighlightLifeline
.getIndex()))) {
683 int acIndex
= toDraw
.getExecOccurrenceDrawIndex();
684 // acIndex = first visible execution occurrence
685 // for drawing speed reason with only search on the visible subset
686 if (toDraw
.getExecutions() != null) {
687 for (int index
= acIndex
; index
< toDraw
.getExecutions().size(); index
++) {
688 BasicExecutionOccurrence exec
= (BasicExecutionOccurrence
) toDraw
.getExecutions().get(index
);
689 int tempEvent
= fStartEvent
;
690 for (int j
= 0; j
< fNbEvent
; j
++) {
691 if (((tempEvent
>= exec
.fStartEventOccurrence
) && (tempEvent
<= exec
.fEndEventOccurrence
) && (tempEvent
+ 1 >= exec
.fStartEventOccurrence
) && (tempEvent
+ 1 <= exec
.fEndEventOccurrence
))) {
692 toDraw
.highlightExecOccurrenceRegion(context
, tempEvent
, 1, Frame
.getUserPref().getTimeCompressionSelectionColor());
694 tempEvent
= tempEvent
+ 1;
696 // if we are outside the visible area we stop right now
697 // This works because execution occurrences are ordered along the Y axis
698 if (exec
.getY() > getY()) {
710 * @see org.eclipse.linuxtools.tmf.ui.views.uml2sd.core.BasicFrame#buildTimeArray()
713 protected List
<SDTimeEvent
> buildTimeArray() {
718 List
<SDTimeEvent
> timeArray
= super.buildTimeArray();
719 fExecutionOccurrencesWithTime
= null;
720 if (getLifelines() != null) {
721 for (int i
= 0; i
< ((List
<GraphNode
>) fNodes
.get(Lifeline
.LIFELINE_TAG
)).size(); i
++) {
722 Lifeline l
= (Lifeline
) ((List
<GraphNode
>) fNodes
.get(Lifeline
.LIFELINE_TAG
)).get(i
);
723 if (l
.hasTimeInfo() && l
.getExecutions() != null) {
724 for (Iterator
<GraphNode
> j
= l
.getExecutions().iterator(); j
.hasNext();) {
725 GraphNode o
= j
.next();
726 if (o
instanceof ExecutionOccurrence
) {
727 ExecutionOccurrence eo
= (ExecutionOccurrence
) o
;
728 if (eo
.hasTimeInfo()) {
729 int event
= eo
.getStartOccurrence();
730 ITmfTimestamp time
= eo
.getStartTime();
731 SDTimeEvent f
= new SDTimeEvent(time
, event
, eo
);
733 if (fExecutionOccurrencesWithTime
== null) {
734 fExecutionOccurrencesWithTime
= new ArrayList
<SDTimeEvent
>();
736 fExecutionOccurrencesWithTime
.add(f
);
737 event
= eo
.getEndOccurrence();
738 time
= eo
.getEndTime();
739 f
= new SDTimeEvent(time
, event
, eo
);
741 fExecutionOccurrencesWithTime
.add(f
);
749 if (fExecutionOccurrencesWithTime
!= null) {
750 SDTimeEvent
[] temp
= fExecutionOccurrencesWithTime
.toArray(new SDTimeEvent
[fExecutionOccurrencesWithTime
.size()]);
751 Arrays
.sort(temp
, new TimeEventComparator());
752 fExecutionOccurrencesWithTime
= Arrays
.asList(temp
);
754 SDTimeEvent
[] temp
= timeArray
.toArray(new SDTimeEvent
[timeArray
.size()]);
755 Arrays
.sort(temp
, new TimeEventComparator());
756 timeArray
= Arrays
.asList(temp
);
758 } catch (Exception e
) {
759 TmfUiPlugin
.getDefault().getLog().log(new Status(IStatus
.ERROR
, TmfUiPlugin
.PLUGIN_ID
, "Error building time array", e
)); //$NON-NLS-1$
766 * Get the closer leaving message.
768 * @param lifeline A lifeline reference
769 * @param message A message reference
770 * @param list A list of graph nodes
771 * @param smallerEvent A smaller event flag
772 * @return the closer leaving message.
774 protected GraphNode
getCloserLeavingMessage(Lifeline lifeline
, BaseMessage message
, List
<GraphNode
> list
, boolean smallerEvent
) {
779 if (smallerEvent
== false) {
781 if (message
!= null) {
782 event
= message
.getEventOccurrence();
784 for (int i
= 0; i
< list
.size(); i
++) {
785 GraphNode node
= (GraphNode
) list
.get(i
);
786 if (node
instanceof SyncMessage
) {
787 SyncMessage syncNode
= (SyncMessage
) node
;
788 if ((syncNode
.getEventOccurrence() > event
) && (syncNode
.getStartLifeline() == lifeline
) && !syncNode
.isSameAs(message
)) {
791 } else if (node
instanceof AsyncMessage
) {
792 AsyncMessage asyncNode
= (AsyncMessage
) node
;
793 if ((asyncNode
.getStartOccurrence() > event
) && (asyncNode
.getStartLifeline() == lifeline
) && !asyncNode
.isSameAs(message
)) {
799 int event
= getMaxEventOccurrence();
800 if (message
!= null) {
801 if (message
instanceof AsyncMessage
) {
802 event
= ((AsyncMessage
) message
).getStartOccurrence();
804 event
= message
.getEventOccurrence();
807 for (int i
= list
.size() - 1; i
>= 0; i
--) {
808 GraphNode node
= (GraphNode
) list
.get(i
);
809 if (node
instanceof SyncMessage
) {
810 SyncMessage syncNode
= (SyncMessage
) node
;
811 if ((syncNode
.getEventOccurrence() < event
) && (syncNode
.getStartLifeline() == lifeline
) && !syncNode
.isSameAs(message
)) {
814 } else if (node
instanceof AsyncMessage
) {
815 AsyncMessage asyncNode
= (AsyncMessage
) node
;
816 if ((asyncNode
.getStartOccurrence() < event
) && (asyncNode
.getStartLifeline() == lifeline
) && !asyncNode
.isSameAs(message
)) {
827 * Get the closer entering message.
829 * @param lifeline A lifeline reference
830 * @param message A message reference
831 * @param list A list of graph nodes
832 * @param smallerEvent A smaller event flag
833 * @return the closer entering message.
835 protected GraphNode
getCloserEnteringMessage(Lifeline lifeline
, BaseMessage message
, List
<GraphNode
> list
, boolean smallerEvent
) {
841 if (message
!= null) {
842 event
= message
.getEventOccurrence();
844 for (int i
= 0; i
< list
.size(); i
++) {
845 GraphNode node
= (GraphNode
) list
.get(i
);
846 if (node
instanceof SyncMessage
) {
847 SyncMessage syncNode
= (SyncMessage
) node
;
848 if ((syncNode
.getEventOccurrence() > event
) && (syncNode
.getEndLifeline() == lifeline
) && !syncNode
.isSameAs(message
)) {
851 } else if (node
instanceof AsyncMessage
) {
852 AsyncMessage asyncNode
= (AsyncMessage
) node
;
853 if ((asyncNode
.getStartOccurrence() > event
) && (asyncNode
.getEndLifeline() == lifeline
) && !asyncNode
.isSameAs(message
)) {
859 int event
= getMaxEventOccurrence();
861 if (message
instanceof AsyncMessage
) {
862 event
= ((AsyncMessage
) message
).getStartOccurrence();
864 event
= message
.getEventOccurrence();
866 for (int i
= list
.size() - 1; i
>= 0; i
--) {
867 GraphNode node
= (GraphNode
) list
.get(i
);
868 if (node
instanceof SyncMessage
) {
869 SyncMessage syncNode
= (SyncMessage
) node
;
870 if ((syncNode
.getEventOccurrence() < event
) && (syncNode
.getEndLifeline() == lifeline
) && !syncNode
.isSameAs(message
)) {
873 } else if (node
instanceof AsyncMessage
) {
874 AsyncMessage asyncNode
= (AsyncMessage
) node
;
875 if ((asyncNode
.getStartOccurrence() < event
) && (asyncNode
.getEndLifeline() == lifeline
) && !asyncNode
.isSameAs(message
)) {
885 * Get distance of given event from given graph node.
887 * @param node A graph node reference.
888 * @param event A event number to check.
889 * @return distance of event from graph node.
891 protected int distanceFromEvent(GraphNode node
, int event
) {
893 if (node
instanceof SyncMessage
) {
894 distance
= ((SyncMessage
) node
).getEventOccurrence() - event
;
895 } else if (node
instanceof AsyncMessage
) {
896 int start
= ((AsyncMessage
) node
).getStartOccurrence();
897 int end
= ((AsyncMessage
) node
).getEndOccurrence();
898 if ((start
- event
) < (end
- event
)) {
899 distance
= start
- event
;
901 distance
= end
- event
;
904 return Math
.abs(distance
);
908 * Get node from 2 given nodes that is close to event.
910 * @param node1 A first graph node
911 * @param node2 A second graph node
912 * @param event A event to check.
913 * @return graph node that is closer or <code>null</code>
915 protected GraphNode
getCloserToEvent(GraphNode node1
, GraphNode node2
, int event
) {
916 if ((node1
!= null) && (node2
!= null)) {
917 if (distanceFromEvent(node1
, event
) < distanceFromEvent(node2
, event
)) {
922 } else if (node1
!= null) {
924 } else if (node2
!= null) {
931 * Get called message based on given start message.
933 * @param startMessage A start message to check.
934 * @return called message (graph node) or <code>null</code>
936 public GraphNode
getCalledMessage(BaseMessage startMessage
) {
938 GraphNode result
= null;
939 Lifeline lifeline
= null;
940 if (startMessage
!= null) {
941 event
= ((BaseMessage
) startMessage
).getEventOccurrence();
942 lifeline
= ((BaseMessage
) startMessage
).getEndLifeline();
943 if (lifeline
== null) {
944 lifeline
= ((BaseMessage
) startMessage
).getStartLifeline();
947 if (lifeline
== null) {
950 GraphNode message
= getCloserLeavingMessage(lifeline
, startMessage
, getSyncMessages(), false);
951 GraphNode messageReturn
= getCloserLeavingMessage(lifeline
, startMessage
, getSyncMessagesReturn(), false);
952 result
= getCloserToEvent(message
, messageReturn
, event
);
953 message
= getCloserLeavingMessage(lifeline
, startMessage
, getAsyncMessages(), false);
954 result
= getCloserToEvent(result
, message
, event
);
955 messageReturn
= getCloserLeavingMessage(lifeline
, startMessage
, getAsyncMessagesReturn(), false);
956 result
= getCloserToEvent(result
, messageReturn
, event
);
961 * Get caller message based on given start message.
963 * @param startMessage A start message to check.
964 * @return called message (graph node) or <code>null</code>
966 public GraphNode
getCallerMessage(BaseMessage startMessage
) {
967 int event
= getMaxEventOccurrence();
968 GraphNode result
= null;
969 Lifeline lifeline
= null;
970 if (startMessage
!= null) {
971 event
= ((BaseMessage
) startMessage
).getEventOccurrence();
972 lifeline
= ((BaseMessage
) startMessage
).getStartLifeline();
973 if (lifeline
== null) {
974 lifeline
= ((BaseMessage
) startMessage
).getEndLifeline();
977 if (lifeline
== null) {
980 GraphNode message
= getCloserEnteringMessage(lifeline
, startMessage
, getSyncMessages(), true);
981 GraphNode messageReturn
= getCloserEnteringMessage(lifeline
, startMessage
, getSyncMessagesReturn(), true);
982 result
= getCloserToEvent(message
, messageReturn
, event
);
983 message
= getCloserEnteringMessage(lifeline
, startMessage
, getAsyncMessages(), true);
984 result
= getCloserToEvent(result
, message
, event
);
985 messageReturn
= getCloserEnteringMessage(lifeline
, startMessage
, getAsyncMessagesReturn(), true);
986 result
= getCloserToEvent(result
, messageReturn
, event
);
991 * Get next lifeline based on given message.
993 * @param lifeline A lifeline reference
994 * @param startMessage A start message to check
995 * @return next lifeline or <code>null</code>
997 public GraphNode
getNextLifelineMessage(Lifeline lifeline
, BaseMessage startMessage
) {
999 if (startMessage
!= null) {
1000 event
= ((BaseMessage
) startMessage
).getEventOccurrence();
1002 if (lifeline
== null) {
1005 GraphNode message
= getCloserLeavingMessage(lifeline
, startMessage
, getSyncMessages(), false);
1006 GraphNode messageReturn
= getCloserLeavingMessage(lifeline
, startMessage
, getSyncMessagesReturn(), false);
1007 GraphNode result
= getCloserToEvent(message
, messageReturn
, event
);
1008 message
= getCloserLeavingMessage(lifeline
, startMessage
, getAsyncMessages(), false);
1009 result
= getCloserToEvent(result
, message
, event
);
1010 messageReturn
= getCloserLeavingMessage(lifeline
, startMessage
, getAsyncMessagesReturn(), false);
1011 result
= getCloserToEvent(result
, messageReturn
, event
);
1016 * Get previous lifeline based on given message.
1018 * @param lifeline A lifeline reference
1019 * @param startMessage A start message to check.
1020 * @return previous lifeline or <code>null</code>
1022 public GraphNode
getPrevLifelineMessage(Lifeline lifeline
, BaseMessage startMessage
) {
1023 int event
= getMaxEventOccurrence();
1024 if (startMessage
!= null)
1025 if (startMessage
instanceof AsyncMessage
) {
1026 event
= ((AsyncMessage
) startMessage
).getStartOccurrence();
1028 event
= startMessage
.getEventOccurrence();
1030 if (lifeline
== null) {
1033 GraphNode message
= getCloserLeavingMessage(lifeline
, startMessage
, getSyncMessages(), true);
1034 GraphNode messageReturn
= getCloserLeavingMessage(lifeline
, startMessage
, getSyncMessagesReturn(), true);
1035 GraphNode result
= getCloserToEvent(message
, messageReturn
, event
);
1036 message
= getCloserLeavingMessage(lifeline
, startMessage
, getAsyncMessages(), true);
1037 result
= getCloserToEvent(result
, message
, event
);
1038 messageReturn
= getCloserLeavingMessage(lifeline
, startMessage
, getAsyncMessagesReturn(), true);
1039 result
= getCloserToEvent(result
, messageReturn
, event
);
1044 * Get the first execution occurrence.
1046 * @param lifeline A lifeline reference
1047 * @return the first execution occurrence of lifeline or <code>null</code>.
1049 public BasicExecutionOccurrence
getFirstExecution(Lifeline lifeline
) {
1050 if (lifeline
== null) {
1053 List
<GraphNode
> list
= lifeline
.getExecutions();
1055 if ((list
== null) || (list
.isEmpty())) {
1059 BasicExecutionOccurrence result
= (BasicExecutionOccurrence
) list
.get(0);
1060 for (int i
= 0; i
< list
.size(); i
++) {
1061 BasicExecutionOccurrence e
= (BasicExecutionOccurrence
) list
.get(i
);
1062 if ((e
.getStartOccurrence() < result
.getEndOccurrence())) {
1070 * Get the previous execution occurrence relative to a given execution occurrence.
1072 * @param exec A execution occurrence reference.
1073 * @return the previous execution occurrence of lifeline or <code>null</code>.
1075 public BasicExecutionOccurrence
getPrevExecOccurrence(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
.fStartEventOccurrence
) && (result
== null)) {
1093 if ((e
.getStartOccurrence() < exec
.fStartEventOccurrence
) && (e
.getStartOccurrence() >= result
.getEndOccurrence())) {
1101 * Get the next execution occurrence relative to a given execution occurrence.
1103 * @param exec A execution occurrence reference.
1104 * @return the next execution occurrence of lifeline or <code>null</code>.
1106 public BasicExecutionOccurrence
getNextExecOccurrence(BasicExecutionOccurrence exec
) {
1110 Lifeline lifeline
= exec
.getLifeline();
1111 if (lifeline
== null) {
1114 List
<GraphNode
> list
= lifeline
.getExecutions();
1118 BasicExecutionOccurrence result
= null;
1119 for (int i
= 0; i
< list
.size(); i
++) {
1120 BasicExecutionOccurrence e
= (BasicExecutionOccurrence
) list
.get(i
);
1121 if ((e
.getStartOccurrence() > exec
.fStartEventOccurrence
) && (result
== null)) {
1124 if ((e
.getStartOccurrence() > exec
.fStartEventOccurrence
) && (e
.getStartOccurrence() <= result
.getEndOccurrence())) {
1132 * Get the last execution occurrence.
1134 * @param lifeline A lifeline reference.
1135 * @return the last execution occurrence of lifeline or <code>null</code>.
1137 public BasicExecutionOccurrence
getLastExecOccurrence(Lifeline lifeline
) {
1138 if (lifeline
== null) {
1141 List
<GraphNode
> list
= lifeline
.getExecutions();
1145 BasicExecutionOccurrence result
= null;
1146 for (int i
= 0; i
< list
.size(); i
++) {
1147 BasicExecutionOccurrence e
= (BasicExecutionOccurrence
) list
.get(i
);
1148 if (result
== null) {
1151 if (e
.getStartOccurrence() > result
.getEndOccurrence()) {