~ubuntu-branches/ubuntu/trusty/eclipse-linuxtools/trusty

« back to all changes in this revision

Viewing changes to lttng/org.eclipse.linuxtools.tmf.ui/src/org/eclipse/linuxtools/tmf/ui/views/uml2sd/core/Frame.java

  • Committer: Package Import Robot
  • Author(s): Jakub Adam
  • Date: 2012-06-29 12:07:30 UTC
  • Revision ID: package-import@ubuntu.com-20120629120730-bfri1xys1i71dpn6
Tags: upstream-1.0.0
ImportĀ upstreamĀ versionĀ 1.0.0

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/**********************************************************************
 
2
 * Copyright (c) 2005, 2008 IBM Corporation and others.
 
3
 * Copyright (c) 2011, 2012 Ericsson.
 
4
 * 
 
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
 
9
 * 
 
10
 * Contributors: 
 
11
 * IBM - Initial API and implementation
 
12
 * Bernd Hufmann - Updated for TMF
 
13
 **********************************************************************/
 
14
package org.eclipse.linuxtools.tmf.ui.views.uml2sd.core;
 
15
 
 
16
import java.util.ArrayList;
 
17
import java.util.Arrays;
 
18
import java.util.Iterator;
 
19
import java.util.List;
 
20
 
 
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;
 
26
 
 
27
/**
 
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.
 
32
 * 
 
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>
 
35
 * 
 
36
 * @see org.eclipse.linuxtools.tmf.ui.views.uml2sd.core.Lifeline Lifeline for more event occurence details
 
37
 * @author sveyrier
 
38
 * @version 1.0
 
39
 */
 
