Contribution for Bug352466: [TMF] Implement UML2 Sequence Diagram
[deliverable/tracecompass.git] / org.eclipse.linuxtools.tmf.ui / src / org / eclipse / linuxtools / tmf / ui / views / uml2sd / core / Lifeline.java
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 $
8 *
9 * Contributors:
10 * IBM - Initial API and implementation
11 * Bernd Hufmann - Updated for TMF
12 **********************************************************************/
13 package org.eclipse.linuxtools.tmf.ui.views.uml2sd.core;
14
15 import java.util.ArrayList;
16 import java.util.List;
17
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;
22
23 /**
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.
30 *
31 * @author sveyrier
32 *
33 */
34 public class Lifeline extends GraphNode {
35
36 /**
37 * The lifeline position in the containing frame
38 */
39 protected int indexInFrame = 0;
40
41 /**
42 * The frame where the lifeline is drawn
43 */
44 protected Frame frame = null;
45
46 /**
47 * The current event occurrence created in the lifeline
48 */
49 protected int eventOccurrence = 0;
50
51 public static final String LIFELINE_TAG = "Lifeline"; //$NON-NLS-1$
52
53 protected int category = -1;
54
55 protected boolean hasTime = false;
56
57 @Override
58 public int getX() {
59 return Metrics.FRAME_H_MARGIN + Metrics.LIFELINE_H_MAGIN + (indexInFrame - 1) * Metrics.swimmingLaneWidth();
60 }
61
62 @Override
63 public int getY() {
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;
65 }
66
67 @Override
68 public int getWidth() {
69 return Metrics.getLifelineWidth();
70 }
71
72 @Override
73 public int getHeight() {
74 // Set room for two text lines
75 return Metrics.getLifelineFontHeigth()/** 2 */
76 + 2 * Metrics.LIFELINE_NAME_H_MARGIN;
77 }
78
79 public Lifeline() {
80 prefId = ISDPreferences.PREF_LIFELINE;
81 }
82
83 /**
84 * Set the lifeline category for this lifeline.
85 *
86 * @param arrayIndex the index of the category to use
87 * @see Frame#setLifelineCategories(LifelineCategories[])
88 */
89 public void setCategory(int arrayIndex) {
90 category = arrayIndex;
91 }
92
93 /**
94 * Returns the tooltip text for the lifeline. It is the combination between the category name(if any) and the
95 * lifeline name
96 *
97 * @return the tooltip text
98 */
99 public String getToolTipText() {
100 if (category >= 0) {
101 LifelineCategories[] categories = frame.getLifelineCategories();
102 if (category < categories.length) {
103 return categories[category].getName() + " " + getName(); //$NON-NLS-1$
104 } else
105 return ""; //$NON-NLS-1$
106 } else
107 return ""; //$NON-NLS-1$
108 }
109
110 /**
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
113 *
114 * @return the first visible Execution Occurrence
115 */
116 public int getExecOccurrenceDrawIndex() {
117 if (!hasChilden)
118 return 0;
119 if (indexes.get(BasicExecutionOccurrence.EXEC_OCC_TAG) != null)
120 return ((Integer) indexes.get(BasicExecutionOccurrence.EXEC_OCC_TAG)).intValue();
121 else
122 return 0;
123 }
124
125 /**
126 * Set the frame on which this lifeline must be drawn
127 *
128 * @param parentFrame
129 */
130 protected void setFrame(Frame parentFrame) {
131 frame = parentFrame;
132 if (hasTime) {
133 frame.setHasTimeInfo(true);
134 }
135 if (frame.getMaxEventOccurrence() < getEventOccurrence() + 1)
136 frame.setMaxEventOccurrence(getEventOccurrence() + 1);
137 }
138
139 /**
140 * Returns the frame which this lifeline is drawn
141 *
142 * @return the Frame
143 */
144 protected Frame getFrame() {
145 return frame;
146 }
147
148 /**
149 * Set the lifeline position index in the containing frame
150 *
151 * @param index the lifeline X position
152 */
153
154 protected void setIndex(int index) {
155 indexInFrame = index;
156 }
157
158 /**
159 * Returns the lifeline position in de the containing frame
160 *
161 * @return the X position
162 */
163 public int getIndex() {
164 return indexInFrame;
165 }
166
167 /**
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
171 * height)
172 *
173 * @param index the new current event occurrence
174 */
175 public void setCurrentEventOccurrence(int eventOcc) {
176 if ((frame != null) && (frame.getMaxEventOccurrence() < eventOcc))
177 frame.setMaxEventOccurrence(eventOcc);
178 eventOccurrence = eventOcc;
179 }
180
181 /**
182 * Returns the last created event occurrence along the lifeline.
183 *
184 * @return the current event occurrence
185 */
186 public int getEventOccurrence() {
187 return eventOccurrence;
188 }
189
190 /**
191 * Creates a new event occurrence along the lifeline.
192 *
193 * @return the new created event occurrence
194 */
195 public int getNewEventOccurrence() {
196 setCurrentEventOccurrence(eventOccurrence + 1);
197 return eventOccurrence;
198 }
199
200 /**
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
203 *
204 * @param exec the execution occurrence to add
205 */
206 public void addExecution(BasicExecutionOccurrence exec) {
207 exec.setLifeline(this);
208 addNode(exec);
209 if ((frame != null) && (frame.getMaxEventOccurrence() < exec.endEventOccurrence))
210 frame.setMaxEventOccurrence(exec.endEventOccurrence);
211 }
212
213 protected void setTimeInfo(boolean value) {
214 hasTime = value;
215 if ((frame != null) && (value == true))
216 frame.setHasTimeInfo(value);
217 }
218
219 /**
220 * @return true if at least one execution occurrence has time info
221 */
222 public boolean hasTimeInfo() {
223 return hasTime;
224 }
225
226 /**
227 * Returns the list of execution occurrence on this lifeline
228 *
229 * @return the execution occurrence list
230 */
231 public List<GraphNode> getExecutions() {
232 if (hasChilden)
233 return (List<GraphNode>) nodes.get(BasicExecutionOccurrence.EXEC_OCC_TAG);
234 else
235 return new ArrayList<GraphNode>();
236 }
237
238 @Override
239 public boolean contains(int _x, int _y) {
240 int x = getX();
241 int y = getY();
242 int width = getWidth();
243 int height = getHeight();
244
245 if (frame == null)
246 return false;
247 if (Frame.contains(x, y, width, height, _x, _y)) {
248 return true;
249 }
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)) {
252 return true;
253 }
254
255 height = Metrics.getLifelineFontHeigth() + 2 * Metrics.LIFELINE_HEARDER_TEXT_V_MARGIN;
256 int hMargin = (Metrics.LIFELINE_VT_MAGIN - height) / 2;
257
258 if (hMargin >= 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))
261 return true;
262 } else {
263 if (Frame.contains(x - Metrics.LIFELINE_SPACING / 2 + 1, frame.getVisibleAreaY(), Metrics.swimmingLaneWidth() - 2, height, _x, _y))
264 return true;
265 }
266 }
267 if (getNodeAt(_x, _y) != null)
268 return true;
269 return false;
270 }
271
272 /**
273 * Returns the lifeline visibility for the given visible area
274 *
275 * @param vx
276 * @param vy
277 * @param vwidth
278 * @param vheight
279 * @return true if visible false otherwise
280 */
281 @Override
282 public boolean isVisible(int vx, int vy, int vwidth, int vheight) {
283 int x = getX();
284 int width = getWidth();
285 if (((x >= vx) && (x <= vx + vwidth)) || ((x + width >= vx) && (x <= vx)))
286 return true;
287 return false;
288 }
289
290 protected void drawName(IGC context) {
291 int x = getX();
292 int y = getY();
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;
295
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));
300 if (hMargin >= 0) {
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);
306 } else {
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);
311 }
312 }
313 }
314
315 /**
316 * Force the lifeline to be drawn at the given coordinate
317 *
318 * @param context - the context to draw into
319 * @param x1 - the x coordinate
320 * @param y1 - the y coordinate
321 */
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);
325 if (isSelected()) {
326 if (Frame.getUserPref().useGradienColor()) {
327 context.setGradientColor(Frame.getUserPref().getBackGroundColor(ISDPreferences.PREF_LIFELINE));
328 }
329 context.setBackground(Frame.getUserPref().getBackGroundColorSelection());
330 context.setForeground(Frame.getUserPref().getForeGroundColorSelection());
331 } else {
332 if (Frame.getUserPref().useGradienColor()) {
333 context.setGradientColor(Frame.getUserPref().getBackGroundColor(ISDPreferences.PREF_LIFELINE));
334 context.setBackground(Frame.getUserPref().getBackGroundColor(ISDPreferences.PREF_FRAME));
335 } else
336 context.setBackground(Frame.getUserPref().getBackGroundColor(ISDPreferences.PREF_LIFELINE));
337 context.setForeground(Frame.getUserPref().getForeGroundColor(ISDPreferences.PREF_LIFELINE));
338 }
339 // Store the lifeline coordinates to save some calls
340 int width = getWidth();
341 int height = getHeight();
342
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);
348 } else
349 context.fillRectangle(x, y, width, height);
350 context.drawRectangle(x, y, width, height);
351
352 if (category >= 0) {
353 LifelineCategories[] categories = frame.getLifelineCategories();
354 if (category < categories.length) {
355 IImage image = categories[category].getImage();
356 if (image != null)
357 context.drawImage(image, x, y, width, height);
358 }
359 }
360
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);
367
368 context.setLineStyle(context.getLineDashStyle());
369 context.setForeground(temp);
370 int oldStyle = context.getLineStyle();
371
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
375
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;
378 /*
379 * if (stop != null) { dashedLineEnd = stop.getY(); }
380 */
381
382 if (isSelected()) {
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());
387 }
388
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);
393
394 context.setLineStyle(context.getLineSolidStyle());
395
396 if (hasFocus())
397 drawFocus(context);
398
399 super.drawChildenNodes(context);
400 }
401
402 /**
403 * Draws the select execution occurrence region using the given color
404 *
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
409 */
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);
419 }
420
421 @Override
422 public void draw(IGC context) {
423 draw(context, getX(), getY());
424 }
425
426 @Override
427 public String getArrayId() {
428 return LIFELINE_TAG;
429 }
430
431 @Override
432 public boolean positiveDistanceToPoint(int x, int y) {
433 if (getX() > x - Metrics.swimmingLaneWidth())
434 return true;
435 return false;
436 }
437
438 @Override
439 public GraphNode getNodeAt(int x, int y) {
440 int vy = 0;
441 int vh = 0;
442 if (getFrame() != null) {
443 vy = getFrame().getVisibleAreaY();
444 vh = getFrame().getVisibleAreaHeight();
445 } else
446 return null;
447 if (getExecutions() == null)
448 return 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)
453 break;
454 } else {
455 if (node.getY() > vy + vh)
456 break;
457 }
458 if (node.contains(x, y)) {
459 GraphNode internal = node.getNodeAt(x, y);
460 if (internal != null)
461 return internal;
462 else
463 return node;
464 }
465 }
466 return null;
467 }
468 }
This page took 0.044082 seconds and 6 git commands to generate.