Commit | Line | Data |
---|---|---|
73005152 BH |
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 | * | |
0d9a6d76 | 173 | * @param eventOcc the new current event occurrence |
73005152 BH |
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 | |
0d9a6d76 FC |
319 | * @param x - the x coordinate |
320 | * @param y - the y coordinate | |
73005152 BH |
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 | } |