40
public class Frame extends BasicFrame {
 
41
 
 
42
    // ------------------------------------------------------------------------
 
43
    // Attributes
 
44
    // ------------------------------------------------------------------------
 
45
    /**
 
46
     * The lifeline that is current highlighted.
 
47
     */
 
48
    protected Lifeline fHighlightLifeline = null;
 
49
    /**
 
50
     * The value of the start event.
 
51
     */
 
52
    protected int fStartEvent = 0;
 
53
    /**
 
54
     * The nubmer of events in the frame.
 
55
     */
 
56
    protected int fNbEvent = 0;
 
57
    /**
 
58
     * The color for highlighting.
 
59
     */
 
60
    protected IColor fHighlightColor = null;
 
61
    /**
 
62
     * The list of time events of the corresponding execution occurrences.
 
63
     */
 
64
    protected List<SDTimeEvent> fExecutionOccurrencesWithTime;
 
65
    /**
 
66
     * The Array of lifeline categories.
 
67
     */
 
68
    protected LifelineCategories[] fLifelineCategories = null;
 
69
 
 
70
    // ------------------------------------------------------------------------
 
71
    // Methods
 
72
    // ------------------------------------------------------------------------
 
73
 
 
74
    /**
 
75
     * Returns a list of all lifelines known by this frame. Known lifelines are the only one which can be displayed on
 
76
     * screen.
 
77
     * 
 
78
     * @return the lifelines list
 
79
     */
 
80
    protected List<GraphNode> getLifelines() {
 
81
        if (!fHasChilden) {
 
82
            return null;
 
83
        } 
 
84
        return (List<GraphNode>) fNodes.get(Lifeline.LIFELINE_TAG);
 
85
    }
 
86
 
 
87
    /**
 
88
     * Returns the number of lifelines stored in the frame
 
89
     * 
 
90
     * @return the number of lifelines
 
91
     */
 
92
    public int lifeLinesCount() {
 
93
        List<GraphNode> lifelines = getLifelines();
 
94
        if (lifelines != null) {
 
95
            return lifelines.size();
 
96
        }
 
97
        return 0;
 
98
    }
 
99
 
 
100
    /**
 
101
     * Returns the lifeline at the given index in the lifelines array
 
102
     * 
 
103
     * @param index the position in the lifeline array
 
104
     * @return the lifeline or <code>null</code>
 
105
     */
 
106
    public Lifeline getLifeline(int index) {
 
107
        if ((getLifelines() != null) && (index >= 0) && (index < lifeLinesCount())) {
 
108
            return (Lifeline) getLifelines().get(index);
 
109
        }
 
110
        return null;
 
111
    }
 
112
 
 
113
    /**
 
114
     * Returns a list of syncMessages known by this frame. Known syncMessages are the only on which can be displayed on
 
115
     * screen
 
116
     * 
 
117
     * @return the syncMessages list
 
118
     */
 
119
    protected List<GraphNode> getSyncMessages() {
 
120
        if (!fHasChilden) {
 
121
            return null;
 
122
        } 
 
123
        return (List<GraphNode>) fNodes.get(SyncMessage.SYNC_MESS_TAG);
 
124
    }
 
125
 
 
126
    /**
 
127
     * Returns the number of syncMessages stored in the frame
 
128
     * 
 
129
     * @return the number of syncMessage
 
130
     */
 
131
    public int syncMessageCount() {
 
132
        if (getSyncMessages() != null) {
 
133
            return getSyncMessages().size();
 
134
        } 
 
135
        return 0;
 
136
    }
 
137
 
 
138
    /**
 
139
     * Returns the syncMessage at the given index in the syncMessages array
 
140
     * 
 
141
     * @param index the position in the syncMessages array
 
142
     * @return the syncMessage or <code>null</code>
 
143
     */
 
144
    public SyncMessage getSyncMessage(int index) {
 
145
        if ((getSyncMessages() != null) && (index >= 0) && (index < getSyncMessages().size())) {
 
146
            return (SyncMessage) getSyncMessages().get(index);
 
147
        }
 
148
        return null;
 
149
    }
 
150
 
 
151
    /**
 
152
     * Returns a list of asyncMessages known by this frame. Known asyncMessages are the only on which can be displayed
 
153
     * on screen
 
154
     * 
 
155
     * @return the asyncMessages list or <code>null</code>
 
156
     */
 
157
    protected List<GraphNode> getAsyncMessages() {
 
158
        if (!fHasChilden) {
 
159
            return null;
 
160
        }
 
161
        return (List<GraphNode>) fNodes.get(AsyncMessage.ASYNC_MESS_TAG);
 
162
    }
 
163
 
 
164
    /**
 
165
     * Returns the number of asyncMessage stored in the frame
 
166
     * 
 
167
     * @return the number of asyncMessage
 
168
     */
 
169
    public int asyncMessageCount() {
 
170
        if (getAsyncMessages() != null) {
 
171
            return getAsyncMessages().size();
 
172
        }
 
173
        return 0;
 
174
    }
 
175
 
 
176
    /**
 
177
     * Returns the asyncMessage at the given index in the asyncMessage array
 
178
     * 
 
179
     * @param index the position in the asyncMessage array
 
180
     * @return the asyncMessage or <code>null</code>
 
181
     */
 
182
    public AsyncMessage getAsyncMessage(int index) {
 
183
        if ((getAsyncMessages() != null) && (index >= 0) && (index < getAsyncMessages().size())) {
 
184
            return (AsyncMessage) getAsyncMessages().get(index);
 
185
        }
 
186
        return null;
 
187
    }
 
188
 
 
189
    /**
 
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
 
192
     * 
 
193
     * @return the syncMessages return list or <code>null</code>
 
194
     */
 
195
    protected List<GraphNode> getSyncMessagesReturn() {
 
196
        if (!fHasChilden) {
 
197
            return null;
 
198
        }
 
199
        return (List<GraphNode>) fNodes.get(SyncMessageReturn.SYNC_MESS_RET_TAG);
 
200
    }
 
201
 
 
202
    /**
 
203
     * Returns the number of syncMessageReturn stored in the frame
 
204
     * 
 
205
     * @return the number of syncMessageReturn
 
206
     */
 
207
    public int syncMessageReturnCount() {
 
208
        if (getSyncMessagesReturn() != null) {
 
209
            return getSyncMessagesReturn().size();
 
210
        }
 
211
        return 0;
 
212
    }
 
213
 
 
214
    /**
 
215
     * Returns the syncMessageReturn at the given index in the syncMessageReturn array
 
216
     * 
 
217
     * @param index the position in the syncMessageReturn array
 
218
     * @return the syncMessageReturn or <code>null</code>
 
219
     */
 
220
    public SyncMessageReturn getSyncMessageReturn(int index) {
 
221
        if ((getSyncMessagesReturn() != null) && (index >= 0) && (index < getSyncMessagesReturn().size())) {
 
222
            return (SyncMessageReturn) getSyncMessagesReturn().get(index);
 
223
        }
 
224
        return null;
 
225
    }
 
226
 
 
227
    /**
 
228
     * Returns a list of asyncMessageRetun known by this frame. Known asyncMessageRetun are the only on which can be
 
229
     * displayed on screen
 
230
     * 
 
231
     * @return the asyncMessageRetun list or <code>null</code>
 
232
     */
 
233
    protected List<GraphNode> getAsyncMessagesReturn() {
 
234
        if (!fHasChilden) {
 
235
            return null;
 
236
        }
 
237
        return (List<GraphNode>) fNodes.get(AsyncMessageReturn.ASYNC_MESS_RET_TAG);
 
238
    }
 
239
 
 
240
    /**
 
241
     * Returns the number of asyncMessageReturn stored in the frame
 
242
     * 
 
243
     * @return the number of asyncMessageReturn
 
244
     */
 
245
    public int asyncMessageReturnCount() {
 
246
        if (getAsyncMessagesReturn() != null) {
 
247
            return getAsyncMessagesReturn().size();
 
248
        }
 
249
        return 0;
 
250
    }
 
251
 
 
252
    /**
 
253
     * Returns the asyncMessageReturn at the given index in the asyncMessageReturn array
 
254
     * 
 
255
     * @param index the position in the asyncMessageReturn array
 
256
     * @return the asyncMessageReturn or <code>null</code>
 
257
     */
 
258
    public AsyncMessageReturn getAsyncMessageReturn(int index) {
 
259
        if ((getAsyncMessagesReturn() != null) && (index >= 0) && (index < getAsyncMessagesReturn().size())) {
 
260
            return (AsyncMessageReturn) getAsyncMessagesReturn().get(index);
 
261
        }
 
262
        return null;
 
263
    }
 
264
 
 
265
    /**
 
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.
 
268
     * 
 
269
     * @param lifeline the lifeline to add
 
270
     */
 
271
    public void addLifeLine(Lifeline lifeline) {
 
272
        fComputeMinMax = true;
 
273
        if (lifeline == null) {
 
274
            return;
 
275
        }
 
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()) {
 
282
            fHasTimeInfo = true;
 
283
        }
 
284
        // add the lifeline to the lifelines list
 
285
        addNode(lifeline);
 
286
    }
 
