Add null-checks for Map.get()
[deliverable/tracecompass.git] / tmf / org.eclipse.tracecompass.tmf.ui / src / org / eclipse / tracecompass / tmf / ui / views / uml2sd / core / Lifeline.java
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
7 *
8 * Contributors:
9 * IBM - Initial API and implementation
10 * Bernd Hufmann - Updated for TMF
11 **********************************************************************/
12
13 package org.eclipse.tracecompass.tmf.ui.views.uml2sd.core;
14
15 import java.util.ArrayList;
16 import java.util.List;
17
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;
23
24 /**
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.
31 *
32 * @version 1.0
33 * @author sveyrier
34 *
35 */
36 public class Lifeline extends GraphNode {
37 // ------------------------------------------------------------------------
38 // Constants
39 // ------------------------------------------------------------------------
40 /**
41 * The life line tag.
42 */
43 public static final String LIFELINE_TAG = "Lifeline"; //$NON-NLS-1$
44
45 // ------------------------------------------------------------------------
46 // Attribute
47 // ------------------------------------------------------------------------
48 /**
49 * The lifeline position in the containing frame
50 */
51 private int fIndexInFrame = 0;
52 /**
53 * The frame where the lifeline is drawn
54 */
55 private Frame fFrame = null;
56 /**
57 * The current event occurrence created in the lifeline
58 */
59 private int fEventOccurrence = 0;
60 /**
61 * The lifeline category.
62 */
63 private int fCategory = -1;
64 /**
65 * Flag whether lifeline has time information available or not
66 */
67 private boolean fHasTimeInfo = false;
68
69 // ------------------------------------------------------------------------
70 // Constructors
71 // ------------------------------------------------------------------------
72 /**
73 * Default constructor
74 */
75 public Lifeline() {
76 setColorPrefId(ISDPreferences.PREF_LIFELINE);
77 }
78
79 // ------------------------------------------------------------------------
80 // Methods
81 // ------------------------------------------------------------------------
82
83 @Override
84 public int getX() {
85 return Metrics.FRAME_H_MARGIN + Metrics.LIFELINE_H_MAGIN + (fIndexInFrame - 1) * Metrics.swimmingLaneWidth();
86 }
87
88 @Override
89 public int getY() {
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;
91 }
92
93 @Override
94 public int getWidth() {
95 return Metrics.getLifelineWidth();
96 }
97
98 @Override
99 public int getHeight() {
100 // Set room for two text lines
101 return Metrics.getLifelineFontHeigth()/** 2 */
102 + 2 * Metrics.LIFELINE_NAME_H_MARGIN;
103 }
104
105 /**
106 * Set the lifeline category for this lifeline.
107 *
108 * @param arrayIndex the index of the category to use
109 * @see Frame#setLifelineCategories(LifelineCategories[])
110 */
111 public void setCategory(int arrayIndex) {
112 fCategory = arrayIndex;
113 }
114
115 /**
116 * Gets the lifeline category for this lifeline.
117 *
118 * @return arrayIndex the index of the category to use
119 */
120 public int getCategory() {
121 return fCategory;
122 }
123
124 /**
125 * Returns the tooltip text for the lifeline. It is the combination between the category name(if any) and the
126 * lifeline name
127 *
128 * @return the tooltip text
129 */
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$
135 }
136 }
137 return ""; //$NON-NLS-1$
138 }
139
140 /**
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
143 *
144 * @return the first visible Execution Occurrence
145 */
146 public int getExecOccurrenceDrawIndex() {
147 if (!hasChildren()) {
148 return 0;
149 }
150 Integer ret = getIndexes().get(BasicExecutionOccurrence.EXEC_OCC_TAG);
151 return (ret == null ? 0 : ret.intValue());
152 }
153
154 /**
155 * Set the frame on which this lifeline must be drawn
156 *
157 * @param parentFrame
158 * Parent frame
159 */
160 protected void setFrame(Frame parentFrame) {
161 fFrame = parentFrame;
162 if (fHasTimeInfo) {
163 fFrame.setHasTimeInfo(true);
164 }
165 if (fFrame.getMaxEventOccurrence() < getEventOccurrence() + 1) {
166 fFrame.setMaxEventOccurrence(getEventOccurrence() + 1);
167 }
168 }
169
170 /**
171 * Returns the frame which this lifeline is drawn
172 *
173 * @return the Frame
174 */
175 protected Frame getFrame() {
176 return fFrame;
177 }
178
179 /**
180 * Set the lifeline position index in the containing frame
181 *
182 * @param index the lifeline X position
183 */
184 protected void setIndex(int index) {
185 fIndexInFrame = index;
186 }
187
188 /**
189 * Returns the lifeline position in de the containing frame
190 *
191 * @return the X position
192 */
193 public int getIndex() {
194 return fIndexInFrame;
195 }
196
197 /**
198 * Set the lifeline event occurrence to the value given in parameter This only change the current event occurrence,
199 * greater event created on this lifeline are still valid and usable. This also need to inform the frame of the
200 * operation mostly to store in the frame the greater event found in the diagram (used to determine the frame
201 * height)
202 *
203 * @param eventOcc the new current event occurrence
204 */
205 public void setCurrentEventOccurrence(int eventOcc) {
206 if ((fFrame != null) && (fFrame.getMaxEventOccurrence() < eventOcc)) {
207 fFrame.setMaxEventOccurrence(eventOcc);
208 }
209 fEventOccurrence = eventOcc;
210 }
211
212 /**
213 * Returns the last created event occurrence along the lifeline.
214 *
215 * @return the current event occurrence
216 */
217 public int getEventOccurrence() {
218 return fEventOccurrence;
219 }
220
221 /**
222 * Creates a new event occurrence along the lifeline.
223 *
224 * @return the new created event occurrence
225 */
226 public int getNewEventOccurrence() {
227 setCurrentEventOccurrence(fEventOccurrence + 1);
228 return fEventOccurrence;
229 }
230
231 /**
232 * Adds the execution occurrence given in parameter to the lifeline.<br>
233 * A Execution occurrence is never drawn in the frame instead it is added to a lifeline
234 *
235 * @param exec the execution occurrence to add
236 */
237 public void addExecution(BasicExecutionOccurrence exec) {
238 exec.setLifeline(this);
239 addNode(exec);
240 if ((fFrame != null) && (fFrame.getMaxEventOccurrence() < exec.getEndOccurrence())) {
241 fFrame.setMaxEventOccurrence(exec.getEndOccurrence());
242 }
243 }
244
245 /**
246 * Set whether lifeline has time information available or not.
247 * @param value The value to set
248 */
249 protected void setTimeInfo(boolean value) {
250 fHasTimeInfo = value;
251 if ((fFrame != null) && value) {
252 fFrame.setHasTimeInfo(value);
253 }
254 }
255
256 /**
257 * Returns true if at least one execution occurrence has time info.
258 *
259 * @return true if at least one execution occurrence has time info
260 */
261 public boolean hasTimeInfo() {
262 return fHasTimeInfo;
263 }
264
265 /**
266 * Returns the list of execution occurrence on this lifeline.
267 *
268 * @return the execution occurrence list
269 */
270 public List<GraphNode> getExecutions() {
271 if (hasChildren()) {
272 return getNodeMap().get(BasicExecutionOccurrence.EXEC_OCC_TAG);
273 }
274 return new ArrayList<>();
275 }
276
277 @Override
278 public boolean contains(int xValue, int yValue) {
279 int x = getX();
280 int y = getY();
281 int width = getWidth();
282 int height = getHeight();
283
284 if (fFrame == null) {
285 return false;
286 }
287 if (GraphNode.contains(x, y, width, height, xValue, yValue)) {
288 return true;
289 }
290 if (GraphNode.contains(x + Metrics.getLifelineWidth() / 2 - Metrics.EXECUTION_OCCURRENCE_WIDTH / 2, y + height, Metrics.EXECUTION_OCCURRENCE_WIDTH, (Metrics.getMessageFontHeigth() + Metrics.getMessagesSpacing()) * fFrame.getMaxEventOccurrence()
291 + Metrics.LIFELINE_VB_MAGIN - 4, xValue, yValue)) {
292 return true;
293 }
294
295 height = Metrics.getLifelineFontHeigth() + 2 * Metrics.LIFELINE_HEARDER_TEXT_V_MARGIN;
296 int hMargin = (Metrics.LIFELINE_VT_MAGIN - height) / 2;
297
298 if (hMargin >= 2) {
299 if (fFrame.getVisibleAreaY() < y - height - hMargin) {
300 if (GraphNode.contains(x - Metrics.LIFELINE_SPACING / 2 + 1, y - height - hMargin, Metrics.swimmingLaneWidth() - 2, height + 1, xValue, yValue)) {
301 return true;
302 }
303 } else {
304 if (GraphNode.contains(x - Metrics.LIFELINE_SPACING / 2 + 1, fFrame.getVisibleAreaY(), Metrics.swimmingLaneWidth() - 2, height, xValue, yValue)) {
305 return true;
306 }
307 }
308 }
309 if (getNodeAt(xValue, yValue) != null) {
310 return true;
311 }
312 return false;
313 }
314
315 /**
316 * Returns the lifeline visibility for the given visible area
317 *
318 * @param vx The x coordinate of the visible area
319 * @param vy The y coordinate of the visible area
320 * @param vwidth The width of the visible area
321 * @param vheight The height of the visible area
322 * @return true if visible false otherwise
323 */
324 @Override
325 public boolean isVisible(int vx, int vy, int vwidth, int vheight) {
326 int x = getX();
327 int width = getWidth();
328 if (((x >= vx) && (x <= vx + vwidth)) || ((x + width >= vx) && (x <= vx))) {
329 return true;
330 }
331 return false;
332 }
333
334 /**
335 * Draws the name within the graphical context.
336 *
337 * @param context The graphical context.
338 */
339 protected void drawName(IGC context) {
340 ISDPreferences pref = SDViewPref.getInstance();
341
342 int x = getX();
343 int y = getY();
344 int height = Metrics.getLifelineHeaderFontHeigth() + 2 * Metrics.LIFELINE_HEARDER_TEXT_V_MARGIN;
345 int hMargin = Metrics.LIFELINE_VT_MAGIN / 4;// (Metrics.LIFELINE_NAME_H_MARGIN)/2;
346
347 context.setLineStyle(context.getLineSolidStyle());
348 context.setBackground(pref.getBackGroundColor(ISDPreferences.PREF_LIFELINE_HEADER));
349 context.setForeground(pref.getForeGroundColor(ISDPreferences.PREF_LIFELINE_HEADER));
350 context.setFont(pref.getFont(ISDPreferences.PREF_LIFELINE_HEADER));
351 if (hMargin >= 0) {
352 if (fFrame.getVisibleAreaY() < y - height - hMargin) {
353 context.fillRectangle(x - Metrics.LIFELINE_SPACING / 2 + 1, y - height - hMargin, Metrics.swimmingLaneWidth() - 2, height);
354 context.drawRectangle(x - Metrics.LIFELINE_SPACING / 2 + 1, y - height - hMargin, Metrics.swimmingLaneWidth() - 2, height);
355 context.setForeground(pref.getFontColor(ISDPreferences.PREF_LIFELINE_HEADER));
356 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);
357 } else {
358 context.fillRectangle(x - Metrics.LIFELINE_SPACING / 2 + 1, fFrame.getVisibleAreaY(), Metrics.swimmingLaneWidth() - 2, height);
359 context.drawRectangle(x - Metrics.LIFELINE_SPACING / 2 + 1, fFrame.getVisibleAreaY(), Metrics.swimmingLaneWidth() - 2, height);
360 context.setForeground(pref.getFontColor(ISDPreferences.PREF_LIFELINE_HEADER));
361 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);
362 }
363 }
364 }
365
366 /**
367 * Force the lifeline to be drawn at the given coordinate
368 *
369 * @param context - the context to draw into
370 * @param x - the x coordinate
371 * @param y - the y coordinate
372 */
373 public void draw(IGC context, int x, int y) {
374
375 ISDPreferences pref = SDViewPref.getInstance();
376
377 // Set the draw color depending if the lifeline must be selected or not
378 context.setLineWidth(Metrics.NORMAL_LINE_WIDTH);
379 if (isSelected()) {
380 if (pref.useGradienColor()) {
381 context.setGradientColor(pref.getBackGroundColor(ISDPreferences.PREF_LIFELINE));
382 }
383 context.setBackground(pref.getBackGroundColorSelection());
384 context.setForeground(pref.getForeGroundColorSelection());
385 } else {
386 if (pref.useGradienColor()) {
387 context.setGradientColor(pref.getBackGroundColor(ISDPreferences.PREF_LIFELINE));
388 context.setBackground(pref.getBackGroundColor(ISDPreferences.PREF_FRAME));
389 } else {
390 context.setBackground(pref.getBackGroundColor(ISDPreferences.PREF_LIFELINE));
391 }
392 context.setForeground(pref.getForeGroundColor(ISDPreferences.PREF_LIFELINE));
393 }
394 // Store the lifeline coordinates to save some calls
395 int width = getWidth();
396 int height = getHeight();
397
398 // Draw the rectangle which contain the lifeline name
399 if (pref.useGradienColor()) {
400 context.fillGradientRectangle(x, y, width, height / 2 - 7, true);
401 context.fillRectangle(x, y + height / 2 - 8, width, +height / 2 - 5);
402 context.fillGradientRectangle(x, y + height, width, -height / 2 + 6, true);
403 } else {
404 context.fillRectangle(x, y, width, height);
405 }
406 context.drawRectangle(x, y, width, height);
407
408 if (fCategory >= 0) {
409 LifelineCategories[] categories = fFrame.getLifelineCategories();
410 if (fCategory < categories.length) {
411 IImage image = categories[fCategory].getImage();
412 if (image != null) {
413 context.drawImage(image, x, y, width, height);
414 }
415 }
416 }
417
418 // Draw the lifeline label into the rectangle
419 // The label is truncated if it cannot fit
420 IColor temp = context.getForeground();
421 context.setFont(pref.getFont(ISDPreferences.PREF_LIFELINE));
422 context.setForeground(pref.getFontColor(ISDPreferences.PREF_LIFELINE));
423 context.drawTextTruncatedCentred(getName(), x + Metrics.LIFELINE_NAME_V_MARGIN, y, Metrics.getLifelineWidth() - 2 * Metrics.LIFELINE_NAME_V_MARGIN, height, true);
424
425 context.setLineStyle(context.getLineDashStyle());
426 context.setForeground(temp);
427 int oldStyle = context.getLineStyle();
428
429 // Now draw the lifeline vertical line
430 // this line height depends on a stop assignment
431 // if there is no stop the line is drawn to the bottom of the frame
432
433 // by default set the height to reach the frame bottom
434 int dashedLineEnd = y + height + (Metrics.getMessageFontHeigth() + Metrics.getMessagesSpacing()) * fFrame.getMaxEventOccurrence() + Metrics.LIFELINE_VB_MAGIN;
435 /*
436 * if (stop != null) { dashedLineEnd = stop.getY(); }
437 */
438
439 if (isSelected()) {
440 context.setForeground(pref.getBackGroundColorSelection());
441 context.setLineWidth(5);
442 context.drawLine(x + Metrics.getLifelineWidth() / 2, y + height, x + Metrics.getLifelineWidth() / 2, dashedLineEnd - 4);
443 context.setForeground(pref.getForeGroundColorSelection());
444 }
445
446 context.setLineWidth(Metrics.NORMAL_LINE_WIDTH);
447 context.drawLine(x + Metrics.getLifelineWidth() / 2, y + height, x + Metrics.getLifelineWidth() / 2, dashedLineEnd - 4);
448 context.drawLine(x + Metrics.getLifelineWidth() / 2, y + height, x + Metrics.getLifelineWidth() / 2, dashedLineEnd - 4);
449 context.setLineStyle(oldStyle);
450
451 context.setLineStyle(context.getLineSolidStyle());
452
453 if (hasFocus()) {
454 drawFocus(context);
455 }
456
457 super.drawChildenNodes(context);
458 }
459
460 /**
461 * Draws the select execution occurrence region using the given color
462 *
463 * @param context the graphical context
464 * @param startEvent the region start
465 * @param nbEvent the region height
466 * @param color the color to use
467 */
468 public void highlightExecOccurrenceRegion(IGC context, int startEvent, int nbEvent, IColor color) {
469 IColor backupColor = context.getBackground();
470 context.setBackground(color);
471 int x = getX() + Metrics.getLifelineWidth() / 2 - Metrics.EXECUTION_OCCURRENCE_WIDTH / 2;
472 int y = getY() + getHeight() + (Metrics.getMessageFontHeigth() + Metrics.getMessagesSpacing()) * startEvent;
473 int width = Metrics.EXECUTION_OCCURRENCE_WIDTH;
474 int height = ((Metrics.getMessageFontHeigth() + Metrics.getMessagesSpacing())) * nbEvent;
475 context.fillRectangle(x, y, width, height);
476 context.setBackground(backupColor);
477 }
478
479 @Override
480 public void draw(IGC context) {
481 draw(context, getX(), getY());
482 }
483
484 @Override
485 public String getArrayId() {
486 return LIFELINE_TAG;
487 }
488
489 @Override
490 public boolean positiveDistanceToPoint(int x, int y) {
491 if (getX() > x - Metrics.swimmingLaneWidth()) {
492 return true;
493 }
494 return false;
495 }
496
497 @Override
498 public GraphNode getNodeAt(int x, int y) {
499 int vy = 0;
500 int vh = 0;
501 if (getFrame() != null) {
502 vy = getFrame().getVisibleAreaY();
503 vh = getFrame().getVisibleAreaHeight();
504 } else {
505 return null;
506 }
507 if (getExecutions() == null) {
508 return null;
509 }
510 for (int i = getExecOccurrenceDrawIndex(); i < getExecutions().size(); i++) {
511 GraphNode node = getExecutions().get(i);
512 if (node.getHeight() < 0) {
513 if (node.getY() + node.getHeight() > vy + vh) {
514 break;
515 }
516 } else {
517 if (node.getY() > vy + vh) {
518 break;
519 }
520 }
521 if (node.contains(x, y)) {
522 GraphNode internal = node.getNodeAt(x, y);
523 if (internal != null) {
524 return internal;
525 }
526 return node;
527 }
528 }
529 return null;
530 }
531 }
This page took 0.065745 seconds and 5 git commands to generate.