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
.Iterator
;
18 import java
.util
.List
;
20 import org
.eclipse
.linuxtools
.tmf
.core
.event
.ITmfTimestamp
;
21 import org
.eclipse
.linuxtools
.tmf
.core
.event
.TmfTimestamp
;
22 import org
.eclipse
.linuxtools
.tmf
.ui
.views
.uml2sd
.drawings
.IGC
;
23 import org
.eclipse
.linuxtools
.tmf
.ui
.views
.uml2sd
.preferences
.ISDPreferences
;
24 import org
.eclipse
.linuxtools
.tmf
.ui
.views
.uml2sd
.preferences
.SDViewPref
;
27 * The Frame class is the base sequence diagram graph nodes container.<br>
28 * For instance, only one frame can be drawn in the View.<br>
29 * Lifelines, Messages and Stop which are supposed to represent a Sequence diagram are drawn in a Frame.<br>
30 * Only the graph node added to their representing list will be drawn.
32 * The lifelines are appended along the X axsis when added in a frame.<br>
33 * The syncMessages are ordered along the Y axsis depending on the event occurrence they are attached to.<br>
35 * @see org.eclipse.linuxtools.tmf.ui.views.uml2sd.core.Lifeline Lifeline for more event occurence details
39 public class BasicFrame
extends GraphNode
{
41 // ------------------------------------------------------------------------
42 // Static Attributes/Constants
43 // ------------------------------------------------------------------------
45 * The sequence diagram reference.
47 protected static ISDPreferences fUserPref
= null;
49 // ------------------------------------------------------------------------
51 // ------------------------------------------------------------------------
54 * Contains the max elapsed time between two consecutive messages in the whole frame
56 protected ITmfTimestamp fMaxTime
= new TmfTimestamp(0);
58 * Contains the min elapsed time between two consecutive messages in the whole frame
60 protected ITmfTimestamp fMinTime
= new TmfTimestamp(0);
62 * Indicate if the min and max elapsed time between two consecutive messages in the whole frame need to be computed
64 protected boolean fComputeMinMax
= true;
66 * Store the preference set by the user regarding the external time. This flag is used determine if the min and max
67 * need to be recomputed in case this preference is changed.
69 protected boolean fLastExternalTimePref
= SDViewPref
.getInstance().excludeExternalTime();
71 * The greater event occurrence created on graph nodes drawn in this Frame This directly impact the Frame height
73 protected int fVerticalIndex
= 0;
75 * The index along the x axis where the next lifeline will is drawn This directly impact the Frame width
77 protected int fHorizontalIndex
= 0;
79 * The time information flag.
81 protected boolean fHasTimeInfo
= false;
83 * The current Frame visible area - x coordinates
85 protected int fVisibleAreaX
;
87 * The current Frame visible area - y coordinates
89 protected int fVisibleAreaY
;
91 * The current Frame visible area - width
93 protected int fVisibleAreaWidth
;
95 * The current Frame visible area - height
97 protected int fVisibleAreaHeight
;
99 * The event occurrence spacing (-1 for none)
101 protected int fForceEventOccurrenceSpacing
= -1;
103 * Flag to indicate customized minumum and maximum.
105 protected boolean fCustomMinMax
= false;
107 * The minimum time between messages of the sequence diagram frame.
109 protected ITmfTimestamp fMinSDTime
= new TmfTimestamp();
111 * The maximum time between messages of the sequence diagram frame.
113 protected ITmfTimestamp fMaxSDTime
= new TmfTimestamp();
115 * Flag to indicate that initial minimum has to be computed.
117 protected boolean fInitSDMin
= true;
119 // ------------------------------------------------------------------------
121 // ------------------------------------------------------------------------
124 * Creates an empty frame.
126 public BasicFrame() {
127 Metrics
.setForcedEventSpacing(fForceEventOccurrenceSpacing
);
130 // ------------------------------------------------------------------------
132 // ------------------------------------------------------------------------
136 * Returns the greater event occurence known by the Frame
138 * @return the greater event occurrence
140 protected int getMaxEventOccurrence() {
141 return fVerticalIndex
;
145 * Set the greater event occurrence created in GraphNodes included in the frame
147 * @param eventOccurrence the new greater event occurrence
149 protected void setMaxEventOccurrence(int eventOccurrence
) {
150 fVerticalIndex
= eventOccurrence
;
154 * This method increase the lifeline place holder The return value is usually assign to a lifeline. This can be used
155 * to set the lifelines drawing order. Also, calling this method two times and assigning only the last given index
156 * to a lifeline will increase this lifeline draw spacing (2 times the default spacing) from the last added
159 * @return a new lifeline index
161 protected int getNewHorizontalIndex() {
162 return ++fHorizontalIndex
;
166 * Returns the current horizontal index
168 * @return the current horizontal index
169 * @see Frame#getNewHorizontalIndex() for horizontal index description
171 protected int getHorizontalIndex() {
172 return fHorizontalIndex
;
177 * @see org.eclipse.linuxtools.tmf.ui.views.uml2sd.core.GraphNode#addNode(org.eclipse.linuxtools.tmf.ui.views.uml2sd.core.GraphNode)
180 public void addNode(GraphNode nodeToAdd
) {
181 fComputeMinMax
= true;
182 super.addNode(nodeToAdd
);
187 * @see org.eclipse.linuxtools.tmf.ui.views.uml2sd.core.GraphNode#getX()
191 return Metrics
.FRAME_H_MARGIN
;
197 * @see org.eclipse.linuxtools.tmf.ui.views.uml2sd.core.GraphNode#getY()
201 return Metrics
.FRAME_V_MARGIN
;
206 * @see org.eclipse.linuxtools.tmf.ui.views.uml2sd.core.GraphNode#getWidth()
209 public int getWidth() {
210 if (fHorizontalIndex
== 0) {
211 return 3 * Metrics
.swimmingLaneWidth() + Metrics
.LIFELINE_H_MAGIN
* 2 - Metrics
.FRAME_H_MARGIN
- Metrics
.LIFELINE_SPACING
/ 2;
213 return fHorizontalIndex
* Metrics
.swimmingLaneWidth() + Metrics
.LIFELINE_H_MAGIN
* 2 + 1 - Metrics
.LIFELINE_SPACING
;
219 * @see org.eclipse.linuxtools.tmf.ui.views.uml2sd.core.GraphNode#getHeight()
222 public int getHeight() {
223 // The Frame height depends on the maximum number of messages added to a lifeline
224 if (fVerticalIndex
== 0) {
225 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
226 + Metrics
.LIFELINE_NAME_H_MARGIN
+ Metrics
.FRAME_NAME_H_MARGIN
+ Metrics
.getLifelineFontHeigth() * 2;
228 if (fForceEventOccurrenceSpacing
>= 0) {
229 Metrics
.setForcedEventSpacing(fForceEventOccurrenceSpacing
);
231 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
232 + Metrics
.LIFELINE_NAME_H_MARGIN
+ Metrics
.FRAME_NAME_H_MARGIN
+ Metrics
.getLifelineFontHeigth() * 2;
236 * Returns the graph node which contains the point given in parameter for the given graph node list and starting the
237 * iteration at the given index<br>
238 * WARNING: Only graph nodes with smaller coordinates than the current visible area can be returned.<br>
240 * @param x the x coordinate of the point to test
241 * @param y the y coordinate of the point to test
242 * @param list the list to search in
243 * @param fromIndex list browsing starting point
244 * @return the graph node containing the point given in parameter, null otherwise
246 * @see org.eclipse.linuxtools.tmf.ui.views.uml2sd.core.GraphNode#getNodeFromListAt(int, int, java.util.List, int)
249 protected GraphNode
getNodeFromListAt(int x
, int y
, List
<GraphNode
> list
, int fromIndex
) {
253 for (int i
= fromIndex
; i
< list
.size(); i
++) {
254 GraphNode node
= (GraphNode
) list
.get(i
);
255 // only lifeline list is x ordered
256 // Stop browsing the list if the node is outside the visible area
257 // all others nodes will be not visible
258 if ((node
instanceof Lifeline
) && (node
.getX() > fVisibleAreaX
+ fVisibleAreaWidth
)) {
261 if (node
.getHeight() < 0) {
262 if (node
.getY() + node
.getHeight() > fVisibleAreaY
+ fVisibleAreaHeight
) {
266 if (node
.getY() > fVisibleAreaY
+ fVisibleAreaHeight
) {
270 if (node
.contains(x
, y
)) {
278 * Draw the Frame rectangle
280 * @param context the context to draw to
282 protected void drawFrame(IGC context
) {
283 context
.setBackground(Frame
.getUserPref().getBackGroundColor(ISDPreferences
.PREF_FRAME
));
284 context
.setForeground(Frame
.getUserPref().getForeGroundColor(ISDPreferences
.PREF_FRAME
));
291 // Draw the frame main rectangle
292 context
.fillRectangle(x
, y
, w
, h
);
293 context
.drawRectangle(x
, y
, w
, h
);
295 context
.setBackground(Frame
.getUserPref().getBackGroundColor(ISDPreferences
.PREF_FRAME_NAME
));
296 context
.setForeground(Frame
.getUserPref().getForeGroundColor(ISDPreferences
.PREF_FRAME_NAME
));
297 context
.setFont(Frame
.getUserPref().getFont(ISDPreferences
.PREF_FRAME_NAME
));
299 int nameWidth
= context
.textExtent(getName()) + 2 * Metrics
.FRAME_NAME_V_MARGIN
;
300 int nameHeight
= Metrics
.getFrameFontHeigth() + +Metrics
.FRAME_NAME_H_MARGIN
* 2;
302 // Draw the frame name area
307 int[] points
= { x
, y
, x
+ nameWidth
, y
, x
+ nameWidth
, y
- 11 + nameHeight
, x
- 11 + nameWidth
, y
+ nameHeight
, x
, y
+ nameHeight
, x
, y
+ nameHeight
};
308 context
.fillPolygon(points
);
309 context
.drawPolygon(points
);
310 context
.drawLine(x
, y
, x
, y
+ nameHeight
);
312 context
.setForeground(Frame
.getUserPref().getFontColor(ISDPreferences
.PREF_FRAME_NAME
));
313 context
.drawTextTruncatedCentred(getName(), x
, y
, nameWidth
- 11, nameHeight
, false);
315 context
.setBackground(Frame
.getUserPref().getBackGroundColor(ISDPreferences
.PREF_FRAME
));
316 context
.setForeground(Frame
.getUserPref().getForeGroundColor(ISDPreferences
.PREF_FRAME
));
321 * @see org.eclipse.linuxtools.tmf.ui.views.uml2sd.core.GraphNode#draw(org.eclipse.linuxtools.tmf.ui.views.uml2sd.drawings.IGC)
324 public void draw(IGC context
) {
329 * Draws the Frame on the given context.<br>
330 * This method start width GraphNodes ordering if needed.<br>
331 * After, depending on the visible area, only visible GraphNodes are drawn.<br>
333 * @param context the context to draw to
334 * @param drawFrame indicate if the frame rectangle need to be redrawn
335 * @see org.eclipse.linuxtools.tmf.ui.views.uml2sd.core.GraphNode#draw(IGC)
337 protected void draw(IGC context
, boolean drawFrame
) {
338 fVisibleAreaHeight
= context
.getVisibleHeight();
339 fVisibleAreaWidth
= context
.getVisibleWidth();
340 fVisibleAreaX
= context
.getContentsX();
341 fVisibleAreaY
= context
.getContentsY();
343 if (fForceEventOccurrenceSpacing
>= 0) {
344 Metrics
.setForcedEventSpacing(fForceEventOccurrenceSpacing
);
346 Metrics
.setForcedEventSpacing(-1);
348 if (fUserPref
== null) {
351 super.drawChildenNodes(context
);
355 * Sets the sequence diagram preferences.
357 * @param pref the preferences to set.
359 public static void setUserPref(ISDPreferences pref
) {
364 * Returns the sequence diagram preferences.
365 * @return the sequence diagram preferences.
367 public static ISDPreferences
getUserPref() {
372 * Sets the event occurrence spacing (-1 for none)
374 * @param space A spacing to set.
376 public void forceEventOccurrenceSpacing(int space
) {
377 fForceEventOccurrenceSpacing
= space
;
381 * Return the X coordinates of the frame visible area
383 * @return the X coordinates of the frame visible area
385 public int getVisibleAreaX() {
386 return fVisibleAreaX
;
390 * Return the frame visible area width
392 * @return the frame visible area width
394 public int getVisibleAreaWidth() {
395 return fVisibleAreaWidth
;
399 * Return the frame visible area height
401 * @return the frame visible area height
403 public int getVisibleAreaHeight() {
404 return fVisibleAreaHeight
;
408 * Return the X coordinates of the frame visible area
410 * @return the X coordinates of the frame visible area
412 public int getVisibleAreaY() {
413 return fVisibleAreaY
;
417 * Return the minimum time stored in the frame taking all GraphNodes into account
419 * @return the minimum GraphNode time
421 public ITmfTimestamp
getMinTime() {
422 if (fLastExternalTimePref
!= SDViewPref
.getInstance().excludeExternalTime()) {
423 fLastExternalTimePref
= SDViewPref
.getInstance().excludeExternalTime();
424 fComputeMinMax
= true;
426 if ((fComputeMinMax
) && (!fCustomMinMax
)) {
428 fComputeMinMax
= false;
433 public void setMin(ITmfTimestamp min
) {
435 fCustomMinMax
= true;
438 public void setMax(ITmfTimestamp max
) {
440 fCustomMinMax
= true;
443 public void resetCustomMinMax() {
444 fCustomMinMax
= false;
445 fComputeMinMax
= true;
449 * Return the maximum time stored in the frame taking all GraphNodes into account
451 * @return the maximum GraphNode time
453 public ITmfTimestamp
getMaxTime() {
454 if (fLastExternalTimePref
!= SDViewPref
.getInstance().excludeExternalTime()) {
455 fLastExternalTimePref
= SDViewPref
.getInstance().excludeExternalTime();
456 fComputeMinMax
= true;
458 if (fComputeMinMax
) {
460 fComputeMinMax
= false;
466 * Computes the minimum and maximum time between consecutive messages within the frame.
468 protected void computeMaxMinTime() {
473 List
<SDTimeEvent
> timeArray
= buildTimeArray();
474 if (timeArray
== null) {
477 for (int i
= 0; i
< timeArray
.size(); i
++) {
478 SDTimeEvent m
= (SDTimeEvent
) timeArray
.get(i
);
480 if (m
.getTime().compareTo(fMaxSDTime
, true) > 0) {
481 fMaxSDTime
= m
.getTime();
484 if ((m
.getTime().compareTo(fMinSDTime
, true) < 0) || fInitSDMin
) {
485 fMinSDTime
= m
.getTime();
492 * Returns the minimum time between consecutive messages.
494 * @return the minimum time between consecutive messages
496 public ITmfTimestamp
getSDMinTime() {
502 * Returns the maximum time between consecutive messages.
504 * @return the maximum time between consecutive messages
506 public ITmfTimestamp
getSDMaxTime() {
512 * Browse all the GraphNode to compute the min and max times store in the Frame
514 protected void computeMinMax() {
515 List
<SDTimeEvent
> timeArray
= buildTimeArray();
516 if (timeArray
== null) {
519 for (int i
= 0; i
< timeArray
.size() - 1; i
++) {
520 SDTimeEvent m1
= (SDTimeEvent
) timeArray
.get(i
);
521 SDTimeEvent m2
= (SDTimeEvent
) timeArray
.get(i
+ 1);
523 updateMinMax(m1
, m2
);
528 * Updates the minimum and maximum time between consecutive message within the frame based on the given values.
530 * @param m1 A first SD time event.
531 * @param m2 A second SD time event.
533 protected void updateMinMax(SDTimeEvent m1
, SDTimeEvent m2
) {
534 ITmfTimestamp delta
= m2
.getTime().getDelta(m1
.getTime());
535 if (fComputeMinMax
) {
536 fMinTime
= delta
.clone();
537 if (fMinTime
.compareTo(TmfTimestamp
.ZERO
, false) < 0) {
538 fMinTime
= new TmfTimestamp(0, m1
.getTime().getScale(), m1
.getTime().getPrecision());
540 fMaxTime
= fMinTime
.clone();
541 fComputeMinMax
= false;
544 if ((delta
.compareTo(fMinTime
, true) < 0) && (delta
.compareTo(TmfTimestamp
.ZERO
, false) > 0)) {
545 fMinTime
= delta
.clone();
548 if ((delta
.compareTo(fMaxTime
, true) > 0) && (delta
.compareTo(TmfTimestamp
.ZERO
, false) > 0)) {
549 fMaxTime
= delta
.clone();
554 * Builds the time array based on the list of graph nodes.
556 * @return the time array else <code>null</code>.
558 protected List
<SDTimeEvent
> buildTimeArray() {
563 Iterator
<String
> it
= fForwardSort
.keySet().iterator();
564 List
<SDTimeEvent
> timeArray
= new ArrayList
<SDTimeEvent
>();
565 while (it
.hasNext()) {
566 String nodeType
= it
.next();
567 List
<GraphNode
> list
= (List
<GraphNode
>) fNodes
.get(nodeType
);
568 for (int i
= 0; i
< list
.size(); i
++) {
569 Object timedNode
= list
.get(i
);
570 if ((timedNode
instanceof ITimeRange
) && ((ITimeRange
) timedNode
).hasTimeInfo()) {
571 int event
= ((GraphNode
) list
.get(i
)).getStartOccurrence();
572 ITmfTimestamp time
= ((ITimeRange
) list
.get(i
)).getStartTime();
573 SDTimeEvent f
= new SDTimeEvent(time
, event
, (ITimeRange
) list
.get(i
));
575 if (event
!= ((GraphNode
) list
.get(i
)).getEndOccurrence()) {
576 event
= ((AsyncMessage
) list
.get(i
)).getEndOccurrence();
577 time
= ((ITimeRange
) list
.get(i
)).getEndTime();
578 f
= new SDTimeEvent(time
, event
, (ITimeRange
) list
.get(i
));
589 * @see org.eclipse.linuxtools.tmf.ui.views.uml2sd.core.GraphNode#getArrayId()
592 public String
getArrayId() {
598 * @see org.eclipse.linuxtools.tmf.ui.views.uml2sd.core.GraphNode#contains(int, int)
601 public boolean contains(int x
, int y
) {