287
 
 
288
    /**
 
289
     * Returns the first visible lifeline drawn in the view
 
290
     * 
 
291
     * @return the first visible lifeline index
 
292
     */
 
293
    public int getFirstVisibleLifeline() {
 
294
        if (!fHasChilden) {
 
295
            return 0;
 
296
        } else if (fIndexes.get(Lifeline.LIFELINE_TAG) != null) {
 
297
            return ((Integer) fIndexes.get(Lifeline.LIFELINE_TAG)).intValue();
 
298
        }
 
299
        return 0;
 
300
    }
 
301
 
 
302
    /**
 
303
     * Returns the first visible synchronous message drawn in the view
 
304
     * 
 
305
     * @return the first visible synchronous message index
 
306
     */
 
307
    public int getFirstVisibleSyncMessage() {
 
308
        if (!fHasChilden) {
 
309
            return 0;
 
310
        } else if (fIndexes.get(SyncMessage.SYNC_MESS_TAG) != null) {
 
311
            return ((Integer) fIndexes.get(SyncMessage.SYNC_MESS_TAG)).intValue();
 
312
        }
 
313
        return 0;
 
314
    }
 
315
 
 
316
    /**
 
317
     * Returns the first visible synchronous message return drawn in the view
 
318
     * 
 
319
     * @return the first visible synchronous message return index
 
320
     */
 
321
    public int getFirstVisibleSyncMessageReturn() {
 
322
        if (!fHasChilden) {
 
323
            return 0;
 
324
        } else if (fIndexes.get(SyncMessageReturn.SYNC_MESS_RET_TAG) != null) {
 
325
            return ((Integer) fIndexes.get(SyncMessageReturn.SYNC_MESS_RET_TAG)).intValue();
 
326
        }
 
327
        return 0;
 
328
    }
 
329
 
 
330
    /**
 
331
     * Returns the first visible synchronous message drawn in the view
 
332
     * 
 
333
     * @return the first visible synchronous message index
 
334
     */
 
335
    public int getFirstVisibleAsyncMessage() {
 
336
        if (!fHasChilden) {
 
337
            return 0;
 
338
        } else if (fIndexes.get(AsyncMessage.ASYNC_MESS_TAG) != null) {
 
339
            return ((Integer) fIndexes.get(AsyncMessage.ASYNC_MESS_TAG)).intValue();
 
340
        }
 
341
        return 0;
 
342
    }
 
343
 
 
344
    /**
 
345
     * Returns the first visible synchronous message return drawn in the view
 
346
     * 
 
347
     * @return the first visible synchronous message return index
 
348
     */
 
349
    public int getFirstVisibleAsyncMessageReturn() {
 
350
        if (!fHasChilden) {
 
351
            return 0;
 
352
        } else if (fIndexes.get(AsyncMessageReturn.ASYNC_MESS_RET_TAG) != null) {
 
353
            return ((Integer) fIndexes.get(AsyncMessageReturn.ASYNC_MESS_RET_TAG)).intValue();
 
354
        }
 
355
        return 0;
 
356
    }
 
357
 
 
358
    /**
 
359
     * Returns the list of execution occurrences.
 
360
     * 
 
361
     * @return the list of execution occurrences
 
362
     */
 
