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: Lifeline.java,v 1.3 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
.List
;
18 import org
.eclipse
.linuxtools
.tmf
.ui
.views
.uml2sd
.drawings
.IColor
;
19 import org
.eclipse
.linuxtools
.tmf
.ui
.views
.uml2sd
.drawings
.IGC
;
20 import org
.eclipse
.linuxtools
.tmf
.ui
.views
.uml2sd
.drawings
.IImage
;
21 import org
.eclipse
.linuxtools
.tmf
.ui
.views
.uml2sd
.drawings
.ISDPreferences
;
24 * Lifeline is the UML2 lifeline graphical representation.<br>
25 * Each lifeline owns a set of event occurrences. An event occurrence is the base element in UML2 to set an event in a
26 * sequence diagram.<br>
27 * Event occurrence define the drawing order of graph node along a lifeline. In this lifeline implementation, event
28 * occurrences are just integer index. The event occurrences with the same value on different lifelines will correspond
29 * the same y coordinate value.
34 public class Lifeline
extends GraphNode
{
37 * The lifeline position in the containing frame
39 protected int indexInFrame
= 0;
42 * The frame where the lifeline is drawn
44 protected Frame frame
= null;
47 * The current event occurrence created in the lifeline
49 protected int eventOccurrence
= 0;
51 public static final String LIFELINE_TAG
= "Lifeline"; //$NON-NLS-1$
53 protected int category
= -1;
55 protected boolean hasTime
= false;
59 return Metrics
.FRAME_H_MARGIN
+ Metrics
.LIFELINE_H_MAGIN
+ (indexInFrame
- 1) * Metrics
.swimmingLaneWidth();
64 return 2 * Metrics
.FRAME_NAME_H_MARGIN
+ Metrics
.LIFELINE_VT_MAGIN
/ 2 + Metrics
.getFrameFontHeigth() + Metrics
.getLifelineHeaderFontHeigth() + Metrics
.FRAME_V_MARGIN
+ 2 * Metrics
.LIFELINE_HEARDER_TEXT_V_MARGIN
;
68 public int getWidth() {
69 return Metrics
.getLifelineWidth();
73 public int getHeight() {
74 // Set room for two text lines
75 return Metrics
.getLifelineFontHeigth()/** 2 */
76 + 2 * Metrics
.LIFELINE_NAME_H_MARGIN
;
80 prefId
= ISDPreferences
.PREF_LIFELINE
;
84 * Set the lifeline category for this lifeline.
86 * @param arrayIndex the index of the category to use
87 * @see Frame#setLifelineCategories(LifelineCategories[])
89 public void setCategory(int arrayIndex
) {
90 category
= arrayIndex
;
94 * Returns the tooltip text for the lifeline. It is the combination between the category name(if any) and the
97 * @return the tooltip text
99 public String
getToolTipText() {
101 LifelineCategories
[] categories
= frame
.getLifelineCategories();
102 if (category
< categories
.length
) {
103 return categories
[category
].getName() + " " + getName(); //$NON-NLS-1$
105 return ""; //$NON-NLS-1$
107 return ""; //$NON-NLS-1$
111 * Returns the index of the first visible Execution Occurrence in the execution occurrence array.<br>
112 * Execution Occurrences are Y ordered in this array
114 * @return the first visible Execution Occurrence
116 public int getExecOccurrenceDrawIndex() {
119 if (indexes
.get(BasicExecutionOccurrence
.EXEC_OCC_TAG
) != null)
120 return ((Integer
) indexes
.get(BasicExecutionOccurrence
.EXEC_OCC_TAG
)).intValue();
126 * Set the frame on which this lifeline must be drawn
130 protected void setFrame(Frame parentFrame
) {
133 frame
.setHasTimeInfo(true);
135 if (frame
.getMaxEventOccurrence() < getEventOccurrence() + 1)
136 frame
.setMaxEventOccurrence(getEventOccurrence() + 1);
140 * Returns the frame which this lifeline is drawn
144 protected Frame
getFrame() {
149 * Set the lifeline position index in the containing frame
151 * @param index the lifeline X position
154 protected void setIndex(int index
) {
155 indexInFrame
= index
;
159 * Returns the lifeline position in de the containing frame
161 * @return the X position
163 public int getIndex() {
168 * Set the lifeline event occurrence to the value given in parameter This only change the current event occurrence,
169 * greater event created on this lifeline are still valid and usable. This also need to inform the frame of the
170 * operation mostly to store in the frame the greater event found in the diagram (used to determine the frame
173 * @param eventOcc the new current event occurrence
175 public void setCurrentEventOccurrence(int eventOcc
) {
176 if ((frame
!= null) && (frame
.getMaxEventOccurrence() < eventOcc
))
177 frame
.setMaxEventOccurrence(eventOcc
);
178 eventOccurrence
= eventOcc
;
182 * Returns the last created event occurrence along the lifeline.
184 * @return the current event occurrence
186 public int getEventOccurrence() {
187 return eventOccurrence
;
191 * Creates a new event occurrence along the lifeline.
193 * @return the new created event occurrence
195 public int getNewEventOccurrence() {
196 setCurrentEventOccurrence(eventOccurrence
+ 1);
197 return eventOccurrence
;
201 * Adds the execution occurrence given in parameter to the lifeline.<br>
202 * A Execution occurrence is never drawn in the frame instead it is added to a lifeline
204 * @param exec the execution occurrence to add
206 public void addExecution(BasicExecutionOccurrence exec
) {
207 exec
.setLifeline(this);
209 if ((frame
!= null) && (frame
.getMaxEventOccurrence() < exec
.endEventOccurrence
))
210 frame
.setMaxEventOccurrence(exec
.endEventOccurrence
);
213 protected void setTimeInfo(boolean value
) {
215 if ((frame
!= null) && (value
== true))
216 frame
.setHasTimeInfo(value
);
220 * @return true if at least one execution occurrence has time info
222 public boolean hasTimeInfo() {
227 * Returns the list of execution occurrence on this lifeline
229 * @return the execution occurrence list
231 public List
<GraphNode
> getExecutions() {
233 return (List
<GraphNode
>) nodes
.get(BasicExecutionOccurrence
.EXEC_OCC_TAG
);
235 return new ArrayList
<GraphNode
>();
239 public boolean contains(int _x
, int _y
) {
242 int width
= getWidth();
243 int height
= getHeight();
247 if (Frame
.contains(x
, y
, width
, height
, _x
, _y
)) {
250 if (Frame
.contains(x
+ Metrics
.getLifelineWidth() / 2 - Metrics
.EXECUTION_OCCURRENCE_WIDTH
/ 2, y
+ height
, Metrics
.EXECUTION_OCCURRENCE_WIDTH
, (Metrics
.getMessageFontHeigth() + Metrics
.getMessagesSpacing()) * frame
.getMaxEventOccurrence()
251 + Metrics
.LIFELINE_VB_MAGIN
- 4, _x
, _y
)) {
255 height
= Metrics
.getLifelineFontHeigth() + 2 * Metrics
.LIFELINE_HEARDER_TEXT_V_MARGIN
;
256 int hMargin
= (Metrics
.LIFELINE_VT_MAGIN
- height
) / 2;
259 if (frame
.getVisibleAreaY() < y
- height
- hMargin
) {
260 if (Frame
.contains(x
- Metrics
.LIFELINE_SPACING
/ 2 + 1, y
- height
- hMargin
, Metrics
.swimmingLaneWidth() - 2, height
+ 1, _x
, _y
))
263 if (Frame
.contains(x
- Metrics
.LIFELINE_SPACING
/ 2 + 1, frame
.getVisibleAreaY(), Metrics
.swimmingLaneWidth() - 2, height
, _x
, _y
))
267 if (getNodeAt(_x
, _y
) != null)
273 * Returns the lifeline visibility for the given visible area
279 * @return true if visible false otherwise
282 public boolean isVisible(int vx
, int vy
, int vwidth
, int vheight
) {
284 int width
= getWidth();
285 if (((x
>= vx
) && (x
<= vx
+ vwidth
)) || ((x
+ width
>= vx
) && (x
<= vx
)))
290 protected void drawName(IGC context
) {
293 int height
= Metrics
.getLifelineHeaderFontHeigth() + 2 * Metrics
.LIFELINE_HEARDER_TEXT_V_MARGIN
;
294 int hMargin
= Metrics
.LIFELINE_VT_MAGIN
/ 4;// (Metrics.LIFELINE_NAME_H_MARGIN)/2;
296 context
.setLineStyle(context
.getLineSolidStyle());
297 context
.setBackground(Frame
.getUserPref().getBackGroundColor(ISDPreferences
.PREF_LIFELINE_HEADER
));
298 context
.setForeground(Frame
.getUserPref().getForeGroundColor(ISDPreferences
.PREF_LIFELINE_HEADER
));
299 context
.setFont(Frame
.getUserPref().getFont(ISDPreferences
.PREF_LIFELINE_HEADER
));
301 if (frame
.getVisibleAreaY() < y
- height
- hMargin
) {
302 context
.fillRectangle(x
- Metrics
.LIFELINE_SPACING
/ 2 + 1, y
- height
- hMargin
, Metrics
.swimmingLaneWidth() - 2, height
);
303 context
.drawRectangle(x
- Metrics
.LIFELINE_SPACING
/ 2 + 1, y
- height
- hMargin
, Metrics
.swimmingLaneWidth() - 2, height
);
304 context
.setForeground(Frame
.getUserPref().getFontColor(ISDPreferences
.PREF_LIFELINE_HEADER
));
305 context
.drawTextTruncatedCentred(getName(), x
+ Metrics
.LIFELINE_NAME_V_MARGIN
- Metrics
.LIFELINE_SPACING
/ 2 + 1, y
- height
- hMargin
, Metrics
.swimmingLaneWidth() - 2 * Metrics
.LIFELINE_NAME_V_MARGIN
- 2, height
, true);
307 context
.fillRectangle(x
- Metrics
.LIFELINE_SPACING
/ 2 + 1, frame
.getVisibleAreaY(), Metrics
.swimmingLaneWidth() - 2, height
);
308 context
.drawRectangle(x
- Metrics
.LIFELINE_SPACING
/ 2 + 1, frame
.getVisibleAreaY(), Metrics
.swimmingLaneWidth() - 2, height
);
309 context
.setForeground(Frame
.getUserPref().getFontColor(ISDPreferences
.PREF_LIFELINE_HEADER
));
310 context
.drawTextTruncatedCentred(getName(), x
- Metrics
.LIFELINE_SPACING
/ 2 + Metrics
.LIFELINE_NAME_V_MARGIN
+ 1, frame
.getVisibleAreaY(), Metrics
.swimmingLaneWidth() - 2 * Metrics
.LIFELINE_NAME_V_MARGIN
- 2, height
, true);
316 * Force the lifeline to be drawn at the given coordinate
318 * @param context - the context to draw into
319 * @param x - the x coordinate
320 * @param y - the y coordinate
322 public void draw(IGC context
, int x
, int y
) {
323 // Set the draw color depending if the lifeline must be selected or not
324 context
.setLineWidth(Metrics
.NORMAL_LINE_WIDTH
);
326 if (Frame
.getUserPref().useGradienColor()) {
327 context
.setGradientColor(Frame
.getUserPref().getBackGroundColor(ISDPreferences
.PREF_LIFELINE
));
329 context
.setBackground(Frame
.getUserPref().getBackGroundColorSelection());
330 context
.setForeground(Frame
.getUserPref().getForeGroundColorSelection());
332 if (Frame
.getUserPref().useGradienColor()) {
333 context
.setGradientColor(Frame
.getUserPref().getBackGroundColor(ISDPreferences
.PREF_LIFELINE
));
334 context
.setBackground(Frame
.getUserPref().getBackGroundColor(ISDPreferences
.PREF_FRAME
));
336 context
.setBackground(Frame
.getUserPref().getBackGroundColor(ISDPreferences
.PREF_LIFELINE
));
337 context
.setForeground(Frame
.getUserPref().getForeGroundColor(ISDPreferences
.PREF_LIFELINE
));
339 // Store the lifeline coordinates to save some calls
340 int width
= getWidth();
341 int height
= getHeight();
343 // Draw the rectangle which contain the lifeline name
344 if (Frame
.getUserPref().useGradienColor()) {
345 context
.fillGradientRectangle(x
, y
, width
, height
/ 2 - 7, true);
346 context
.fillRectangle(x
, y
+ height
/ 2 - 8, width
, +height
/ 2 - 5);
347 context
.fillGradientRectangle(x
, y
+ height
, width
, -height
/ 2 + 6, true);
349 context
.fillRectangle(x
, y
, width
, height
);
350 context
.drawRectangle(x
, y
, width
, height
);
353 LifelineCategories
[] categories
= frame
.getLifelineCategories();
354 if (category
< categories
.length
) {
355 IImage image
= categories
[category
].getImage();
357 context
.drawImage(image
, x
, y
, width
, height
);
361 // Draw the lifeline label into the rectangle
362 // The label is truncated if it cannot fit
363 IColor temp
= context
.getForeground();
364 context
.setFont(Frame
.getUserPref().getFont(ISDPreferences
.PREF_LIFELINE
));
365 context
.setForeground(Frame
.getUserPref().getFontColor(ISDPreferences
.PREF_LIFELINE
));
366 context
.drawTextTruncatedCentred(getName(), x
+ Metrics
.LIFELINE_NAME_V_MARGIN
, y
, Metrics
.getLifelineWidth() - 2 * Metrics
.LIFELINE_NAME_V_MARGIN
, height
, true);
368 context
.setLineStyle(context
.getLineDashStyle());
369 context
.setForeground(temp
);
370 int oldStyle
= context
.getLineStyle();
372 // Now draw the lifeline vertical line
373 // this line height depends on a stop assignment
374 // if there is no stop the line is drawn to the bottom of the frame
376 // by default set the height to reach the frame bottom
377 int dashedLineEnd
= y
+ height
+ (Metrics
.getMessageFontHeigth() + Metrics
.getMessagesSpacing()) * frame
.getMaxEventOccurrence() + Metrics
.LIFELINE_VB_MAGIN
;
379 * if (stop != null) { dashedLineEnd = stop.getY(); }
383 context
.setForeground(Frame
.getUserPref().getBackGroundColorSelection());
384 context
.setLineWidth(5);
385 context
.drawLine(x
+ Metrics
.getLifelineWidth() / 2, y
+ height
, x
+ Metrics
.getLifelineWidth() / 2, dashedLineEnd
- 4);
386 context
.setForeground(Frame
.getUserPref().getForeGroundColorSelection());
389 context
.setLineWidth(Metrics
.NORMAL_LINE_WIDTH
);
390 context
.drawLine(x
+ Metrics
.getLifelineWidth() / 2, y
+ height
, x
+ Metrics
.getLifelineWidth() / 2, dashedLineEnd
- 4);
391 context
.drawLine(x
+ Metrics
.getLifelineWidth() / 2, y
+ height
, x
+ Metrics
.getLifelineWidth() / 2, dashedLineEnd
- 4);
392 context
.setLineStyle(oldStyle
);
394 context
.setLineStyle(context
.getLineSolidStyle());
399 super.drawChildenNodes(context
);
403 * Draws the select execution occurrence region using the given color
405 * @param context the graphical context
406 * @param startEvent the region start
407 * @param nbEvent the region height
408 * @param color the color to use
410 public void highlightExecOccurrenceRegion(IGC context
, int startEvent
, int nbEvent
, IColor color
) {
411 IColor backupColor
= context
.getBackground();
412 context
.setBackground(color
);
413 int x
= getX() + Metrics
.getLifelineWidth() / 2 - Metrics
.EXECUTION_OCCURRENCE_WIDTH
/ 2;
414 int y
= getY() + getHeight() + (Metrics
.getMessageFontHeigth() + Metrics
.getMessagesSpacing()) * startEvent
;
415 int width
= Metrics
.EXECUTION_OCCURRENCE_WIDTH
;
416 int height
= ((Metrics
.getMessageFontHeigth() + Metrics
.getMessagesSpacing())) * nbEvent
;
417 context
.fillRectangle(x
, y
, width
, height
);
418 context
.setBackground(backupColor
);
422 public void draw(IGC context
) {
423 draw(context
, getX(), getY());
427 public String
getArrayId() {
432 public boolean positiveDistanceToPoint(int x
, int y
) {
433 if (getX() > x
- Metrics
.swimmingLaneWidth())
439 public GraphNode
getNodeAt(int x
, int y
) {
442 if (getFrame() != null) {
443 vy
= getFrame().getVisibleAreaY();
444 vh
= getFrame().getVisibleAreaHeight();
447 if (getExecutions() == null)
449 for (int i
= getExecOccurrenceDrawIndex(); i
< getExecutions().size(); i
++) {
450 GraphNode node
= (GraphNode
) getExecutions().get(i
);
451 if (node
.getHeight() < 0) {
452 if (node
.getY() + node
.getHeight() > vy
+ vh
)
455 if (node
.getY() > vy
+ vh
)
458 if (node
.contains(x
, y
)) {
459 GraphNode internal
= node
.getNodeAt(x
, y
);
460 if (internal
!= null)