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 java
.util
.ArrayList
;
16 import java
.util
.List
;
18 import org
.eclipse
.tracecompass
.tmf
.ui
.views
.uml2sd
.drawings
.IColor
;
19 import org
.eclipse
.tracecompass
.tmf
.ui
.views
.uml2sd
.drawings
.IGC
;
20 import org
.eclipse
.tracecompass
.tmf
.ui
.views
.uml2sd
.drawings
.IImage
;
21 import org
.eclipse
.tracecompass
.tmf
.ui
.views
.uml2sd
.preferences
.ISDPreferences
;
22 import org
.eclipse
.tracecompass
.tmf
.ui
.views
.uml2sd
.preferences
.SDViewPref
;
25 * Lifeline is the UML2 lifeline graphical representation.<br>
26 * Each lifeline owns a set of event occurrences. An event occurrence is the base element in UML2 to set an event in a
27 * sequence diagram.<br>
28 * Event occurrence define the drawing order of graph node along a lifeline. In this lifeline implementation, event
29 * occurrences are just integer index. The event occurrences with the same value on different lifelines will correspond
30 * the same y coordinate value.
36 public class Lifeline
extends GraphNode
{
37 // ------------------------------------------------------------------------
39 // ------------------------------------------------------------------------
43 public static final String LIFELINE_TAG
= "Lifeline"; //$NON-NLS-1$
45 // ------------------------------------------------------------------------
47 // ------------------------------------------------------------------------
49 * The lifeline position in the containing frame
51 private int fIndexInFrame
= 0;
53 * The frame where the lifeline is drawn
55 private Frame fFrame
= null;
57 * The current event occurrence created in the lifeline
59 private int fEventOccurrence
= 0;
61 * The lifeline category.
63 private int fCategory
= -1;
65 * Flag whether lifeline has time information available or not
67 private boolean fHasTimeInfo
= false;
69 // ------------------------------------------------------------------------
71 // ------------------------------------------------------------------------
76 setColorPrefId(ISDPreferences
.PREF_LIFELINE
);
79 // ------------------------------------------------------------------------
81 // ------------------------------------------------------------------------
85 return Metrics
.FRAME_H_MARGIN
+ Metrics
.LIFELINE_H_MAGIN
+ (fIndexInFrame
- 1) * Metrics
.swimmingLaneWidth();
90 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
;
94 public int getWidth() {
95 return Metrics
.getLifelineWidth();
99 public int getHeight() {
100 // Set room for two text lines
101 return Metrics
.getLifelineFontHeigth()/** 2 */
102 + 2 * Metrics
.LIFELINE_NAME_H_MARGIN
;
106 * Set the lifeline category for this lifeline.
108 * @param arrayIndex the index of the category to use
109 * @see Frame#setLifelineCategories(LifelineCategories[])
111 public void setCategory(int arrayIndex
) {
112 fCategory
= arrayIndex
;
116 * Gets the lifeline category for this lifeline.
118 * @return arrayIndex the index of the category to use
120 public int getCategory() {
125 * Returns the tooltip text for the lifeline. It is the combination between the category name(if any) and the
128 * @return the tooltip text
130 public String
getToolTipText() {
131 if (fCategory
>= 0) {
132 LifelineCategories
[] categories
= fFrame
.getLifelineCategories();
133 if (fCategory
< categories
.length
) {
134 return categories
[fCategory
].getName() + " " + getName(); //$NON-NLS-1$
137 return ""; //$NON-NLS-1$
141 * Returns the index of the first visible Execution Occurrence in the execution occurrence array.<br>
142 * Execution Occurrences are Y ordered in this array
144 * @return the first visible Execution Occurrence
146 public int getExecOccurrenceDrawIndex() {
147 if (!hasChildren()) {
150 if (getIndexes().get(BasicExecutionOccurrence
.EXEC_OCC_TAG
) != null) {
151 return getIndexes().get(BasicExecutionOccurrence
.EXEC_OCC_TAG
).intValue();
157 * Set the frame on which this lifeline must be drawn
162 protected void setFrame(Frame parentFrame
) {
163 fFrame
= parentFrame
;
165 fFrame
.setHasTimeInfo(true);
167 if (fFrame
.getMaxEventOccurrence() < getEventOccurrence() + 1) {
168 fFrame
.setMaxEventOccurrence(getEventOccurrence() + 1);
173 * Returns the frame which this lifeline is drawn
177 protected Frame
getFrame() {
182 * Set the lifeline position index in the containing frame
184 * @param index the lifeline X position
186 protected void setIndex(int index
) {
187 fIndexInFrame
= index
;
191 * Returns the lifeline position in de the containing frame
193 * @return the X position
195 public int getIndex() {
196 return fIndexInFrame
;
200 * Set the lifeline event occurrence to the value given in parameter This only change the current event occurrence,
201 * greater event created on this lifeline are still valid and usable. This also need to inform the frame of the
202 * operation mostly to store in the frame the greater event found in the diagram (used to determine the frame
205 * @param eventOcc the new current event occurrence
207 public void setCurrentEventOccurrence(int eventOcc
) {
208 if ((fFrame
!= null) && (fFrame
.getMaxEventOccurrence() < eventOcc
)) {
209 fFrame
.setMaxEventOccurrence(eventOcc
);
211 fEventOccurrence
= eventOcc
;
215 * Returns the last created event occurrence along the lifeline.
217 * @return the current event occurrence
219 public int getEventOccurrence() {
220 return fEventOccurrence
;
224 * Creates a new event occurrence along the lifeline.
226 * @return the new created event occurrence
228 public int getNewEventOccurrence() {
229 setCurrentEventOccurrence(fEventOccurrence
+ 1);
230 return fEventOccurrence
;
234 * Adds the execution occurrence given in parameter to the lifeline.<br>
235 * A Execution occurrence is never drawn in the frame instead it is added to a lifeline
237 * @param exec the execution occurrence to add
239 public void addExecution(BasicExecutionOccurrence exec
) {
240 exec
.setLifeline(this);
242 if ((fFrame
!= null) && (fFrame
.getMaxEventOccurrence() < exec
.getEndOccurrence())) {
243 fFrame
.setMaxEventOccurrence(exec
.getEndOccurrence());
248 * Set whether lifeline has time information available or not.
249 * @param value The value to set
251 protected void setTimeInfo(boolean value
) {
252 fHasTimeInfo
= value
;
253 if ((fFrame
!= null) && value
) {
254 fFrame
.setHasTimeInfo(value
);
259 * Returns true if at least one execution occurrence has time info.
261 * @return true if at least one execution occurrence has time info
263 public boolean hasTimeInfo() {
268 * Returns the list of execution occurrence on this lifeline.
270 * @return the execution occurrence list
272 public List
<GraphNode
> getExecutions() {
274 return getNodeMap().get(BasicExecutionOccurrence
.EXEC_OCC_TAG
);
276 return new ArrayList
<>();
280 public boolean contains(int xValue
, int yValue
) {
283 int width
= getWidth();
284 int height
= getHeight();
286 if (fFrame
== null) {
289 if (GraphNode
.contains(x
, y
, width
, height
, xValue
, yValue
)) {
292 if (GraphNode
.contains(x
+ Metrics
.getLifelineWidth() / 2 - Metrics
.EXECUTION_OCCURRENCE_WIDTH
/ 2, y
+ height
, Metrics
.EXECUTION_OCCURRENCE_WIDTH
, (Metrics
.getMessageFontHeigth() + Metrics
.getMessagesSpacing()) * fFrame
.getMaxEventOccurrence()
293 + Metrics
.LIFELINE_VB_MAGIN
- 4, xValue
, yValue
)) {
297 height
= Metrics
.getLifelineFontHeigth() + 2 * Metrics
.LIFELINE_HEARDER_TEXT_V_MARGIN
;
298 int hMargin
= (Metrics
.LIFELINE_VT_MAGIN
- height
) / 2;
301 if (fFrame
.getVisibleAreaY() < y
- height
- hMargin
) {
302 if (GraphNode
.contains(x
- Metrics
.LIFELINE_SPACING
/ 2 + 1, y
- height
- hMargin
, Metrics
.swimmingLaneWidth() - 2, height
+ 1, xValue
, yValue
)) {
306 if (GraphNode
.contains(x
- Metrics
.LIFELINE_SPACING
/ 2 + 1, fFrame
.getVisibleAreaY(), Metrics
.swimmingLaneWidth() - 2, height
, xValue
, yValue
)) {
311 if (getNodeAt(xValue
, yValue
) != null) {
318 * Returns the lifeline visibility for the given visible area
320 * @param vx The x coordinate of the visible area
321 * @param vy The y coordinate of the visible area
322 * @param vwidth The width of the visible area
323 * @param vheight The height of the visible area
324 * @return true if visible false otherwise
327 public boolean isVisible(int vx
, int vy
, int vwidth
, int vheight
) {
329 int width
= getWidth();
330 if (((x
>= vx
) && (x
<= vx
+ vwidth
)) || ((x
+ width
>= vx
) && (x
<= vx
))) {
337 * Draws the name within the graphical context.
339 * @param context The graphical context.
341 protected void drawName(IGC context
) {
342 ISDPreferences pref
= SDViewPref
.getInstance();
346 int height
= Metrics
.getLifelineHeaderFontHeigth() + 2 * Metrics
.LIFELINE_HEARDER_TEXT_V_MARGIN
;
347 int hMargin
= Metrics
.LIFELINE_VT_MAGIN
/ 4;// (Metrics.LIFELINE_NAME_H_MARGIN)/2;
349 context
.setLineStyle(context
.getLineSolidStyle());
350 context
.setBackground(pref
.getBackGroundColor(ISDPreferences
.PREF_LIFELINE_HEADER
));
351 context
.setForeground(pref
.getForeGroundColor(ISDPreferences
.PREF_LIFELINE_HEADER
));
352 context
.setFont(pref
.getFont(ISDPreferences
.PREF_LIFELINE_HEADER
));
354 if (fFrame
.getVisibleAreaY() < y
- height
- hMargin
) {
355 context
.fillRectangle(x
- Metrics
.LIFELINE_SPACING
/ 2 + 1, y
- height
- hMargin
, Metrics
.swimmingLaneWidth() - 2, height
);
356 context
.drawRectangle(x
- Metrics
.LIFELINE_SPACING
/ 2 + 1, y
- height
- hMargin
, Metrics
.swimmingLaneWidth() - 2, height
);
357 context
.setForeground(pref
.getFontColor(ISDPreferences
.PREF_LIFELINE_HEADER
));
358 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);
360 context
.fillRectangle(x
- Metrics
.LIFELINE_SPACING
/ 2 + 1, fFrame
.getVisibleAreaY(), Metrics
.swimmingLaneWidth() - 2, height
);
361 context
.drawRectangle(x
- Metrics
.LIFELINE_SPACING
/ 2 + 1, fFrame
.getVisibleAreaY(), Metrics
.swimmingLaneWidth() - 2, height
);
362 context
.setForeground(pref
.getFontColor(ISDPreferences
.PREF_LIFELINE_HEADER
));
363 context
.drawTextTruncatedCentred(getName(), x
- Metrics
.LIFELINE_SPACING
/ 2 + Metrics
.LIFELINE_NAME_V_MARGIN
+ 1, fFrame
.getVisibleAreaY(), Metrics
.swimmingLaneWidth() - 2 * Metrics
.LIFELINE_NAME_V_MARGIN
- 2, height
, true);
369 * Force the lifeline to be drawn at the given coordinate
371 * @param context - the context to draw into
372 * @param x - the x coordinate
373 * @param y - the y coordinate
375 public void draw(IGC context
, int x
, int y
) {
377 ISDPreferences pref
= SDViewPref
.getInstance();
379 // Set the draw color depending if the lifeline must be selected or not
380 context
.setLineWidth(Metrics
.NORMAL_LINE_WIDTH
);
382 if (pref
.useGradienColor()) {
383 context
.setGradientColor(pref
.getBackGroundColor(ISDPreferences
.PREF_LIFELINE
));
385 context
.setBackground(pref
.getBackGroundColorSelection());
386 context
.setForeground(pref
.getForeGroundColorSelection());
388 if (pref
.useGradienColor()) {
389 context
.setGradientColor(pref
.getBackGroundColor(ISDPreferences
.PREF_LIFELINE
));
390 context
.setBackground(pref
.getBackGroundColor(ISDPreferences
.PREF_FRAME
));
392 context
.setBackground(pref
.getBackGroundColor(ISDPreferences
.PREF_LIFELINE
));
394 context
.setForeground(pref
.getForeGroundColor(ISDPreferences
.PREF_LIFELINE
));
396 // Store the lifeline coordinates to save some calls
397 int width
= getWidth();
398 int height
= getHeight();
400 // Draw the rectangle which contain the lifeline name
401 if (pref
.useGradienColor()) {
402 context
.fillGradientRectangle(x
, y
, width
, height
/ 2 - 7, true);
403 context
.fillRectangle(x
, y
+ height
/ 2 - 8, width
, +height
/ 2 - 5);
404 context
.fillGradientRectangle(x
, y
+ height
, width
, -height
/ 2 + 6, true);
406 context
.fillRectangle(x
, y
, width
, height
);
408 context
.drawRectangle(x
, y
, width
, height
);
410 if (fCategory
>= 0) {
411 LifelineCategories
[] categories
= fFrame
.getLifelineCategories();
412 if (fCategory
< categories
.length
) {
413 IImage image
= categories
[fCategory
].getImage();
415 context
.drawImage(image
, x
, y
, width
, height
);
420 // Draw the lifeline label into the rectangle
421 // The label is truncated if it cannot fit
422 IColor temp
= context
.getForeground();
423 context
.setFont(pref
.getFont(ISDPreferences
.PREF_LIFELINE
));
424 context
.setForeground(pref
.getFontColor(ISDPreferences
.PREF_LIFELINE
));
425 context
.drawTextTruncatedCentred(getName(), x
+ Metrics
.LIFELINE_NAME_V_MARGIN
, y
, Metrics
.getLifelineWidth() - 2 * Metrics
.LIFELINE_NAME_V_MARGIN
, height
, true);
427 context
.setLineStyle(context
.getLineDashStyle());
428 context
.setForeground(temp
);
429 int oldStyle
= context
.getLineStyle();
431 // Now draw the lifeline vertical line
432 // this line height depends on a stop assignment
433 // if there is no stop the line is drawn to the bottom of the frame
435 // by default set the height to reach the frame bottom
436 int dashedLineEnd
= y
+ height
+ (Metrics
.getMessageFontHeigth() + Metrics
.getMessagesSpacing()) * fFrame
.getMaxEventOccurrence() + Metrics
.LIFELINE_VB_MAGIN
;
438 * if (stop != null) { dashedLineEnd = stop.getY(); }
442 context
.setForeground(pref
.getBackGroundColorSelection());
443 context
.setLineWidth(5);
444 context
.drawLine(x
+ Metrics
.getLifelineWidth() / 2, y
+ height
, x
+ Metrics
.getLifelineWidth() / 2, dashedLineEnd
- 4);
445 context
.setForeground(pref
.getForeGroundColorSelection());
448 context
.setLineWidth(Metrics
.NORMAL_LINE_WIDTH
);
449 context
.drawLine(x
+ Metrics
.getLifelineWidth() / 2, y
+ height
, x
+ Metrics
.getLifelineWidth() / 2, dashedLineEnd
- 4);
450 context
.drawLine(x
+ Metrics
.getLifelineWidth() / 2, y
+ height
, x
+ Metrics
.getLifelineWidth() / 2, dashedLineEnd
- 4);
451 context
.setLineStyle(oldStyle
);
453 context
.setLineStyle(context
.getLineSolidStyle());
459 super.drawChildenNodes(context
);
463 * Draws the select execution occurrence region using the given color
465 * @param context the graphical context
466 * @param startEvent the region start
467 * @param nbEvent the region height
468 * @param color the color to use
470 public void highlightExecOccurrenceRegion(IGC context
, int startEvent
, int nbEvent
, IColor color
) {
471 IColor backupColor
= context
.getBackground();
472 context
.setBackground(color
);
473 int x
= getX() + Metrics
.getLifelineWidth() / 2 - Metrics
.EXECUTION_OCCURRENCE_WIDTH
/ 2;
474 int y
= getY() + getHeight() + (Metrics
.getMessageFontHeigth() + Metrics
.getMessagesSpacing()) * startEvent
;
475 int width
= Metrics
.EXECUTION_OCCURRENCE_WIDTH
;
476 int height
= ((Metrics
.getMessageFontHeigth() + Metrics
.getMessagesSpacing())) * nbEvent
;
477 context
.fillRectangle(x
, y
, width
, height
);
478 context
.setBackground(backupColor
);
482 public void draw(IGC context
) {
483 draw(context
, getX(), getY());
487 public String
getArrayId() {
492 public boolean positiveDistanceToPoint(int x
, int y
) {
493 if (getX() > x
- Metrics
.swimmingLaneWidth()) {
500 public GraphNode
getNodeAt(int x
, int y
) {
503 if (getFrame() != null) {
504 vy
= getFrame().getVisibleAreaY();
505 vh
= getFrame().getVisibleAreaHeight();
509 if (getExecutions() == null) {
512 for (int i
= getExecOccurrenceDrawIndex(); i
< getExecutions().size(); i
++) {
513 GraphNode node
= getExecutions().get(i
);
514 if (node
.getHeight() < 0) {
515 if (node
.getY() + node
.getHeight() > vy
+ vh
) {
519 if (node
.getY() > vy
+ vh
) {
523 if (node
.contains(x
, y
)) {
524 GraphNode internal
= node
.getNodeAt(x
, y
);
525 if (internal
!= null) {