363
    public List<SDTimeEvent> getExecutionOccurrencesWithTime() {
 
364
        return fExecutionOccurrencesWithTime;
 
365
    }
 
366
 
 
367
    /**
 
368
     * Inserts a lifeline after a given lifeline.
 
369
     * 
 
370
     * @param toInsert A lifeline to insert
 
371
     * @param after A lifelife the toInsert-lifeline will be inserted after.  
 
372
     */
 
373
    public void insertLifelineAfter(Lifeline toInsert, Lifeline after) {
 
374
        if ((toInsert == null)) {
 
375
            return;
 
376
        }
 
377
        if (toInsert == after) {
 
378
            return;
 
379
        }
 
380
        int insertPoint = 0;
 
381
        if (after != null) {
 
382
            insertPoint = after.getIndex();
 
383
        }
 
384
        int removePoint = toInsert.getIndex() - 1;
 
385
        if (removePoint >= insertPoint) {
 
386
            getLifelines().remove(removePoint);
 
387
        }
 
388
        getLifelines().add(insertPoint, toInsert);
 
389
        if (removePoint < insertPoint) {
 
390
            getLifelines().remove(removePoint);
 
391
        }
 
392
 
 
393
        if (removePoint >= insertPoint) {
 
394
            toInsert.setIndex(insertPoint + 1);
 
395
        } else {
 
396
            toInsert.setIndex(insertPoint - 1);
 
397
        }
 
398
 
 
399
        insertPoint++;
 
400
        if (removePoint >= insertPoint) {
 
401
            for (int i = insertPoint; i < getLifelines().size(); i++) {
 
402
                getLifeline(i).setIndex(i + 1);
 
403
            }
 
404
        } else {
 
405
            for (int i = 0; i < insertPoint && i < getLifelines().size(); i++) {
 
406
                getLifeline(i).setIndex(i + 1);
 
407
            }
 
408
        }
 
409
    }
 
410
 
 
411
    /**
 
412
     * Inserts a lifeline before a given lifeline.
 
413
     * 
 
414
     * @param toInsert A lifeline to insert
 
415
     * @param after A lifelife the toInsert-lifeline will be inserted before.  
 
416
     */
 
417
    public void insertLifelineBefore(Lifeline toInsert, Lifeline before) {
 
418
        if ((toInsert == null)) {
 
419
            return;
 
420
        }
 
421
        if (toInsert == before) {
 
422
            return;
 
423
        }
 
424
        int insertPoint = 0;
 
425
        if (before != null) {
 
426
            insertPoint = before.getIndex() - 1;
 
427
        }
 
428
        int removePoint = toInsert.getIndex() - 1;
 
429
        if (removePoint >= insertPoint) {
 
430
            getLifelines().remove(removePoint);
 
431
        }
 
432
        getLifelines().add(insertPoint, toInsert);
 
433
        if (removePoint < insertPoint) {
 
434
            getLifelines().remove(removePoint);
 
435
        }
 
436
 
 
437
        if (removePoint >= insertPoint) {
 
438
            toInsert.setIndex(insertPoint + 1);
 
439
        } else {
 
440
            toInsert.setIndex(insertPoint - 1);
 
441
        }
 
442
 
 
443
        insertPoint++;
 
444
        if (removePoint >= insertPoint) {
 
445
            for (int i = insertPoint; i < getLifelines().size(); i++) {
 
446
                getLifeline(i).setIndex(i + 1);
 
447
            }
 
448
        } else {
 
449
            for (int i = 0; i < insertPoint && i < getLifelines().size(); i++) {
 
450
                getLifeline(i).setIndex(i + 1);
 
451
            }
 
452
        }
 
453
    }
 
454
 
 
455
    /**
 
456
     * Gets the closer life line to the given x-coordinate.
 
457
     * 
 
458
     * @param x A x coordinate
 
459
     * @return the closer lifeline 
 
460
     */
 
461
    public Lifeline getCloserLifeline(int x) {
 
462
        int index = (x - Metrics.FRAME_H_MARGIN + Metrics.LIFELINE_H_MAGIN) / Metrics.swimmingLaneWidth() - 1;
 
463
        if (index < 0) {
 
464
            index = 0;
 
465
        }
 
466
        if (index >= getLifelines().size()) {
 
467
            index = getLifelines().size() - 1;
 
468
        }
 
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);
 
473
        if (index > 0) {
 
474
            node2 = getLifeline(index - 1);
 
475
            dist2 = Math.abs(node2.getX() + node2.getWidth() / 2 - x);
 
476
        }
 
477
        if (index < getLifelines().size() - 1) {
 
478
            node3 = getLifeline(index + 1);
 
479
            dist3 = Math.abs(node3.getX() + node3.getWidth() / 2 - x);
 
480
        }
 
