1 /**********************************************************************
2 * Copyright (c) 2005, 2008, 2011 IBM Corporation and others.
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
7 * $Id: BasicFrame.java,v 1.2 2008/01/24 02:28:49 apnan Exp $
10 * IBM - Initial API and implementation
11 * Bernd Hufmann - Updated for TMF
12 **********************************************************************/
13 package org
.eclipse
.linuxtools
.tmf
.ui
.views
.uml2sd
.core
;
15 import java
.util
.ArrayList
;
16 import java
.util
.Iterator
;
17 import java
.util
.List
;
19 import org
.eclipse
.linuxtools
.tmf
.event
.TmfTimestamp
;
20 import org
.eclipse
.linuxtools
.tmf
.ui
.views
.uml2sd
.drawings
.IGC
;
21 import org
.eclipse
.linuxtools
.tmf
.ui
.views
.uml2sd
.drawings
.ISDPreferences
;
22 import org
.eclipse
.linuxtools
.tmf
.ui
.views
.uml2sd
.preferences
.SDViewPref
;
25 * The Frame class is the base sequence diagram graph nodes container.<br>
26 * For instance, only one frame can be drawn in the View.<br>
27 * Lifelines, Messages and Stop which are supposed to represent a Sequence diagram are drawn in a Frame.<br>
28 * Only the graph node added to their representing list will be drawn.
30 * The lifelines are appended along the X axsis when added in a frame.<br>
31 * The syncMessages are ordered along the Y axsis depending on the event occurrence they are attached to.<br>
33 * @see org.eclipse.linuxtools.tmf.ui.views.uml2sd.core.Lifeline Lifeline for more event occurence details
37 public class BasicFrame
extends GraphNode
{
40 * Contains the max elapsed time between two consecutive messages in the whole frame
42 protected TmfTimestamp maxTime
= new TmfTimestamp(0);
44 * Contains the min elapsed time between two consecutive messages in the whole frame
46 protected TmfTimestamp minTime
= new TmfTimestamp(0);
49 * Indicate if the min and max elapsed time between two consecutive messages in the whole frame need to be computed
51 protected boolean computeMinMax
= true;
54 * Store the preference set by the user regarding the external time. This flag is used determine if the min and max
55 * need to be recomputed in case this preference is changed.
57 protected boolean lastExternalTimePref
= SDViewPref
.getInstance().excludeExternalTime();
60 * The greater event occurrence created on graph nodes drawn in this Frame This directly impact the Frame height
62 protected int verticalIndex
= 0;
65 * The index along the x axis where the next lifeline will is drawn This directly impact the Frame width
67 protected int horizontalIndex
= 0;
69 protected boolean timeInfo
= false;
72 * The current Frame visible area
74 protected int visibleAreaX
;
75 protected int visibleAreaY
;
76 protected int visibleAreaWidth
;
77 protected int visibleAreaHeight
;
79 protected static ISDPreferences userPref
= null;
81 protected int forceEventOccurrenceSpacing
= -1;
83 protected boolean customMinMax
= false;
85 protected TmfTimestamp minSDTime
= new TmfTimestamp();
86 protected TmfTimestamp maxSDTime
= new TmfTimestamp();
87 protected boolean initSDMin
= true;
90 * Creates an empty frame.
93 Metrics
.setForcedEventSpacing(forceEventOccurrenceSpacing
);
98 * Returns the greater event occurence known by the Frame
100 * @return the greater event occurrence
102 protected int getMaxEventOccurrence() {
103 return verticalIndex
;
107 * Set the greater event occurrence created in GraphNodes included in the frame
109 * @param eventOccurrence the new greater event occurrence
111 protected void setMaxEventOccurrence(int eventOccurrence
) {
112 verticalIndex
= eventOccurrence
;
116 * This method increase the lifeline place holder The return value is usually assign to a lifeline. This can be used
117 * to set the lifelines drawing order. Also, calling this method two times and assigning only the last given index
118 * to a lifeline will increase this lifeline draw spacing (2 times the default spacing) from the last added
121 * @return a new lifeline index
123 protected int getNewHorizontalIndex() {
124 return ++horizontalIndex
;
128 * Returns the current horizontal index
130 * @return the current horizontal index
131 * @see Frame#getNewHorizontalIndex() for horizontal index description
133 protected int getHorizontalIndex() {
134 return horizontalIndex
;
138 * Add a GraphNode into the frame
140 * @param nodeToAdd the node to add
143 public void addNode(GraphNode nodeToAdd
) {
144 computeMinMax
= true;
145 super.addNode(nodeToAdd
);
149 * @return the frame x axis value in the containing view
150 * @see org.eclipse.linuxtools.tmf.ui.views.uml2sd.core.GraphNode#getX()
154 return Metrics
.FRAME_H_MARGIN
;
158 * @return the frame y axis value in the containing view
159 * @see org.eclipse.linuxtools.tmf.ui.views.uml2sd.core.GraphNode#getX()
163 return Metrics
.FRAME_V_MARGIN
;
167 * The frame width depends on the number of lifeline added in the frame
169 * @return the frame width
170 * @see org.eclipse.linuxtools.tmf.ui.views.uml2sd.core.GraphNode#getWidth()
173 public int getWidth() {
174 if (horizontalIndex
== 0)
175 return 3 * Metrics
.swimmingLaneWidth() + Metrics
.LIFELINE_H_MAGIN
* 2 - Metrics
.FRAME_H_MARGIN
- Metrics
.LIFELINE_SPACING
/ 2;
177 return horizontalIndex
* Metrics
.swimmingLaneWidth() + Metrics
.LIFELINE_H_MAGIN
* 2 + 1 - Metrics
.LIFELINE_SPACING
;
181 * The Frame height depends on the maximum number of messages added to a lifeline( Taking all lifelines into
184 * @return the frame height
185 * @see org.eclipse.linuxtools.tmf.ui.views.uml2sd.core.GraphNode#getHeight()
188 public int getHeight() {
189 if (verticalIndex
== 0)
190 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
191 + Metrics
.LIFELINE_NAME_H_MARGIN
+ Metrics
.FRAME_NAME_H_MARGIN
+ Metrics
.getLifelineFontHeigth() * 2;
192 if (forceEventOccurrenceSpacing
>= 0)
193 Metrics
.setForcedEventSpacing(forceEventOccurrenceSpacing
);
194 return verticalIndex
* (Metrics
.getMessagesSpacing() + Metrics
.getMessageFontHeigth()) + Metrics
.LIFELINE_NAME_H_MARGIN
+ Metrics
.FRAME_NAME_H_MARGIN
+ Metrics
.getFrameFontHeigth() + Metrics
.LIFELINE_VT_MAGIN
+ Metrics
.LIFELINE_VB_MAGIN
195 + Metrics
.LIFELINE_NAME_H_MARGIN
+ Metrics
.FRAME_NAME_H_MARGIN
+ Metrics
.getLifelineFontHeigth() * 2;
199 * Returns the graph node which contains the point given in parameter for the given graph node list and starting the
200 * iteration at the given index<br>
201 * WARNING: Only graph nodes with smaller coordinates than the current visible area can be returned.<br>
203 * @param x the x coordinate of the point to test
204 * @param y the y coordinate of the point to test
205 * @param list the list to search in
206 * @param fromIndex list browsing starting point
207 * @return the graph node containing the point given in parameter, null otherwise
210 protected GraphNode
getNodeFromListAt(int x
, int y
, List
<GraphNode
> list
, int fromIndex
) {
213 for (int i
= fromIndex
; i
< list
.size(); i
++) {
214 GraphNode node
= (GraphNode
) list
.get(i
);
215 // only lifeline list is x ordered
216 // Stop browsing the list if the node is outside the visible area
217 // all others nodes will be not visible
218 if ((node
instanceof Lifeline
) && (node
.getX() > visibleAreaX
+ visibleAreaWidth
))
220 if (node
.getHeight() < 0) {
221 if (node
.getY() + node
.getHeight() > visibleAreaY
+ visibleAreaHeight
)
224 if (node
.getY() > visibleAreaY
+ visibleAreaHeight
)
227 if (node
.contains(x
, y
))
234 * Draw the Frame rectangle
236 * @param context the context to draw to
238 protected void drawFrame(IGC context
) {
239 context
.setBackground(Frame
.getUserPref().getBackGroundColor(ISDPreferences
.PREF_FRAME
));
240 context
.setForeground(Frame
.getUserPref().getForeGroundColor(ISDPreferences
.PREF_FRAME
));
247 // Draw the frame main rectangle
248 context
.fillRectangle(x
, y
, w
, h
);
249 context
.drawRectangle(x
, y
, w
, h
);
251 context
.setBackground(Frame
.getUserPref().getBackGroundColor(ISDPreferences
.PREF_FRAME_NAME
));
252 context
.setForeground(Frame
.getUserPref().getForeGroundColor(ISDPreferences
.PREF_FRAME_NAME
));
253 context
.setFont(Frame
.getUserPref().getFont(ISDPreferences
.PREF_FRAME_NAME
));
255 int nameWidth
= context
.textExtent(getName()) + 2 * Metrics
.FRAME_NAME_V_MARGIN
;
256 int nameHeight
= Metrics
.getFrameFontHeigth() + +Metrics
.FRAME_NAME_H_MARGIN
* 2;
258 // Draw the frame name area
262 int[] points
= { x
, y
, x
+ nameWidth
, y
, x
+ nameWidth
, y
- 11 + nameHeight
, x
- 11 + nameWidth
, y
+ nameHeight
, x
, y
+ nameHeight
, x
, y
+ nameHeight
};
263 context
.fillPolygon(points
);
264 context
.drawPolygon(points
);
265 context
.drawLine(x
, y
, x
, y
+ nameHeight
);
267 context
.setForeground(Frame
.getUserPref().getFontColor(ISDPreferences
.PREF_FRAME_NAME
));
268 context
.drawTextTruncatedCentred(getName(), x
, y
, nameWidth
- 11, nameHeight
, false);
270 context
.setBackground(Frame
.getUserPref().getBackGroundColor(ISDPreferences
.PREF_FRAME
));
271 context
.setForeground(Frame
.getUserPref().getForeGroundColor(ISDPreferences
.PREF_FRAME
));
275 * Draws the Frame on the given context.<br>
276 * This method start width GraphNodes ordering if needed.<br>
277 * After, depending on the visible area, only visible GraphNodes are drawn.<br>
279 * @param context the context to draw to
280 * @see org.eclipse.linuxtools.tmf.ui.views.uml2sd.core.GraphNode#draw(IGC)
283 public void draw(IGC context
) {
288 * Draws the Frame on the given context.<br>
289 * This method start width GraphNodes ordering if needed.<br>
290 * After, depending on the visible area, only visible GraphNodes are drawn.<br>
292 * @param context the context to draw to
293 * @param drawFrame indicate if the frame rectangle need to be redrawn
294 * @see org.eclipse.linuxtools.tmf.ui.views.uml2sd.core.GraphNode#draw(IGC)
296 protected void draw(IGC context
, boolean drawFrame
) {
297 visibleAreaHeight
= context
.getVisibleHeight();
298 visibleAreaWidth
= context
.getVisibleWidth();
299 visibleAreaX
= context
.getContentsX();
300 visibleAreaY
= context
.getContentsY();
302 if (forceEventOccurrenceSpacing
>= 0)
303 Metrics
.setForcedEventSpacing(forceEventOccurrenceSpacing
);
305 Metrics
.setForcedEventSpacing(-1);
306 if (userPref
== null)
308 super.drawChildenNodes(context
);
311 public static void setUserPref(ISDPreferences pref
) {
315 public static ISDPreferences
getUserPref() {
319 public void forceEventOccurrenceSpacing(int space
) {
320 forceEventOccurrenceSpacing
= space
;
324 * Return the X coordinates of the frame visible area
326 * @return the X coordinates of the frame visible area
328 public int getVisibleAreaX() {
333 * Return the frame visible area width
335 * @return the frame visible area width
337 public int getVisibleAreaWidth() {
338 return visibleAreaWidth
;
342 * Return the frame visible area height
344 * @return the frame visible area height
346 public int getVisibleAreaHeight() {
347 return visibleAreaHeight
;
351 * Return the X coordinates of the frame visible area
353 * @return the X coordinates of the frame visible area
355 public int getVisibleAreaY() {
360 * Return the minimum time stored in the frame taking all GraphNodes into account
362 * @return the minimum GraphNode time
364 public TmfTimestamp
getMinTime() {
365 if (lastExternalTimePref
!= SDViewPref
.getInstance().excludeExternalTime()) {
366 lastExternalTimePref
= SDViewPref
.getInstance().excludeExternalTime();
367 computeMinMax
= true;
369 if ((computeMinMax
) && (!customMinMax
)) {
371 computeMinMax
= false;
376 public void setMin(TmfTimestamp min
) {
381 public void setMax(TmfTimestamp max
) {
386 public void resetCustomMinMax() {
387 customMinMax
= false;
388 computeMinMax
= true;
392 * Return the maximum time stored in the frame taking all GraphNodes into account
394 * @return the maximum GraphNode time
396 public TmfTimestamp
getMaxTime() {
397 if (lastExternalTimePref
!= SDViewPref
.getInstance().excludeExternalTime()) {
398 lastExternalTimePref
= SDViewPref
.getInstance().excludeExternalTime();
399 computeMinMax
= true;
403 computeMinMax
= false;
408 protected void computeMaxMinTime() {
412 List
<SDTimeEvent
> timeArray
= buildTimeArray();
413 if (timeArray
== null)
415 for (int i
= 0; i
< timeArray
.size(); i
++) {
416 SDTimeEvent m
= (SDTimeEvent
) timeArray
.get(i
);
418 if (m
.getTime().compareTo(maxSDTime
, true) > 0) {
419 maxSDTime
= m
.getTime();
422 if ((m
.getTime().compareTo(minSDTime
, true) < 0) || (initSDMin
== true)) {
423 minSDTime
= m
.getTime();
429 public TmfTimestamp
getSDMinTime() {
434 public TmfTimestamp
getSDMaxTime() {
440 * Browse all the GraphNode to compute the min and max times store in the Frame
442 protected void computeMinMax() {
443 List
<SDTimeEvent
> timeArray
= buildTimeArray();
444 if (timeArray
== null)
446 for (int i
= 0; i
< timeArray
.size() - 1; i
++) {
447 SDTimeEvent m1
= (SDTimeEvent
) timeArray
.get(i
);
448 SDTimeEvent m2
= (SDTimeEvent
) timeArray
.get(i
+ 1);
450 updateMinMax(m1
, m2
);
455 protected void updateMinMax(SDTimeEvent m1
, SDTimeEvent m2
) {
456 TmfTimestamp delta
= m2
.getTime().getDelta(m1
.getTime());
458 minTime
= delta
.clone();
459 if (minTime
.compareTo(TmfTimestamp
.Zero
, false) < 0) {
460 minTime
= new TmfTimestamp(0, m1
.getTime().getScale(), m1
.getTime().getPrecision());
462 maxTime
= minTime
.clone();
463 computeMinMax
= false;
466 if ((delta
.compareTo(minTime
, true) < 0) && (delta
.compareTo(TmfTimestamp
.Zero
, false) > 0)) {
467 minTime
= delta
.clone();
470 if ((delta
.compareTo(maxTime
, true) > 0) && (delta
.compareTo(TmfTimestamp
.Zero
, false) > 0)) {
471 maxTime
= delta
.clone();
475 protected List
<SDTimeEvent
> buildTimeArray() {
479 Iterator
<String
> it
= fSort
.keySet().iterator();
480 List
<SDTimeEvent
> timeArray
= new ArrayList
<SDTimeEvent
>();
481 while (it
.hasNext()) {
482 String nodeType
= it
.next();
483 List
<GraphNode
> list
= (List
<GraphNode
>) nodes
.get(nodeType
);
484 for (int i
= 0; i
< list
.size(); i
++) {
485 Object timedNode
= list
.get(i
);
486 if ((timedNode
instanceof ITimeRange
) && ((ITimeRange
) timedNode
).hasTimeInfo()) {
487 int event
= ((GraphNode
) list
.get(i
)).getStartOccurrence();
488 TmfTimestamp time
= ((ITimeRange
) list
.get(i
)).getStartTime();
489 SDTimeEvent f
= new SDTimeEvent(time
, event
, (ITimeRange
) list
.get(i
));
491 if (event
!= ((GraphNode
) list
.get(i
)).getEndOccurrence()) {
492 event
= ((AsyncMessage
) list
.get(i
)).getEndOccurrence();
493 time
= ((ITimeRange
) list
.get(i
)).getEndTime();
494 f
= new SDTimeEvent(time
, event
, (ITimeRange
) list
.get(i
));
505 * @see org.eclipse.linuxtools.tmf.ui.views.uml2sd.core.GraphNode#getArrayId()
508 public String
getArrayId() {
514 * @see org.eclipse.linuxtools.tmf.ui.views.uml2sd.core.GraphNode#contains(int, int)
517 public boolean contains(int x
, int y
) {