1 /**********************************************************************
2 * Copyright (c) 2005, 2014 IBM Corporation, Ericsson
3 * All rights reserved. This program and the accompanying materials
4 * are made available under the terms of the Eclipse Public License v1.0
5 * which accompanies this distribution, and is available at
6 * http://www.eclipse.org/legal/epl-v10.html
9 * IBM - Initial API and implementation
10 * Bernd Hufmann - Updated for TMF
11 **********************************************************************/
13 package org
.eclipse
.tracecompass
.tmf
.ui
.views
.uml2sd
.core
;
15 import static org
.eclipse
.tracecompass
.common
.core
.NonNullUtils
.checkNotNull
;
17 import java
.util
.ArrayList
;
18 import java
.util
.Iterator
;
19 import java
.util
.List
;
21 import org
.eclipse
.tracecompass
.tmf
.core
.timestamp
.ITmfTimestamp
;
22 import org
.eclipse
.tracecompass
.tmf
.core
.timestamp
.TmfTimestamp
;
23 import org
.eclipse
.tracecompass
.tmf
.ui
.views
.uml2sd
.drawings
.IGC
;
24 import org
.eclipse
.tracecompass
.tmf
.ui
.views
.uml2sd
.preferences
.ISDPreferences
;
25 import org
.eclipse
.tracecompass
.tmf
.ui
.views
.uml2sd
.preferences
.SDViewPref
;
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.tracecompass.tmf.ui.views.uml2sd.core.Lifeline Lifeline for more event occurence details
40 public class BasicFrame
extends GraphNode
{
42 // ------------------------------------------------------------------------
44 // ------------------------------------------------------------------------
47 * Contains the max elapsed time between two consecutive messages in the whole frame
49 private ITmfTimestamp fMaxTime
= new TmfTimestamp(0);
51 * Contains the min elapsed time between two consecutive messages in the whole frame
53 private ITmfTimestamp fMinTime
= new TmfTimestamp(0);
55 * Indicate if the min and max elapsed time between two consecutive messages in the whole frame need to be computed
57 private boolean fComputeMinMax
= true;
59 * Store the preference set by the user regarding the external time. This flag is used determine if the min and max
60 * need to be recomputed in case this preference is changed.
62 private boolean fLastExternalTimePref
= SDViewPref
.getInstance().excludeExternalTime();
64 * The greater event occurrence created on graph nodes drawn in this Frame This directly impact the Frame height
66 private int fVerticalIndex
= 0;
68 * The index along the x axis where the next lifeline will is drawn This directly impact the Frame width
70 private int fHorizontalIndex
= 0;
72 * The time information flag.
74 private boolean fHasTimeInfo
= false;
76 * The current Frame visible area - x coordinates
78 private int fVisibleAreaX
;
80 * The current Frame visible area - y coordinates
82 private int fVisibleAreaY
;
84 * The current Frame visible area - width
86 private int fVisibleAreaWidth
;
88 * The current Frame visible area - height
90 private int fVisibleAreaHeight
;
92 * The event occurrence spacing (-1 for none)
94 private int fForceEventOccurrenceSpacing
= -1;
96 * Flag to indicate customized minumum and maximum.
98 private boolean fCustomMinMax
= false;
100 * The minimum time between messages of the sequence diagram frame.
102 private ITmfTimestamp fMinSDTime
= new TmfTimestamp();
104 * The maximum time between messages of the sequence diagram frame.
106 private ITmfTimestamp fMaxSDTime
= new TmfTimestamp();
108 * Flag to indicate that initial minimum has to be computed.
110 private boolean fInitSDMin
= true;
112 // ------------------------------------------------------------------------
114 // ------------------------------------------------------------------------
117 * Creates an empty frame.
119 public BasicFrame() {
120 Metrics
.setForcedEventSpacing(fForceEventOccurrenceSpacing
);
123 // ------------------------------------------------------------------------
125 // ------------------------------------------------------------------------
129 * Returns the greater event occurence known by the Frame
131 * @return the greater event occurrence
133 protected int getMaxEventOccurrence() {
134 return fVerticalIndex
;
138 * Set the greater event occurrence created in GraphNodes included in the frame
140 * @param eventOccurrence the new greater event occurrence
142 protected void setMaxEventOccurrence(int eventOccurrence
) {
143 fVerticalIndex
= eventOccurrence
;
147 * This method increase the lifeline place holder The return value is usually assign to a lifeline. This can be used
148 * to set the lifelines drawing order. Also, calling this method two times and assigning only the last given index
149 * to a lifeline will increase this lifeline draw spacing (2 times the default spacing) from the last added
152 * @return a new lifeline index
154 protected int getNewHorizontalIndex() {
155 return ++fHorizontalIndex
;
159 * Returns the current horizontal index
161 * @return the current horizontal index
162 * @see Frame#getNewHorizontalIndex() for horizontal index description
164 protected int getHorizontalIndex() {
165 return fHorizontalIndex
;
169 public void addNode(GraphNode nodeToAdd
) {
170 setComputeMinMax(true);
171 super.addNode(nodeToAdd
);
176 return Metrics
.FRAME_H_MARGIN
;
181 return Metrics
.FRAME_V_MARGIN
;
185 public int getWidth() {
186 if (fHorizontalIndex
== 0) {
187 return 3 * Metrics
.swimmingLaneWidth() + Metrics
.LIFELINE_H_MAGIN
* 2 - Metrics
.FRAME_H_MARGIN
- Metrics
.LIFELINE_SPACING
/ 2;
189 return fHorizontalIndex
* Metrics
.swimmingLaneWidth() + Metrics
.LIFELINE_H_MAGIN
* 2 + 1 - Metrics
.LIFELINE_SPACING
;
193 public int getHeight() {
194 // The Frame height depends on the maximum number of messages added to a lifeline
195 if (fVerticalIndex
== 0) {
196 return 5 * (Metrics
.getMessagesSpacing() + Metrics
.getMessageFontHeigth()) + Metrics
.LIFELINE_NAME_H_MARGIN
+ Metrics
.FRAME_NAME_H_MARGIN
+ Metrics
.getFrameFontHeigth() + Metrics
.LIFELINE_VT_MAGIN
+ Metrics
.LIFELINE_VB_MAGIN
197 + Metrics
.LIFELINE_NAME_H_MARGIN
+ Metrics
.FRAME_NAME_H_MARGIN
+ Metrics
.getLifelineFontHeigth() * 2;
199 if (fForceEventOccurrenceSpacing
>= 0) {
200 Metrics
.setForcedEventSpacing(fForceEventOccurrenceSpacing
);
202 return fVerticalIndex
* (Metrics
.getMessagesSpacing() + Metrics
.getMessageFontHeigth()) + Metrics
.LIFELINE_NAME_H_MARGIN
+ Metrics
.FRAME_NAME_H_MARGIN
+ Metrics
.getFrameFontHeigth() + Metrics
.LIFELINE_VT_MAGIN
+ Metrics
.LIFELINE_VB_MAGIN
203 + Metrics
.LIFELINE_NAME_H_MARGIN
+ Metrics
.FRAME_NAME_H_MARGIN
+ Metrics
.getLifelineFontHeigth() * 2;
207 * @return true if mininum and maximum time needs to be calculated else false
209 protected boolean isComputeMinMax() {
210 return fComputeMinMax
;
214 * @return true if mininum and maximum time needs to be calculated else false
216 protected boolean isCustomMinMax() {
217 return fCustomMinMax
;
221 * gets the initialization flag for SD minimum.
223 * @return the initialization flag for SD minimum
225 protected boolean getInitSDMin() {
230 * Returns the graph node which contains the point given in parameter for the given graph node list and starting the
231 * iteration at the given index<br>
232 * WARNING: Only graph nodes with smaller coordinates than the current visible area can be returned.<br>
234 * @param x the x coordinate of the point to test
235 * @param y the y coordinate of the point to test
236 * @param list the list to search in
237 * @param fromIndex list browsing starting point
238 * @return the graph node containing the point given in parameter, null otherwise
240 * @see org.eclipse.tracecompass.tmf.ui.views.uml2sd.core.GraphNode#getNodeFromListAt(int, int, java.util.List, int)
243 protected GraphNode
getNodeFromListAt(int x
, int y
, List
<GraphNode
> list
, int fromIndex
) {
247 for (int i
= fromIndex
; i
< list
.size(); i
++) {
248 GraphNode node
= list
.get(i
);
249 // only lifeline list is x ordered
250 // Stop browsing the list if the node is outside the visible area
251 // all others nodes will be not visible
252 if ((node
instanceof Lifeline
) && (node
.getX() > fVisibleAreaX
+ fVisibleAreaWidth
)) {
255 if (node
.getHeight() < 0) {
256 if (node
.getY() + node
.getHeight() > fVisibleAreaY
+ fVisibleAreaHeight
) {
260 if (node
.getY() > fVisibleAreaY
+ fVisibleAreaHeight
) {
264 if (node
.contains(x
, y
)) {
272 * Draw the Frame rectangle
274 * @param context the context to draw to
276 protected void drawFrame(IGC context
) {
278 ISDPreferences pref
= SDViewPref
.getInstance();
280 context
.setBackground(pref
.getBackGroundColor(ISDPreferences
.PREF_FRAME
));
281 context
.setForeground(pref
.getForeGroundColor(ISDPreferences
.PREF_FRAME
));
288 // Draw the frame main rectangle
289 context
.fillRectangle(x
, y
, w
, h
);
290 context
.drawRectangle(x
, y
, w
, h
);
292 context
.setBackground(pref
.getBackGroundColor(ISDPreferences
.PREF_FRAME_NAME
));
293 context
.setForeground(pref
.getForeGroundColor(ISDPreferences
.PREF_FRAME_NAME
));
294 context
.setFont(pref
.getFont(ISDPreferences
.PREF_FRAME_NAME
));
296 int nameWidth
= context
.textExtent(getName()) + 2 * Metrics
.FRAME_NAME_V_MARGIN
;
297 int nameHeight
= Metrics
.getFrameFontHeigth() + +Metrics
.FRAME_NAME_H_MARGIN
* 2;
299 // Draw the frame name area
304 int[] points
= { x
, y
, x
+ nameWidth
, y
, x
+ nameWidth
, y
- 11 + nameHeight
, x
- 11 + nameWidth
, y
+ nameHeight
, x
, y
+ nameHeight
, x
, y
+ nameHeight
};
305 context
.fillPolygon(points
);
306 context
.drawPolygon(points
);
307 context
.drawLine(x
, y
, x
, y
+ nameHeight
);
309 context
.setForeground(pref
.getFontColor(ISDPreferences
.PREF_FRAME_NAME
));
310 context
.drawTextTruncatedCentred(getName(), x
, y
, nameWidth
- 11, nameHeight
, false);
312 context
.setBackground(pref
.getBackGroundColor(ISDPreferences
.PREF_FRAME
));
313 context
.setForeground(pref
.getForeGroundColor(ISDPreferences
.PREF_FRAME
));
317 public void draw(IGC context
) {
322 * Draws the Frame on the given context.<br>
323 * This method start width GraphNodes ordering if needed.<br>
324 * After, depending on the visible area, only visible GraphNodes are drawn.<br>
326 * @param context the context to draw to
327 * @param drawFrame indicate if the frame rectangle need to be redrawn
328 * @see org.eclipse.tracecompass.tmf.ui.views.uml2sd.core.GraphNode#draw(IGC)
330 protected void draw(IGC context
, boolean drawFrame
) {
331 fVisibleAreaHeight
= context
.getVisibleHeight();
332 fVisibleAreaWidth
= context
.getVisibleWidth();
333 fVisibleAreaX
= context
.getContentsX();
334 fVisibleAreaY
= context
.getContentsY();
336 if (fForceEventOccurrenceSpacing
>= 0) {
337 Metrics
.setForcedEventSpacing(fForceEventOccurrenceSpacing
);
339 Metrics
.setForcedEventSpacing(-1);
342 super.drawChildenNodes(context
);
346 * Sets the event occurrence spacing (-1 for none)
348 * @param space A spacing to set.
350 public void forceEventOccurrenceSpacing(int space
) {
351 fForceEventOccurrenceSpacing
= space
;
355 * Return the X coordinates of the frame visible area
357 * @return the X coordinates of the frame visible area
359 public int getVisibleAreaX() {
360 return fVisibleAreaX
;
364 * Return the frame visible area width
366 * @return the frame visible area width
368 public int getVisibleAreaWidth() {
369 return fVisibleAreaWidth
;
373 * Return the frame visible area height
375 * @return the frame visible area height
377 public int getVisibleAreaHeight() {
378 return fVisibleAreaHeight
;
382 * Return the X coordinates of the frame visible area
384 * @return the X coordinates of the frame visible area
386 public int getVisibleAreaY() {
387 return fVisibleAreaY
;
391 * Return the minimum time stored in the frame taking all GraphNodes into account
393 * @return the minimum GraphNode time
395 public ITmfTimestamp
getMinTime() {
396 if (fLastExternalTimePref
!= SDViewPref
.getInstance().excludeExternalTime()) {
397 fLastExternalTimePref
= SDViewPref
.getInstance().excludeExternalTime();
398 setComputeMinMax(true);
400 if ((fComputeMinMax
) && (!fCustomMinMax
)) {
402 setComputeMinMax(false);
408 * Set the minimum timestamp of the frame.
411 * The minimum timestamp
413 public void setMin(ITmfTimestamp min
) {
415 fCustomMinMax
= true;
419 * Set the maximum timestamp of the frame.
422 * The maximum timestamp
424 public void setMax(ITmfTimestamp max
) {
426 fCustomMinMax
= true;
430 * Reset min/max timestamp values to the default ones.
432 public void resetCustomMinMax() {
433 fCustomMinMax
= false;
434 setComputeMinMax(true);
438 * Return the maximum time stored in the frame taking all GraphNodes into account
440 * @return the maximum GraphNode time
442 public ITmfTimestamp
getMaxTime() {
443 if (fLastExternalTimePref
!= SDViewPref
.getInstance().excludeExternalTime()) {
444 fLastExternalTimePref
= SDViewPref
.getInstance().excludeExternalTime();
445 setComputeMinMax(true);
447 if (fComputeMinMax
) {
449 setComputeMinMax(false);
455 * Computes the minimum and maximum time between consecutive messages within the frame.
457 protected void computeMaxMinTime() {
462 List
<SDTimeEvent
> timeArray
= buildTimeArray();
464 if ((timeArray
== null) || timeArray
.isEmpty()) {
467 for (int i
= 0; i
< timeArray
.size(); i
++) {
468 SDTimeEvent m
= timeArray
.get(i
);
470 if (m
.getTime().compareTo(fMaxSDTime
) > 0) {
471 fMaxSDTime
= m
.getTime();
474 if ((m
.getTime().compareTo(fMinSDTime
) < 0) || fInitSDMin
) {
475 fMinSDTime
= m
.getTime();
482 * Returns the minimum time between consecutive messages.
484 * @return the minimum time between consecutive messages
486 public ITmfTimestamp
getSDMinTime() {
492 * Returns the maximum time between consecutive messages.
494 * @return the maximum time between consecutive messages
496 public ITmfTimestamp
getSDMaxTime() {
502 * Browse all the GraphNode to compute the min and max times store in the Frame
504 protected void computeMinMax() {
505 List
<SDTimeEvent
> timeArray
= buildTimeArray();
507 if ((timeArray
== null) || timeArray
.isEmpty()) {
510 for (int i
= 0; i
< timeArray
.size() - 1; i
++) {
511 SDTimeEvent m1
= timeArray
.get(i
);
512 SDTimeEvent m2
= timeArray
.get(i
+ 1);
514 updateMinMax(m1
, m2
);
519 * Updates the minimum and maximum time between consecutive message within the frame based on the given values.
521 * @param m1 A first SD time event.
522 * @param m2 A second SD time event.
524 protected void updateMinMax(SDTimeEvent m1
, SDTimeEvent m2
) {
525 ITmfTimestamp delta
= m2
.getTime().getDelta(m1
.getTime());
526 if (fComputeMinMax
) {
528 if (fMinTime
.compareTo(TmfTimestamp
.ZERO
) < 0) {
529 fMinTime
= new TmfTimestamp(0, m1
.getTime().getScale());
532 setComputeMinMax(false);
535 if ((delta
.compareTo(fMinTime
) < 0) && (delta
.compareTo(TmfTimestamp
.ZERO
) > 0)) {
539 if ((delta
.compareTo(fMaxTime
) > 0) && (delta
.compareTo(TmfTimestamp
.ZERO
) > 0)) {
545 * Builds the time array based on the list of graph nodes.
547 * @return the time array else empty list.
549 protected List
<SDTimeEvent
> buildTimeArray() {
550 if (!hasChildren()) {
551 return new ArrayList
<>();
554 Iterator
<String
> it
= getForwardSortMap().keySet().iterator();
555 List
<SDTimeEvent
> timeArray
= new ArrayList
<>();
556 while (it
.hasNext()) {
557 String nodeType
= it
.next();
558 List
<GraphNode
> list
= checkNotNull(getNodeMap().get(nodeType
));
559 for (int i
= 0; i
< list
.size(); i
++) {
560 Object timedNode
= list
.get(i
);
561 if ((timedNode
instanceof ITimeRange
) && ((ITimeRange
) timedNode
).hasTimeInfo()) {
562 int event
= list
.get(i
).getStartOccurrence();
563 ITmfTimestamp time
= ((ITimeRange
) list
.get(i
)).getStartTime();
564 SDTimeEvent f
= new SDTimeEvent(time
, event
, (ITimeRange
) list
.get(i
));
566 if (event
!= list
.get(i
).getEndOccurrence()) {
567 event
= (list
.get(i
)).getEndOccurrence();
568 time
= ((ITimeRange
) list
.get(i
)).getEndTime();
569 f
= new SDTimeEvent(time
, event
, (ITimeRange
) list
.get(i
));
579 public String
getArrayId() {
584 public boolean contains(int x
, int y
) {
589 * @return true if frame has time info else false
591 public boolean hasTimeInfo() {
596 * Sets the flag whether the frame has time info or not
599 * true if frame has time info else false
601 public void setHasTimeInfo(boolean hasTimeInfo
) {
602 fHasTimeInfo
= hasTimeInfo
;
606 * Sets the flag for minimum and maximum computation.
608 * @param computeMinMax
609 * true if mininum and maximum time needs to be calculated else false
611 public void setComputeMinMax(boolean computeMinMax
) {
612 fComputeMinMax
= computeMinMax
;
616 * Sets the initialization flag for SD minimum.
621 public void setInitSDMin(boolean initSDMin
) {
622 fInitSDMin
= initSDMin
;