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 fHighlightLifeline = null;
50
* The value of the start event.
52
protected int fStartEvent = 0;
54
* The nubmer of events in the frame.
56
protected int fNbEvent = 0;
58
* The color for highlighting.
60
protected IColor fHighlightColor = null;
62
* The list of time events of the corresponding execution occurrences.
64
protected List<SDTimeEvent> fExecutionOccurrencesWithTime;
66
* The Array of lifeline categories.
68
protected LifelineCategories[] fLifelineCategories = 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>) fNodes.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>) fNodes.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>) fNodes.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>) fNodes.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>) fNodes.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
fComputeMinMax = 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 (fIndexes.get(Lifeline.LIFELINE_TAG) != null) {
297
return ((Integer) fIndexes.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 (fIndexes.get(SyncMessage.SYNC_MESS_TAG) != null) {
311
return ((Integer) fIndexes.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 (fIndexes.get(SyncMessageReturn.SYNC_MESS_RET_TAG) != null) {
325
return ((Integer) fIndexes.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 (fIndexes.get(AsyncMessage.ASYNC_MESS_TAG) != null) {
339
return ((Integer) fIndexes.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 (fIndexes.get(AsyncMessageReturn.ASYNC_MESS_RET_TAG) != null) {
353
return ((Integer) fIndexes.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 fExecutionOccurrencesWithTime;
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(List<?> 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
fHighlightLifeline = null;
514
this.fStartEvent = 0;
516
fHighlightColor = 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) || timeArray.isEmpty()) {
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() && ((m1.getGraphNode() instanceof BaseMessage) && (m2.getGraphNode() instanceof BaseMessage))) {
533
BaseMessage mes1 = (BaseMessage) m1.getGraphNode();
534
BaseMessage mes2 = (BaseMessage) m2.getGraphNode();
535
if ((mes2.fStartLifeline == null) || (mes1.fEndLifeline == null)) {
540
updateMinMax(m1, m2);
545
* Find the two graph nodes that are closest to this date, one just earlier, second just later. If date is before
546
* any graph node, bounds[0] is null and bounds[1] is the earliest. If date is after any graph node, bounds[1] is
547
* null and bounds[0] is the latest.
549
* @param dateToFind date to be found
550
* @param bounds a two items array that will receive bounds if found
551
* @return true if both bounds not null
553
public boolean findDateBounds(ITmfTimestamp dateToFind, ITimeRange bounds[]) {
555
List<SDTimeEvent> timeArray = buildTimeArray();
557
if ((timeArray == null) || timeArray.isEmpty()) {
563
for (int i = 0; i < timeArray.size(); i++) {
564
SDTimeEvent m = (SDTimeEvent) timeArray.get(i);
565
if (m.getTime().compareTo(dateToFind, true) > 0) {
566
bounds[1] = m.getGraphNode();
568
bounds[0] = ((SDTimeEvent) timeArray.get(i - 1)).getGraphNode();
574
bounds[0] = ((SDTimeEvent) timeArray.get(timeArray.size() - 1)).getGraphNode();
580
* Set whether time information is available or not
582
* @param value <code>true</code> for has time information else <code>false</code>
584
protected void setHasTimeInfo(boolean value) {
585
fHasTimeInfo = value;
589
* Returns whether frame has time info or not.
591
* @return <code>true</code> whether frame has time info else <code>false</code>
593
public boolean hasTimeInfo() {
598
* Highlights the time compression.
600
* @param lifeline A lifeline to highlight
601
* @param startEvent A start event number
602
* @param nbEvent A number of events
603
* @param color A color for highlighting
605
public void highlightTimeCompression(Lifeline lifeline, int startEvent, int nbEvent, IColor color) {
606
fHighlightLifeline = lifeline;
607
this.fStartEvent = startEvent;
608
this.fNbEvent = nbEvent;
609
fHighlightColor = color;
613
* Set the lifeline categories which will be use during the lifelines creation
615
* @see Lifeline#setCategory(int)
616
* @param categories the lifeline categories array
618
public void setLifelineCategories(LifelineCategories[] categories) {
619
fLifelineCategories = Arrays.copyOf(categories, categories.length);
623
* Returns the lifeline categories array set for the this frame
625
* @return the lifeline categories array or null if not set
627
public LifelineCategories[] getLifelineCategories() {
628
return Arrays.copyOf(fLifelineCategories, fLifelineCategories.length);
632
* Adds a message to the Frame message list. Four kinds of syncMessages can be added:<br>
633
* - synchronous syncMessages<br>
634
* - synchronous syncMessages return<br>
635
* - asynchronous syncMessages<br>
636
* - asynchronous syncMessages return<br>
637
* For drawing performance reason, it is recommended to add synchronous syncMessages in the same order they should
638
* appear along the Y axis in the Frame.
640
* @param message the message to add
642
public void addMessage(BaseMessage message) {
648
* @see org.eclipse.linuxtools.tmf.ui.views.uml2sd.core.BasicFrame#draw(org.eclipse.linuxtools.tmf.ui.views.uml2sd.drawings.IGC)
651
public void draw(IGC context) {
657
if (fHighlightLifeline != null) {
658
IColor backupColor = context.getBackground();
659
context.setBackground(SDViewPref.getInstance().getTimeCompressionSelectionColor());
660
int gy = fHighlightLifeline.getY() + fHighlightLifeline.getHeight() + (Metrics.getMessageFontHeigth() + Metrics.getMessagesSpacing()) * fStartEvent;
661
context.fillRectangle(Metrics.FRAME_H_MARGIN + 1, gy, fHighlightLifeline.getX() + Metrics.getLifelineWidth() / 2 - Metrics.FRAME_H_MARGIN, (Metrics.getMessageFontHeigth() + Metrics.getMessagesSpacing()) * fNbEvent);
662
context.setBackground(backupColor);
664
super.draw(context, false);
665
int lifelineArryStep = 1;
666
if (Metrics.swimmingLaneWidth() * context.getZoom() < Metrics.LIFELINE_SIGNIFICANT_HSPACING) {
667
lifelineArryStep = Math.round(Metrics.LIFELINE_SIGNIFICANT_HSPACING / (Metrics.swimmingLaneWidth() * context.getZoom()));
669
if (fIndexes.size() == 0) {
672
int lifeLineDrawIndex = ((Integer) fIndexes.get(Lifeline.LIFELINE_TAG)).intValue();
673
for (int i = lifeLineDrawIndex; i < ((List<GraphNode>) fNodes.get(Lifeline.LIFELINE_TAG)).size(); i = i + lifelineArryStep) {
674
Lifeline toDraw = (Lifeline) ((List<GraphNode>) fNodes.get(Lifeline.LIFELINE_TAG)).get(i);
675
if (toDraw.getX() - Metrics.LIFELINE_SPACING / 2 > context.getContentsX() + context.getVisibleWidth()) {
678
toDraw.drawName(context);
680
if (fHighlightLifeline != null) {
681
if (toDraw == fHighlightLifeline) {
682
toDraw.highlightExecOccurrenceRegion(context, fStartEvent, fNbEvent, fHighlightColor);
683
} else if ((toDraw.getIndex() < fHighlightLifeline.getIndex()) || ((toDraw.getIndex() < fHighlightLifeline.getIndex()))) {
685
int acIndex = toDraw.getExecOccurrenceDrawIndex();
686
// acIndex = first visible execution occurrence
687
// for drawing speed reason with only search on the visible subset
688
if (toDraw.getExecutions() != null) {
689
for (int index = acIndex; index < toDraw.getExecutions().size(); index++) {
690
BasicExecutionOccurrence exec = (BasicExecutionOccurrence) toDraw.getExecutions().get(index);
691
int tempEvent = fStartEvent;
692
for (int j = 0; j < fNbEvent; j++) {
693
if (((tempEvent >= exec.fStartEventOccurrence) && (tempEvent <= exec.fEndEventOccurrence) && (tempEvent + 1 >= exec.fStartEventOccurrence) && (tempEvent + 1 <= exec.fEndEventOccurrence))) {
694
toDraw.highlightExecOccurrenceRegion(context, tempEvent, 1, SDViewPref.getInstance().getTimeCompressionSelectionColor());
696
tempEvent = tempEvent + 1;
698
// if we are outside the visible area we stop right now
699
// This works because execution occurrences are ordered along the Y axis
700
if (exec.getY() > getY()) {
712
* @see org.eclipse.linuxtools.tmf.ui.views.uml2sd.core.BasicFrame#buildTimeArray()
715
protected List<SDTimeEvent> buildTimeArray() {
718
return new ArrayList<SDTimeEvent>();
721
List<SDTimeEvent> timeArray = super.buildTimeArray();
722
fExecutionOccurrencesWithTime = null;
723
if (getLifelines() != null) {
724
for (int i = 0; i < ((List<GraphNode>) fNodes.get(Lifeline.LIFELINE_TAG)).size(); i++) {
725
Lifeline lifeline = (Lifeline) ((List<GraphNode>) fNodes.get(Lifeline.LIFELINE_TAG)).get(i);
726
if (lifeline.hasTimeInfo() && lifeline.getExecutions() != null) {
727
for (Iterator<GraphNode> j = lifeline.getExecutions().iterator(); j.hasNext();) {
728
GraphNode o = j.next();
729
if (o instanceof ExecutionOccurrence) {
730
ExecutionOccurrence eo = (ExecutionOccurrence) o;
731
if (eo.hasTimeInfo()) {
732
int event = eo.getStartOccurrence();
733
ITmfTimestamp time = eo.getStartTime();
734
SDTimeEvent f = new SDTimeEvent(time, event, eo);
736
if (fExecutionOccurrencesWithTime == null) {
737
fExecutionOccurrencesWithTime = new ArrayList<SDTimeEvent>();
739
fExecutionOccurrencesWithTime.add(f);
740
event = eo.getEndOccurrence();
741
time = eo.getEndTime();
742
f = new SDTimeEvent(time, event, eo);
744
fExecutionOccurrencesWithTime.add(f);
752
if (fExecutionOccurrencesWithTime != null) {
753
SDTimeEvent[] temp = fExecutionOccurrencesWithTime.toArray(new SDTimeEvent[fExecutionOccurrencesWithTime.size()]);
754
Arrays.sort(temp, new TimeEventComparator());
755
fExecutionOccurrencesWithTime = Arrays.asList(temp);
757
SDTimeEvent[] temp = timeArray.toArray(new SDTimeEvent[timeArray.size()]);
758
Arrays.sort(temp, new TimeEventComparator());
759
timeArray = Arrays.asList(temp);
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) {
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) {
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();
1053
if ((list == null) || (list.isEmpty())) {
1057
BasicExecutionOccurrence result = (BasicExecutionOccurrence) list.get(0);
1058
for (int i = 0; i < list.size(); i++) {
1059
BasicExecutionOccurrence e = (BasicExecutionOccurrence) list.get(i);
1060
if ((e.getStartOccurrence() < result.getEndOccurrence())) {
1068
* Get the previous execution occurrence relative to a given execution occurrence.
1070
* @param exec A execution occurrence reference.
1071
* @return the previous execution occurrence of lifeline or <code>null</code>.
1073
public BasicExecutionOccurrence getPrevExecOccurrence(BasicExecutionOccurrence exec) {
1077
Lifeline lifeline = exec.getLifeline();
1078
if (lifeline == null) {
1081
List<GraphNode> list = lifeline.getExecutions();
1085
BasicExecutionOccurrence result = null;
1086
for (int i = 0; i < list.size(); i++) {
1087
BasicExecutionOccurrence e = (BasicExecutionOccurrence) list.get(i);
1088
if ((e.getStartOccurrence() < exec.fStartEventOccurrence) && (result == null)) {
1091
if ((e.getStartOccurrence() < exec.fStartEventOccurrence) && (e.getStartOccurrence() >= result.getEndOccurrence())) {
1099
* Get the next execution occurrence relative to a given execution occurrence.
1101
* @param exec A execution occurrence reference.
1102
* @return the next execution occurrence of lifeline or <code>null</code>.
1104
public BasicExecutionOccurrence getNextExecOccurrence(BasicExecutionOccurrence exec) {
1108
Lifeline lifeline = exec.getLifeline();
1109
if (lifeline == null) {
1112
List<GraphNode> list = lifeline.getExecutions();
1116
BasicExecutionOccurrence result = null;
1117
for (int i = 0; i < list.size(); i++) {
1118
BasicExecutionOccurrence e = (BasicExecutionOccurrence) list.get(i);
1119
if ((e.getStartOccurrence() > exec.fStartEventOccurrence) && (result == null)) {
1122
if ((e.getStartOccurrence() > exec.fStartEventOccurrence) && (e.getStartOccurrence() <= result.getEndOccurrence())) {
1130
* Get the last execution occurrence.
1132
* @param lifeline A lifeline reference.
1133
* @return the last execution occurrence of lifeline or <code>null</code>.
1135
public BasicExecutionOccurrence getLastExecOccurrence(Lifeline lifeline) {
1136
if (lifeline == null) {
1139
List<GraphNode> list = lifeline.getExecutions();
1143
BasicExecutionOccurrence result = null;
1144
for (int i = 0; i < list.size(); i++) {
1145
BasicExecutionOccurrence e = (BasicExecutionOccurrence) list.get(i);
1146
if (result == null) {
1149
if (e.getStartOccurrence() > result.getEndOccurrence()) {