481
        if (dist1 <= dist2 && dist1 <= dist3) {
 
482
            return node1;
 
483
        } else if (dist2 <= dist1 && dist2 <= dist3) {
 
484
            return node2;
 
485
        }
 
486
        return node3;
 
487
    }
 
488
 
 
489
    /**
 
490
     * Re-orders the given list of lifelines.
 
491
     * 
 
492
     * @param list A list of lifelines to reorder.
 
493
     */
 
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));
 
501
                    } else {
 
502
                        insertLifelineBefore(temp[0], temp[1]);
 
503
                    }
 
504
                }
 
505
            }
 
506
        }
 
507
    }
 
508
 
 
509
    /**
 
510
     * Resets the time compression information.
 
511
     */
 
512
    public void resetTimeCompression() {
 
513
        fHighlightLifeline = null;
 
514
        this.fStartEvent = 0;
 
515
        this.fNbEvent = 0;
 
516
        fHighlightColor = null;
 
517
    }
 
518
 
 
519
    /*
 
520
     * (non-Javadoc)
 
521
     * @see org.eclipse.linuxtools.tmf.ui.views.uml2sd.core.BasicFrame#computeMinMax()
 
522
     */
 
523
    @Override
 
524
    protected void computeMinMax() {
 
525
        List<SDTimeEvent> timeArray = buildTimeArray();
 
526
        if ((timeArray == null) || timeArray.isEmpty()) {
 
527
            return;
 
528
        }
 
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)) {
 
536
                    continue;
 
537
                }
 
538
            }
 
539
 
 
540
            updateMinMax(m1, m2);
 
541
        }
 
542
    }
 
543
 
 
544
    /**
 
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.
 
548
     * 
 
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
 
552
     */
 
553
    public boolean findDateBounds(ITmfTimestamp dateToFind, ITimeRange bounds[]) {
 
554
        if (hasTimeInfo()) {
 
555
            List<SDTimeEvent> timeArray = buildTimeArray();
 
556
 
 
557
            if ((timeArray == null) || timeArray.isEmpty()) {
 
558
                return false;
 
559
            }
 
560
 
 
561
            bounds[0] = null;
 
562
            bounds[1] = null;
 
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();
 
567
                    if (i > 0) {
 
568
                        bounds[0] = ((SDTimeEvent) timeArray.get(i - 1)).getGraphNode();
 
569
                        return true;
 
570
                    }
 
571
                    return false;
 
572
                }
 
573
            }
 
574
            bounds[0] = ((SDTimeEvent) timeArray.get(timeArray.size() - 1)).getGraphNode();
 
575
        }
 
576
        return false;
 
577
    }
 
578
 
 
579
    /**
 
580
     * Set whether time information is available or not
 
581
     * 
 
582
     * @param value <code>true</code> for has time information else <code>false</code>
 
583
     */
 
584
    protected void setHasTimeInfo(boolean value) {
 
585
        fHasTimeInfo = value;
 
586
    }
 
587
 
 
588
    /**
 
589
     * Returns whether frame has time info or not.
 
590
     * 
 
591
     * @return <code>true</code> whether frame has time info else <code>false</code>
 
592
     */
 
593
    public boolean hasTimeInfo() {
 
594
        return fHasTimeInfo;
 
595
    }
 
596
 
 
597
    /**
 
598
     * Highlights the time compression.
 
599
     * 
 
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
 
604
     */
 
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;
 
610
    }
 
611
 
 
612
    /**
 
613
     * Set the lifeline categories which will be use during the lifelines creation
 
614
     * 
 
615
     * @see Lifeline#setCategory(int)
 
616
     * @param categories the lifeline categories array
 
617
     */
 
618
    public void setLifelineCategories(LifelineCategories[] categories) {
 
619
        fLifelineCategories = Arrays.copyOf(categories, categories.length);
 
620
    }
 
621
 
 
622
    /**
 
623
     * Returns the lifeline categories array set for the this frame
 
624
     * 
 
625
     * @return the lifeline categories array or null if not set
 
626
     */
 
627
    public LifelineCategories[] getLifelineCategories() {
 
628
        return  Arrays.copyOf(fLifelineCategories, fLifelineCategories.length); 
 
629
    }
 
630
 
 
631
    /**
 
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.
 
639
     * 
 
640
     * @param message the message to add
 
641
     */
 
642
    public void addMessage(BaseMessage message) {
 
643
        addNode(message);
 
644
    }
 
645
 
 
646
    /*
 
647
     * (non-Javadoc)
 
648
     * @see org.eclipse.linuxtools.tmf.ui.views.uml2sd.core.BasicFrame#draw(org.eclipse.linuxtools.tmf.ui.views.uml2sd.drawings.IGC)
 
649
     */
 
650
    @Override
 
651
    public void draw(IGC context) {
 
652
        drawFrame(context);
 
653
        if (!fHasChilden) {
 
654
            return;
 
655
        }
 
656
        
 
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);
 
663
        }
 
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()));
 
668
        }
 
669
        if (fIndexes.size() == 0) {
 
670
            return;
 
671
        }
 
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()) {
 
676
                break;
 
677
            }
 
678
            toDraw.drawName(context);
 
679
 
 
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()))) {
 
684
 
 
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());
 
695
                                }
 
696
                                tempEvent = tempEvent + 1;
 
697
                            }
 
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()) {
 
701
                                break;
 
702
                            }
 
703
                        }
 
704
                    }
 
705
                }
 
706
            }
 
707
        }
 
708
    }
 
709
 
 
710
    /*
 
711
     * (non-Javadoc)
 
712
     * @see org.eclipse.linuxtools.tmf.ui.views.uml2sd.core.BasicFrame#buildTimeArray()
 
713
     */
 
714
    @Override
 
715
    protected List<SDTimeEvent> buildTimeArray() {
 
716
 
 
717
        if (!fHasChilden) {
 
718
            return new ArrayList<SDTimeEvent>();
 
719
        }
 
720
 
 
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);
 
735
                                timeArray.add(f);
 
736
                                if (fExecutionOccurrencesWithTime == null) {
 
737
                                    fExecutionOccurrencesWithTime = new ArrayList<SDTimeEvent>();
 
738
                                }
 
739
                                fExecutionOccurrencesWithTime.add(f);
 
740
                                event = eo.getEndOccurrence();
 
741
                                time = eo.getEndTime();
 
742
                                f = new SDTimeEvent(time, event, eo);
 
743
                                timeArray.add(f);
 
744
                                fExecutionOccurrencesWithTime.add(f);
 
745
                            }
 
746
                        }
 
747
                    }
 
748
                }
 
749
            }
 
750
        }
 
751
 
 
752
        if (fExecutionOccurrencesWithTime != null) {
 
753
            SDTimeEvent[] temp = fExecutionOccurrencesWithTime.toArray(new SDTimeEvent[fExecutionOccurrencesWithTime.size()]);
 
754
            Arrays.sort(temp, new TimeEventComparator());
 
755
            fExecutionOccurrencesWithTime = Arrays.asList(temp);
 
756
        }
 
757
        SDTimeEvent[] temp = timeArray.toArray(new SDTimeEvent[timeArray.size()]);
 
758
        Arrays.sort(temp, new TimeEventComparator());
 
759
        timeArray = Arrays.asList(temp);
 
760
        return timeArray;
 
761
    }
 
762
 
 
763
    /**
 
764
     * Get the closer leaving message.
 
765
     * 
 
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.
 
771
     */
 
772
    protected GraphNode getCloserLeavingMessage(Lifeline lifeline, BaseMessage message, List<GraphNode> list, boolean smallerEvent) {
 
773
        if (list == null) {
 
774
            return null;
 
775
        }
 
776
 
 
777
        if (!smallerEvent) {
 
778
            int event = 0;
 
779
            if (message != null) {
 
780
                event = message.getEventOccurrence();
 
781
            }
 
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)) {
 
787
                        return node;
 
788
                    }
 
789
                } else if (node instanceof AsyncMessage) {
 
790
                    AsyncMessage asyncNode = (AsyncMessage) node;
 
791
                    if ((asyncNode.getStartOccurrence() > event) && (asyncNode.getStartLifeline() == lifeline) && !asyncNode.isSameAs(message)) {
 
792
                        return node;
 
793
                    }
 
794
                }
 
795
            }
 
796
        } else {
 
797
            int event = getMaxEventOccurrence();
 
798
            if (message != null) {
 
799
                if (message instanceof AsyncMessage) {
 
800
                    event = ((AsyncMessage) message).getStartOccurrence();
 
801
                } else {
 
802
                    event = message.getEventOccurrence();
 
803
                }
 
804
            }
 
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)) {
 
810
                        return node;
 
811
                    }
 
812
                } else if (node instanceof AsyncMessage) {
 
813
                    AsyncMessage asyncNode = (AsyncMessage) node;
 
814
                    if ((asyncNode.getStartOccurrence() < event) && (asyncNode.getStartLifeline() == lifeline) && !asyncNode.isSameAs(message)) {
 
815
                        return node;
 
816
                    }
 
817
                }
 
818
            }
 
819
        }
 
820
        return null;
 
821
    }
 
822
 
 
823
    
 
824
    /**
 
825
     * Get the closer entering message.
 
826
     * 
 
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.
 
832
     */
 
833
    protected GraphNode getCloserEnteringMessage(Lifeline lifeline, BaseMessage message, List<GraphNode> list, boolean smallerEvent) {
 
834
        if (list == null) {
 
835
            return null;
 
836
        }
 
837
        if (!smallerEvent) {
 
838
            int event = 0;
 
839
            if (message != null) {
 
840
                event = message.getEventOccurrence();
 
841
            }
 
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)) {
 
847
                        return node;
 
848
                    }
 
849
                } else if (node instanceof AsyncMessage) {
 
850
                    AsyncMessage asyncNode = (AsyncMessage) node;
 
851
                    if ((asyncNode.getStartOccurrence() > event) && (asyncNode.getEndLifeline() == lifeline) && !asyncNode.isSameAs(message)) {
 
852
                        return node;
 
853
                    }
 
854
                }
 
855
            }
 
856
        } else {
 
857
            int event = getMaxEventOccurrence();
 
858
            if (message != null)
 
859
                if (message instanceof AsyncMessage) {
 
860
                    event = ((AsyncMessage) message).getStartOccurrence();
 
861
                } else {
 
862
                    event = message.getEventOccurrence();
 
863
                }
 
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)) {
 
869
                        return node;
 
870
                    }
 
871
                } else if (node instanceof AsyncMessage) {
 
872
                    AsyncMessage asyncNode = (AsyncMessage) node;
 
873
                    if ((asyncNode.getStartOccurrence() < event) && (asyncNode.getEndLifeline() == lifeline) && !asyncNode.isSameAs(message)) {
 
874
                        return node;
 
875
                    }
 
876
                }
 
877
            }
 
878
        }
 
879
        return null;
 
880
    }
 
881
 
 
882
    /**
 
883
     * Get distance of given event from given graph node.
 
884
     * 
 
885
     * @param node A graph node reference.
 
886
     * @param event A event number to check.
 
887
     * @return distance of event from graph node.
 
888
     */
 
889
    protected int distanceFromEvent(GraphNode node, int event) {
 
890
        int distance = 0;
 
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;
 
898
            } else {
 
899
                distance = end - event;
 
900
            }
 
901
        }
 
902
        return Math.abs(distance);
 
903
    }
 
904
 
 
905
    /**
 
906
     * Get node from 2 given nodes that is close to event.
 
907
     * 
 
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>
 
912
     */
 
913
    protected GraphNode getCloserToEvent(GraphNode node1, GraphNode node2, int event) {
 
914
        if ((node1 != null) && (node2 != null)) {
 
915
            if (distanceFromEvent(node1, event) < distanceFromEvent(node2, event)) {
 
916
                return node1;
 
917
            } else {
 
918
                return node2;
 
919
            }
 
920
        } else if (node1 != null) {
 
921
            return node1;
 
922
        } else if (node2 != null) {
 
923
            return node2;
 
924
        } 
 
925
        return null;
 
926
    }
 
927
 
 
928
    /**
 
929
     * Get called message based on given start message.
 
930
     * 
 
931
     * @param startMessage A start message to check.
 
932
     * @return called message (graph node) or <code>null</code>
 
933
     */
 
934
    public GraphNode getCalledMessage(BaseMessage startMessage) {
 
935
        int event = 0;
 
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();
 
943
            }
 
944
        }
 
945
        if (lifeline == null) {
 
946
            return null;
 
947
        }
 
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);
 
955
        return result;
 
956
    }
 
957
 
 
958
    /**
 
959
     * Get caller message based on given start message.
 
960
     * 
 
961
     * @param startMessage A start message to check.
 
962
     * @return called message (graph node) or <code>null</code>
 
963
     */
 
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();
 
973
            }
 
974
        }
 
975
        if (lifeline == null) {
 
976
            return null;
 
977
        }
 
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);
 
985
        return result;
 
986
    }
 
987
 
 
988
    /**
 
989
     * Get next lifeline based on given message.
 
990
     * 
 
991
     * @param lifeline A lifeline reference
 
992
     * @param startMessage A start message to check
 
993
     * @return next lifeline or <code>null</code>
 
994
     */
 
995
    public GraphNode getNextLifelineMessage(Lifeline lifeline, BaseMessage startMessage) {
 
996
        int event = 0;
 
997
        if (startMessage != null) {
 
998
            event = ((BaseMessage) startMessage).getEventOccurrence();
 
999
        }
 
1000
        if (lifeline == null) {
 
1001
            return null;
 
1002
        }
 
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);
 
1010
        return result;
 
1011
    }
 
1012
 
 
1013
    /**
 
1014
     * Get previous lifeline based on given message.
 
1015
     * 
 
1016
     * @param lifeline A lifeline reference
 
1017
     * @param startMessage A start message to check.
 
1018
     * @return previous lifeline or <code>null</code>
 
1019
     */
 
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();
 
1025
            } else {
 
1026
                event = startMessage.getEventOccurrence();
 
1027
            }
 
1028
        if (lifeline == null) {
 
1029
            return null;
 
1030
        }
 
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);
 
1038
        return result;
 
1039
    }
 
1040
    
 
1041
    /**
 
1042
     * Get the first execution occurrence.
 
1043
     * 
 
1044
     * @param lifeline A lifeline reference
 
1045
     * @return the first execution occurrence of lifeline or <code>null</code>.
 
1046
     */
 
1047
    public BasicExecutionOccurrence getFirstExecution(Lifeline lifeline) {
 
1048
        if (lifeline == null) {
 
1049
            return null;
 
1050
        }
 
1051
        List<GraphNode> list = lifeline.getExecutions();
 
1052
 
 
1053
        if ((list == null) || (list.isEmpty())) {
 
1054
            return null;
 
1055
        }
 
1056
 
 
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())) {
 
1061
                result = e;
 
1062
            }
 
1063
        }
 
1064
        return result;
 
1065
    }
 
1066
    
 
1067
    /**
 
1068
     * Get the previous execution occurrence relative to a given execution occurrence.
 
1069
     * 
 
1070
     * @param exec A execution occurrence reference.
 
1071
     * @return the previous execution occurrence of lifeline or <code>null</code>.
 
1072
     */
 
1073
    public BasicExecutionOccurrence getPrevExecOccurrence(BasicExecutionOccurrence exec) {
 
1074
        if (exec == null) {
 
1075
            return null;
 
1076
        }
 
1077
        Lifeline lifeline = exec.getLifeline();
 
1078
        if (lifeline == null) {
 
1079
            return null;
 
1080
        }
 
1081
        List<GraphNode> list = lifeline.getExecutions();
 
1082
        if (list == null) {
 
1083
            return null;
 
1084
        }
 
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)) {
 
1089
                result = e;
 
1090
            }
 
1091
            if ((e.getStartOccurrence() < exec.fStartEventOccurrence) && (e.getStartOccurrence() >= result.getEndOccurrence())) {
 
1092
                result = e;
 
1093
            }
 
1094
        }
 
1095
        return result;
 
1096
    }
 
1097
 
 
1098
    /**
 
1099
     * Get the next execution occurrence relative to a given execution occurrence.
 
1100
     * 
 
1101
     * @param exec A execution occurrence reference.
 
1102
     * @return the next execution occurrence of lifeline or <code>null</code>.
 
1103
     */
 
1104
    public BasicExecutionOccurrence getNextExecOccurrence(BasicExecutionOccurrence exec) {
 
1105
        if (exec == null) {
 
1106
            return null;
 
1107
        }
 
1108
        Lifeline lifeline = exec.getLifeline();
 
1109
        if (lifeline == null) {
 
1110
            return null;
 
1111
        }
 
1112
        List<GraphNode> list = lifeline.getExecutions();
 
1113
        if (list == null) {
 
1114
            return null;
 
1115
        }
 
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)) {
 
1120
                result = e;
 
1121
            }
 
1122
            if ((e.getStartOccurrence() > exec.fStartEventOccurrence) && (e.getStartOccurrence() <= result.getEndOccurrence())) {
 
1123
                result = e;
 
1124
            }
 
1125
        }
 
1126
        return result;
 
1127
    }
 
1128
 
 
1129
    /**
 
1130
     * Get the last execution occurrence.
 
1131
     * 
 
1132
     * @param lifeline A lifeline reference.
 
1133
     * @return the last execution occurrence of lifeline or <code>null</code>.
 
1134
     */
 
1135
    public BasicExecutionOccurrence getLastExecOccurrence(Lifeline lifeline) {
 
1136
        if (lifeline == null) {
 
1137
            return null;
 
1138
        }
 
1139
        List<GraphNode> list = lifeline.getExecutions();
 
1140
        if (list == null) {
 
1141
            return null;
 
1142
        }
 
1143
        BasicExecutionOccurrence result = null;
 
1144
        for (int i = 0; i < list.size(); i++) {
 
1145
            BasicExecutionOccurrence e = (BasicExecutionOccurrence) list.get(i);
 
1146
            if (result == null) {
 
1147
                result = e;
 
1148
            }
 
1149
            if (e.getStartOccurrence() > result.getEndOccurrence()) {
 
1150
                result = e;
 
1151
            }
 
1152
        }
 
1153
        return result;
 
1154
    }
 
1155
}