Commit | Line | Data |
---|---|---|
73005152 | 1 | /********************************************************************** |
11252342 | 2 | * Copyright (c) 2005, 2013 IBM Corporation, Ericsson |
73005152 BH |
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 | |
abbdd66a AM |
7 | * |
8 | * Contributors: | |
c8422608 AM |
9 | * IBM - Initial API and implementation |
10 | * Bernd Hufmann - Updated for TMF | |
73005152 | 11 | **********************************************************************/ |
c8422608 | 12 | |
2bdf0193 | 13 | package org.eclipse.tracecompass.tmf.ui.views.uml2sd.core; |
73005152 | 14 | |
2bdf0193 AM |
15 | import org.eclipse.tracecompass.tmf.ui.views.uml2sd.drawings.IColor; |
16 | import org.eclipse.tracecompass.tmf.ui.views.uml2sd.drawings.IGC; | |
17 | import org.eclipse.tracecompass.tmf.ui.views.uml2sd.preferences.ISDPreferences; | |
18 | import org.eclipse.tracecompass.tmf.ui.views.uml2sd.preferences.SDViewPref; | |
73005152 BH |
19 | |
20 | /** | |
21 | * The base UML2 syncMessages implementation.<br> | |
22 | * This abstract class only define one event occurrence to attach to the message.<br> | |
23 | * Usually a message has two event occurrences attached, one for both ends. But some syncMessages(like synchronous | |
24 | * syncMessages) only need one event occurrence to represent the time when they appear. Others kind of message | |
25 | * representations (like asynchronous syncMessages) will be responsible to define the missing second eventOccurrence | |
26 | * property.<br> | |
27 | * <br> | |
abbdd66a | 28 | * |
73005152 | 29 | * @see Lifeline Lifeline for more event occurence details |
df0b8ff4 | 30 | * @version 1.0 |
73005152 BH |
31 | * @author sveyrier |
32 | */ | |
33 | public abstract class BaseMessage extends GraphNode { | |
abbdd66a | 34 | |
df0b8ff4 BH |
35 | // ------------------------------------------------------------------------ |
36 | // Attributes | |
37 | // ------------------------------------------------------------------------ | |
73005152 BH |
38 | /** |
39 | * The lifeline which send the message | |
40 | */ | |
cab6c8ff | 41 | private Lifeline fStartLifeline = null; |
73005152 BH |
42 | /** |
43 | * The lifeline which receive the message | |
44 | */ | |
cab6c8ff | 45 | private Lifeline fEndLifeline = null; |
df0b8ff4 | 46 | /** |
abbdd66a | 47 | * The visiblitiy flag. |
df0b8ff4 | 48 | */ |
cab6c8ff | 49 | private boolean fVisible = true; |
73005152 | 50 | |
df0b8ff4 BH |
51 | // ------------------------------------------------------------------------ |
52 | // Methods | |
53 | // ------------------------------------------------------------------------ | |
11252342 | 54 | |
73005152 BH |
55 | @Override |
56 | public int getX() { | |
57 | // returns the exact x coordinate | |
58 | return getX(false); | |
59 | } | |
60 | ||
61 | @Override | |
62 | public int getY() { | |
63 | /* | |
64 | * Note: lifeline.getY() return the y coordinate of the top left corner of the rectangle which contain the | |
65 | * lifeline name getHeight return the height of this rectangle The message y coordinate is then relative to this | |
66 | * position depending of its eventOccurrence Space between syncMessages is constant | |
67 | */ | |
eb63f5ff | 68 | if ((fStartLifeline != null) && (fEndLifeline != null)) { |
73005152 BH |
69 | /* |
70 | * Regular message, both ends are attached to a lifeline | |
71 | */ | |
cab6c8ff | 72 | return fEndLifeline.getY() + fEndLifeline.getHeight() + (Metrics.getMessageFontHeigth() + Metrics.getMessagesSpacing()) * getEndOccurrence(); |
73005152 | 73 | |
abbdd66a AM |
74 | } |
75 | /* | |
76 | * UML2 lost message kind | |
77 | */ | |
78 | if (fStartLifeline != null) { | |
cab6c8ff | 79 | return fStartLifeline.getY() + fStartLifeline.getHeight() + (Metrics.getMessageFontHeigth() + Metrics.getMessagesSpacing()) * getEndOccurrence(); |
abbdd66a | 80 | } |
73005152 | 81 | |
abbdd66a AM |
82 | /* |
83 | * UML2 found message kind | |
84 | */ | |
85 | if (fEndLifeline != null) { | |
cab6c8ff | 86 | return fEndLifeline.getY() + fEndLifeline.getHeight() + (Metrics.getMessageFontHeigth() + Metrics.getMessagesSpacing()) * getEndOccurrence(); |
73005152 BH |
87 | } |
88 | // return 0 by default | |
89 | return 0; | |
90 | } | |
91 | ||
92 | @Override | |
93 | public int getWidth() { | |
94 | // Returns the exact width | |
95 | return getWidth(false); | |
96 | } | |
97 | ||
98 | @Override | |
99 | public int getHeight() { | |
100 | return 0; | |
101 | } | |
102 | ||
103 | /** | |
104 | * Returns the graph node x coordinate.<br> | |
105 | * Depending on the quick parameter a approximative or exact value is return.<br> | |
106 | * The approximative value does not take into account if both message ends are connected to a Lifeline Execution | |
107 | * Occurrence.<br> | |
108 | * Execution occurrence on a lifeline increase the vertical line width which represent the lifeline, this directly | |
109 | * affect the message x coordinate and width.<br> | |
110 | * <br> | |
111 | * This method is typically used to faster execute none graphical operation like tooltip lookup.<br> | |
112 | * <br> | |
abbdd66a | 113 | * |
73005152 BH |
114 | * @param quick true to get an approximative value<br> |
115 | * false to get the exact x value<br> | |
116 | * @return the graph node x coordinate | |
117 | */ | |
118 | protected int getX(boolean quick) { | |
119 | int x = 0; | |
120 | int activationWidth = Metrics.EXECUTION_OCCURRENCE_WIDTH / 2; | |
eb63f5ff BH |
121 | if ((fStartLifeline != null) && (fEndLifeline != null)) { |
122 | x = fStartLifeline.getX() + Metrics.getLifelineWidth() / 2; | |
73005152 | 123 | } else { |
eb63f5ff BH |
124 | if (fStartLifeline != null) { |
125 | x = fStartLifeline.getX() + Metrics.getLifelineWidth() / 2; | |
73005152 BH |
126 | } |
127 | ||
eb63f5ff BH |
128 | if (fEndLifeline != null) { |
129 | x = fEndLifeline.getX() - Metrics.LIFELINE_SPACING / 2; | |
73005152 BH |
130 | } |
131 | } | |
132 | ||
df0b8ff4 | 133 | if (quick) { |
73005152 | 134 | return x; |
df0b8ff4 | 135 | } |
73005152 | 136 | |
eb63f5ff | 137 | if ((fStartLifeline != null) && (fEndLifeline != null) && (fStartLifeline.getX() > fEndLifeline.getX())) { |
73005152 BH |
138 | activationWidth = -activationWidth; |
139 | } | |
140 | ||
cab6c8ff | 141 | if (isMessageStartInActivation(getEndOccurrence())) { |
73005152 BH |
142 | x = x + activationWidth; |
143 | } | |
144 | ||
145 | return x; | |
146 | } | |
147 | ||
148 | /** | |
149 | * Returns the graph node width.<br> | |
150 | * Depending on the quick parameter a approximative or exact value is returned.<br> | |
151 | * The approximative value does not take into account if both message ends are connected to a Lifeline Execution | |
152 | * Occurrence.<br> | |
153 | * Execution occurrence on a lifeline increase the vertical line width which represent the lifeline, this directly | |
154 | * affect the message x coordinate and width.<br> | |
155 | * <br> | |
156 | * This method is typically used to faster execute none graphical operation like tooltip lookup.<br> | |
157 | * <br> | |
abbdd66a | 158 | * |
73005152 BH |
159 | * @param quick true to get an approximative value<br> |
160 | * false to get the exact x value | |
161 | * @return the graph node width | |
162 | */ | |
163 | protected int getWidth(boolean quick) { | |
164 | int width = 0; | |
165 | int activationWidth = Metrics.EXECUTION_OCCURRENCE_WIDTH / 2; | |
eb63f5ff BH |
166 | if ((fStartLifeline != null) && (fEndLifeline != null)) { |
167 | if (fStartLifeline == fEndLifeline) { | |
73005152 | 168 | width = Metrics.INTERNAL_MESSAGE_WIDTH + Metrics.EXECUTION_OCCURRENCE_WIDTH; |
df0b8ff4 | 169 | } else { |
eb63f5ff | 170 | width = fEndLifeline.getX() + Metrics.getLifelineWidth() / 2 - getX(true); |
df0b8ff4 | 171 | } |
73005152 | 172 | } else { |
eb63f5ff | 173 | if (fStartLifeline != null) { |
73005152 BH |
174 | width = Metrics.swimmingLaneWidth() / 2; |
175 | } | |
eb63f5ff | 176 | if (fEndLifeline != null) { |
73005152 BH |
177 | width = Metrics.swimmingLaneWidth() / 2; |
178 | } | |
179 | } | |
180 | ||
df0b8ff4 | 181 | if (quick) { |
73005152 | 182 | return width; |
df0b8ff4 | 183 | } |
73005152 | 184 | |
eb63f5ff | 185 | if ((fStartLifeline != null) && (fEndLifeline != null) && (fStartLifeline.getX() > fEndLifeline.getX())) { |
73005152 BH |
186 | activationWidth = -activationWidth; |
187 | } | |
188 | ||
cab6c8ff | 189 | if (isMessageStartInActivation(getEndOccurrence())) { |
73005152 | 190 | width = width - activationWidth; |
df0b8ff4 | 191 | } |
73005152 | 192 | |
cab6c8ff | 193 | if (isMessageEndInActivation(getEndOccurrence())) { |
73005152 | 194 | width = width - activationWidth; |
df0b8ff4 | 195 | } |
73005152 BH |
196 | |
197 | return width; | |
198 | } | |
199 | ||
200 | @Override | |
201 | public boolean isVisible(int x, int y, int width, int height) { | |
202 | // ***Common*** syncMessages visibility | |
203 | // draw the message only if at least one end is visible | |
eb63f5ff | 204 | if (fEndLifeline != null && (fEndLifeline.isVisible(x, y, width, height)) || (fStartLifeline != null && fStartLifeline.isVisible(x, y, width, height))) { |
73005152 | 205 | return true; |
df0b8ff4 | 206 | } |
73005152 | 207 | // In this case it can be a message which cross the whole visible area |
eb63f5ff BH |
208 | else if (fEndLifeline != null && (!fEndLifeline.isVisible(x, y, width, height)) && (fStartLifeline != null && !fStartLifeline.isVisible(x, y, width, height))) { |
209 | if (fEndLifeline.getX() > x + width && fStartLifeline.getX() < x) { | |
73005152 | 210 | return true; |
eb63f5ff | 211 | } else if (fStartLifeline.getX() > x + width && fEndLifeline.getX() < x) { |
73005152 | 212 | return true; |
df0b8ff4 | 213 | } |
73005152 BH |
214 | } |
215 | return false; | |
216 | } | |
217 | ||
df0b8ff4 BH |
218 | /** |
219 | * Sets the visibility value. | |
abbdd66a | 220 | * |
df0b8ff4 BH |
221 | * @param value The visibility to set. |
222 | */ | |
73005152 | 223 | public void setVisible(boolean value) { |
eb63f5ff | 224 | fVisible = value; |
73005152 BH |
225 | } |
226 | ||
df0b8ff4 | 227 | /** |
abbdd66a | 228 | * @return the visibility value. |
df0b8ff4 | 229 | */ |
73005152 | 230 | public boolean isVisible() { |
eb63f5ff | 231 | return fVisible; |
73005152 BH |
232 | } |
233 | ||
234 | /** | |
235 | * Set the lifeline from which this message has been sent. | |
abbdd66a | 236 | * |
73005152 BH |
237 | * @param lifeline - the message sender |
238 | */ | |
239 | public void setStartLifeline(Lifeline lifeline) { | |
eb63f5ff | 240 | fStartLifeline = lifeline; |
73005152 BH |
241 | } |
242 | ||
243 | /** | |
244 | * Returns the lifeline from which this message has been sent. | |
abbdd66a | 245 | * |
73005152 BH |
246 | * @return the message sender |
247 | */ | |
248 | public Lifeline getStartLifeline() { | |
eb63f5ff | 249 | return fStartLifeline; |
73005152 BH |
250 | } |
251 | ||
252 | /** | |
253 | * Returns the lifeline which has received this message. | |
abbdd66a | 254 | * |
73005152 BH |
255 | * @return the message receiver |
256 | */ | |
257 | public Lifeline getEndLifeline() { | |
eb63f5ff | 258 | return fEndLifeline; |
73005152 BH |
259 | } |
260 | ||
261 | /** | |
262 | * Set the lifeline which has receive this message. | |
abbdd66a | 263 | * |
73005152 BH |
264 | * @param lifeline the message receiver |
265 | */ | |
266 | public void setEndLifeline(Lifeline lifeline) { | |
eb63f5ff | 267 | fEndLifeline = lifeline; |
73005152 BH |
268 | } |
269 | ||
270 | /** | |
271 | * Set the event occurrence when this message occurs.<br> | |
abbdd66a | 272 | * |
73005152 BH |
273 | * @param occurrence the event occurrence to assign to this message.<br> |
274 | * @see Lifeline Lifeline for more event occurence details | |
275 | */ | |
276 | protected void setEventOccurrence(int occurrence) { | |
cab6c8ff | 277 | setEndOccurrence(occurrence); |
73005152 BH |
278 | } |
279 | ||
280 | /** | |
281 | * Returns the event occurence when is message occurs.<br> | |
abbdd66a | 282 | * |
73005152 BH |
283 | * @return the event occurrence assigned to this message.<br> |
284 | * @see Lifeline Lifeline for more event occurence details | |
285 | */ | |
286 | public int getEventOccurrence() { | |
cab6c8ff | 287 | return getEndOccurrence(); |
73005152 BH |
288 | } |
289 | ||
290 | /** | |
291 | * Determines if the given eventOccurence occurs on a executionOccurence owned by the sending lifeline.<br> | |
292 | * WARNING: this method will return a valid result only for execution occurrences which are visible in the View.<br> | |
293 | * As consequence this method is only used for drawing purpose, especially to determine the exact message x | |
294 | * coordinate and width.<br> | |
abbdd66a | 295 | * |
73005152 BH |
296 | * @see BaseMessage#getX(boolean) |
297 | * @param event the event occurrence to test | |
298 | * @return true if occurs on a execution occurrence owned by the sending lifeine, false otherwise | |
299 | */ | |
300 | protected boolean isMessageStartInActivation(int event) { | |
301 | boolean inActivation = false; | |
eb63f5ff | 302 | if ((fStartLifeline != null) && (fStartLifeline.getExecutions() != null)) { |
73005152 BH |
303 | // int acIndex=startLifeline.getExecOccurrenceDrawIndex(); |
304 | // acIndex = first visible execution occurrence | |
305 | // for drawing speed reason with only search on the visivle subset | |
306 | int thisY = getY(); | |
eb63f5ff BH |
307 | for (int i = 0; i < fStartLifeline.getExecutions().size(); i++) { |
308 | BasicExecutionOccurrence toDraw = (BasicExecutionOccurrence) fStartLifeline.getExecutions().get(i); | |
cab6c8ff | 309 | if ((event >= toDraw.getStartOccurrence()) && (event <= toDraw.getEndOccurrence())) { |
73005152 | 310 | inActivation = true; |
df0b8ff4 | 311 | } |
73005152 BH |
312 | // if we are outside the visible area we stop right now |
313 | // This works because execution occurrences are ordered along the Y axis | |
df0b8ff4 | 314 | if (toDraw.getY() > thisY) { |
73005152 | 315 | break; |
df0b8ff4 | 316 | } |
73005152 BH |
317 | } |
318 | } | |
319 | return inActivation; | |
320 | } | |
321 | ||
322 | /** | |
323 | * Determines if the given event occurrence occurs on a execution occurrence owned by the receiving lifeline.<br> | |
324 | * WARNING: this method will return a valid result only for execution occurrences which are visible in the View.<br> | |
325 | * As consequence this method is only used for drawing purpose, especially to determine the exact message x | |
326 | * coordinate and width.<br> | |
abbdd66a | 327 | * |
73005152 BH |
328 | * @see BaseMessage#getX(boolean) |
329 | * @param event the event occurrence to test | |
330 | * @return true if occurs on a execution occurrence owned by the receiving lifeline, false otherwise | |
331 | */ | |
332 | protected boolean isMessageEndInActivation(int event) { | |
333 | boolean inActivation = false; | |
eb63f5ff | 334 | if ((fEndLifeline != null) && (fEndLifeline.getExecutions() != null)) { |
73005152 BH |
335 | // acIndex = first visible execution occurrence |
336 | // for drawing speed reason with only search on the visivle subset | |
eb63f5ff BH |
337 | for (int i = 0; i < fEndLifeline.getExecutions().size(); i++) { |
338 | BasicExecutionOccurrence toDraw = (BasicExecutionOccurrence) fEndLifeline.getExecutions().get(i); | |
cab6c8ff | 339 | if ((event >= toDraw.getStartOccurrence()) && (event <= toDraw.getEndOccurrence())) { |
73005152 | 340 | inActivation = true; |
df0b8ff4 | 341 | } |
73005152 BH |
342 | // if we are outside the visible area we stop right now |
343 | // This works because execution occurrences are ordered along the Y axis | |
df0b8ff4 | 344 | if (toDraw.getY() > getY()) { |
73005152 | 345 | break; |
df0b8ff4 | 346 | } |
73005152 BH |
347 | } |
348 | } | |
349 | return inActivation; | |
350 | } | |
351 | ||
73005152 | 352 | @Override |
eb63f5ff | 353 | public boolean contains(int xValue, int yValue) { |
73005152 BH |
354 | int x = getX(); |
355 | int y = getY(); | |
356 | int width = getWidth(); | |
357 | int height = getHeight(); | |
358 | ||
359 | // Used to create a rectangle which contains the message label to allow selection when clicking the label | |
360 | int tempHeight = Metrics.MESSAGES_NAME_SPACING + Metrics.getMessageFontHeigth(); | |
361 | ||
362 | // Is it a self message? | |
eb63f5ff | 363 | if (fStartLifeline == fEndLifeline) { |
73005152 BH |
364 | /* |
365 | * Rectangle.contains(x,y, width, height) does not works with negative height or width We check here if the | |
366 | * rectangle width is negative. | |
367 | */ | |
368 | if (getName().length() * Metrics.getAverageCharWidth() > Metrics.swimmingLaneWidth() - Metrics.EXECUTION_OCCURRENCE_WIDTH / 2 + -Metrics.INTERNAL_MESSAGE_WIDTH) { | |
abbdd66a | 369 | if (GraphNode.contains(x + Metrics.INTERNAL_MESSAGE_WIDTH + 10, y, Metrics.swimmingLaneWidth() - Metrics.EXECUTION_OCCURRENCE_WIDTH / 2 + -Metrics.INTERNAL_MESSAGE_WIDTH, Metrics.getMessageFontHeigth(), xValue, yValue)) { |
73005152 | 370 | return true; |
df0b8ff4 | 371 | } |
73005152 | 372 | } else { |
abbdd66a | 373 | if (GraphNode.contains(x + Metrics.INTERNAL_MESSAGE_WIDTH + 10, y, getName().length() * Metrics.getAverageCharWidth(), Metrics.getMessageFontHeigth(), xValue, yValue)) { |
73005152 | 374 | return true; |
df0b8ff4 | 375 | } |
73005152 BH |
376 | } |
377 | ||
378 | // Test if the point is in part 1 of the self message | |
379 | // see: "private void drawMessage (NGC context)" method for self message drawing schema | |
abbdd66a | 380 | if (GraphNode.contains(x, y - Metrics.MESSAGE_SELECTION_TOLERANCE / 2, Metrics.INTERNAL_MESSAGE_WIDTH / 2, Metrics.MESSAGE_SELECTION_TOLERANCE, xValue, yValue)) { |
73005152 | 381 | return true; |
df0b8ff4 | 382 | } |
73005152 BH |
383 | |
384 | // Test if the point is in part 3 of the self message | |
abbdd66a | 385 | if (GraphNode.contains(x + Metrics.INTERNAL_MESSAGE_WIDTH - Metrics.MESSAGE_SELECTION_TOLERANCE / 2, y, Metrics.MESSAGE_SELECTION_TOLERANCE, height + Metrics.SYNC_INTERNAL_MESSAGE_HEIGHT, xValue, yValue)) { |
73005152 | 386 | return true; |
df0b8ff4 | 387 | } |
73005152 BH |
388 | |
389 | // Test if the point is in part 5 of the self message | |
abbdd66a | 390 | if (GraphNode.contains(x, y + height - Metrics.MESSAGE_SELECTION_TOLERANCE / 2 + Metrics.SYNC_INTERNAL_MESSAGE_HEIGHT, Metrics.INTERNAL_MESSAGE_WIDTH / 2, Metrics.MESSAGE_SELECTION_TOLERANCE, xValue, yValue)) { |
73005152 | 391 | return true; |
df0b8ff4 | 392 | } |
73005152 BH |
393 | |
394 | // false otherwise | |
395 | return false; | |
396 | } | |
abbdd66a | 397 | if (GraphNode.contains(x, y - tempHeight, width, tempHeight, xValue, yValue)) { |
73005152 | 398 | return true; |
df0b8ff4 | 399 | } |
73005152 BH |
400 | // false otherwise |
401 | return false; | |
402 | } | |
403 | ||
df0b8ff4 BH |
404 | /** |
405 | * Method to draw the message using the graphical context. | |
abbdd66a | 406 | * |
df0b8ff4 BH |
407 | * @param context A graphical context to draw in. |
408 | */ | |
73005152 | 409 | protected void drawMessage(IGC context) { |
cab6c8ff BH |
410 | int fX = 0; |
411 | int fY = 0; | |
412 | int fW = 0; | |
413 | int fH = 0; | |
73005152 | 414 | |
3145ec83 | 415 | // temporary store the coordinates to avoid more methods calls |
73005152 BH |
416 | int x = getX(); |
417 | int y = getY(); | |
418 | int width = getWidth(); | |
419 | int height = getHeight(); | |
420 | ||
3145ec83 BH |
421 | ISDPreferences pref = SDViewPref.getInstance(); |
422 | ||
73005152 BH |
423 | // UML2 found message (always drawn from left to right) |
424 | // or UML2 lost message (always drawn from left to right) | |
eb63f5ff | 425 | if ((fStartLifeline == null || fEndLifeline == null) && fStartLifeline != fEndLifeline) { |
73005152 BH |
426 | // Draw the message label above the message and centered |
427 | // The label is truncated if it cannot fit between the two message end | |
428 | // 2*Metrics.MESSAGES_NAME_SPACING = space above the label + space below the label | |
429 | IColor temp = context.getForeground(); | |
cab6c8ff | 430 | context.setForeground(pref.getFontColor(getColorPrefId())); |
73005152 BH |
431 | context.drawTextTruncatedCentred(getName(), x, y - Metrics.getMessageFontHeigth() - 2 * Metrics.MESSAGES_NAME_SPACING, width, 2 * Metrics.MESSAGES_NAME_SPACING + Metrics.getMessageFontHeigth(), !isSelected()); |
432 | context.setForeground(temp); | |
433 | int margin = 0; | |
eb63f5ff | 434 | if (fEndLifeline == null) { |
73005152 | 435 | margin = Metrics.MESSAGE_CIRCLE_RAY; |
df0b8ff4 | 436 | } |
73005152 BH |
437 | |
438 | // Draw the message main line | |
439 | context.drawLine(x, y, x + width, y + height); | |
440 | // Draw the two little lines which make a arrow part of the message | |
eb63f5ff BH |
441 | Double xt = Double.valueOf(Math.cos(0.75) * 7); |
442 | Double yt = Double.valueOf(Math.sin(0.75) * 7); | |
73005152 BH |
443 | if (context.getLineStyle() == context.getLineSolidStyle()) { |
444 | IColor backcolor = context.getBackground(); | |
445 | context.setBackground(context.getForeground()); | |
446 | int[] points = { x + width - margin, y + height, x + width - xt.intValue() - margin, y + height - yt.intValue(), x + width - xt.intValue() - margin, y + height + yt.intValue(), x + width - margin, y + height }; | |
447 | context.fillPolygon(points); | |
448 | context.drawPolygon(points); | |
449 | context.setBackground(backcolor); | |
450 | } else { | |
451 | int currentStyle = context.getLineStyle(); | |
452 | int currentWidth = context.getLineWidth(); | |
453 | context.setLineWidth(currentWidth + 2); | |
454 | context.setLineStyle(context.getLineSolidStyle()); | |
455 | context.drawLine(x + width - xt.intValue() - margin, y + height - yt.intValue(), x + width - margin, y + height); | |
456 | context.drawLine(x + width - xt.intValue() - margin, y + height + yt.intValue(), x + width - margin, y + height); | |
457 | context.setLineStyle(currentStyle); | |
458 | context.setLineWidth(currentWidth); | |
459 | } | |
460 | IColor storedColor = context.getBackground(); | |
461 | context.setBackground(context.getForeground()); | |
462 | ||
463 | // Draw a circle at the message end (endLifeline side) | |
464 | int ray = Metrics.MESSAGE_CIRCLE_RAY; | |
df0b8ff4 | 465 | if (context.getLineWidth() != Metrics.NORMAL_LINE_WIDTH) { |
73005152 | 466 | ray = ray + Metrics.SELECTION_LINE_WIDTH - Metrics.NORMAL_LINE_WIDTH; |
df0b8ff4 | 467 | } |
eb63f5ff | 468 | if (fStartLifeline == null) { |
73005152 | 469 | context.fillOval(x - ray, y - ray, ray * 2, ray * 2); |
df0b8ff4 | 470 | } else { |
73005152 | 471 | context.fillOval(x + width - ray, y + height - ray, ray * 2, ray * 2); |
df0b8ff4 | 472 | } |
73005152 | 473 | context.setBackground(storedColor); |
cab6c8ff | 474 | context.setForeground(pref.getFontColor(getColorPrefId())); |
73005152 BH |
475 | fX = x; |
476 | fY = y - yt.intValue(); | |
477 | fW = width; | |
478 | fH = height + 2 * yt.intValue(); | |
479 | } | |
480 | // it is self message (always drawn at the left side of the owning lifeLifeline) | |
eb63f5ff | 481 | else if (fStartLifeline != null && fEndLifeline != null && fStartLifeline == fEndLifeline) { |
73005152 BH |
482 | /* |
483 | * Self syncMessages are drawn in 5 parts 1 -----------+ + 2 + | | | 3 | + 5 + 4 -----------+ | |
484 | */ | |
485 | int tempy = Metrics.INTERNAL_MESSAGE_WIDTH / 2; | |
df0b8ff4 | 486 | if (Metrics.SYNC_INTERNAL_MESSAGE_HEIGHT <= Metrics.INTERNAL_MESSAGE_WIDTH) { |
73005152 | 487 | tempy = Metrics.SYNC_INTERNAL_MESSAGE_HEIGHT / 2; |
df0b8ff4 | 488 | } |
73005152 BH |
489 | |
490 | // Part 1 | |
491 | context.drawLine(x, y, x + Metrics.INTERNAL_MESSAGE_WIDTH / 2, y); | |
492 | // Part 3 | |
493 | context.drawLine(x + Metrics.INTERNAL_MESSAGE_WIDTH, y + tempy, x + Metrics.INTERNAL_MESSAGE_WIDTH, y + height + Metrics.SYNC_INTERNAL_MESSAGE_HEIGHT - tempy); | |
494 | // Part 5 | |
495 | context.drawLine(x, y + height + Metrics.SYNC_INTERNAL_MESSAGE_HEIGHT, x + Metrics.INTERNAL_MESSAGE_WIDTH / 2, y + height + Metrics.SYNC_INTERNAL_MESSAGE_HEIGHT); | |
496 | ||
eb63f5ff BH |
497 | Double xt = Double.valueOf(Math.cos(0.75) * 7); |
498 | Double yt = Double.valueOf(Math.sin(0.75) * 7); | |
73005152 BH |
499 | |
500 | fX = x; | |
501 | fY = y; | |
502 | fW = Metrics.INTERNAL_MESSAGE_WIDTH; | |
503 | fH = height + Metrics.SYNC_INTERNAL_MESSAGE_HEIGHT; | |
504 | ||
505 | // Draw the two little lines which make a arrow part of the message | |
506 | if (context.getLineStyle() == context.getLineSolidStyle()) { | |
507 | IColor backcolor = context.getBackground(); | |
508 | context.setBackground(context.getForeground()); | |
509 | int[] points = { x, y + height + Metrics.SYNC_INTERNAL_MESSAGE_HEIGHT, x + xt.intValue(), y + height + Metrics.SYNC_INTERNAL_MESSAGE_HEIGHT + yt.intValue(), x + xt.intValue(), | |
510 | y + height + Metrics.SYNC_INTERNAL_MESSAGE_HEIGHT - yt.intValue(), x, y + height + Metrics.SYNC_INTERNAL_MESSAGE_HEIGHT }; | |
511 | context.fillPolygon(points); | |
512 | context.drawPolygon(points); | |
513 | context.setBackground(backcolor); | |
514 | } else { | |
515 | int currentStyle = context.getLineStyle(); | |
516 | int currentWidth = context.getLineWidth(); | |
517 | context.setLineWidth(currentWidth + 2); | |
518 | context.setLineStyle(context.getLineSolidStyle()); | |
519 | context.drawLine(x + xt.intValue(), y + height + Metrics.SYNC_INTERNAL_MESSAGE_HEIGHT + yt.intValue(), x, y + height + Metrics.SYNC_INTERNAL_MESSAGE_HEIGHT); | |
520 | context.drawLine(x + xt.intValue(), y + height + Metrics.SYNC_INTERNAL_MESSAGE_HEIGHT - yt.intValue(), x, y + height + Metrics.SYNC_INTERNAL_MESSAGE_HEIGHT); | |
521 | context.setLineStyle(currentStyle); | |
522 | context.setLineWidth(currentWidth); | |
523 | } | |
524 | ||
525 | // Part 2 | |
526 | context.drawArc(x, y, Metrics.INTERNAL_MESSAGE_WIDTH, 2 * tempy, 0, 90); | |
527 | // Part 4 | |
528 | context.drawArc(x, y + Metrics.SYNC_INTERNAL_MESSAGE_HEIGHT, Metrics.INTERNAL_MESSAGE_WIDTH, -2 * tempy, 0, -90); | |
529 | ||
530 | // Draw the message label above the message and centered | |
531 | // The label is truncated if it cannot fit between the two message end | |
532 | // 2*Metrics.MESSAGES_NAME_SPACING = space above the label + space below the label | |
533 | ||
534 | // the space available for the text is sorter if are drawing internal message on the last lifeline | |
cab6c8ff | 535 | context.setForeground(pref.getFontColor(getColorPrefId())); |
eb63f5ff | 536 | if (fStartLifeline.getIndex() == fStartLifeline.getFrame().getHorizontalIndex()) { |
73005152 BH |
537 | context.drawTextTruncated(getName(), x + width + Metrics.INTERNAL_MESSAGE_V_MARGIN / 2, y, Metrics.swimmingLaneWidth() / 2 - Metrics.EXECUTION_OCCURRENCE_WIDTH + -Metrics.INTERNAL_MESSAGE_WIDTH, +Metrics.MESSAGES_NAME_SPACING |
538 | - Metrics.getMessageFontHeigth(), !isSelected()); | |
df0b8ff4 | 539 | } else { |
73005152 BH |
540 | context.drawTextTruncated(getName(), x + width + Metrics.INTERNAL_MESSAGE_V_MARGIN / 2, y, Metrics.swimmingLaneWidth() - Metrics.EXECUTION_OCCURRENCE_WIDTH + -Metrics.INTERNAL_MESSAGE_WIDTH, |
541 | +Metrics.MESSAGES_NAME_SPACING - Metrics.getMessageFontHeigth(), !isSelected()); | |
df0b8ff4 | 542 | } |
73005152 BH |
543 | } |
544 | // it is regular message | |
eb63f5ff | 545 | else if (fStartLifeline != null && fEndLifeline != null) { |
73005152 BH |
546 | // Draw the message main line |
547 | context.drawLine(x, y, x + width, y + height); | |
548 | ||
eb63f5ff | 549 | int spaceBTWStartEnd = fEndLifeline.getX() - fStartLifeline.getX(); |
73005152 BH |
550 | |
551 | double a = height; | |
552 | double b = width; | |
553 | double angle = Math.atan(a / b); | |
554 | // Compute the coordinates of the two little lines which make the arrow part of the message | |
555 | int sign = 1; | |
df0b8ff4 | 556 | if (spaceBTWStartEnd < 0) { |
73005152 | 557 | sign = -1; |
df0b8ff4 | 558 | } |
eb63f5ff BH |
559 | Double x1 = Double.valueOf(sign * Math.cos(angle - 0.75) * 7); |
560 | Double y1 = Double.valueOf(sign * Math.sin(angle - 0.75) * 7); | |
561 | Double x2 = Double.valueOf(sign * Math.cos(angle + 0.75) * 7); | |
562 | Double y2 = Double.valueOf(sign * Math.sin(angle + 0.75) * 7); | |
73005152 BH |
563 | |
564 | fX = getX(); | |
565 | fY = y + height - y2.intValue(); | |
566 | fW = getWidth(); | |
567 | fH = y2.intValue() - y1.intValue() + 1; | |
568 | if (fW < 0) { | |
569 | fW = -fW; | |
570 | fX = fX - fW; | |
571 | } | |
572 | ||
573 | if (fH < 0) { | |
574 | fH = -fH; | |
575 | fY = fY - fH; | |
576 | } | |
577 | ||
578 | // Draw the two little lines which make a arrow part of the message | |
579 | if (context.getLineStyle() == context.getLineSolidStyle()) { | |
580 | IColor backcolor = context.getBackground(); | |
581 | context.setBackground(context.getForeground()); | |
582 | int[] points = { x + width - x1.intValue(), y + height - y1.intValue(), x + width, y + height, x + width - x2.intValue(), y + height - y2.intValue(), x + width - x1.intValue(), y + height - y1.intValue() }; | |
583 | context.fillPolygon(points); | |
584 | context.drawPolygon(points); | |
585 | context.setBackground(backcolor); | |
586 | } else { | |
587 | int currentStyle = context.getLineStyle(); | |
588 | int currentWidth = context.getLineWidth(); | |
589 | context.setLineWidth(currentWidth + 2); | |
590 | context.setLineStyle(context.getLineSolidStyle()); | |
591 | context.drawLine(x + width - x1.intValue(), y + height - y1.intValue(), x + width, y + height); | |
592 | context.drawLine(x + width - x2.intValue(), y + height - y2.intValue(), x + width, y + height); | |
593 | context.setLineStyle(currentStyle); | |
594 | context.setLineWidth(currentWidth); | |
595 | } | |
596 | ||
597 | // Draw the message label above the message and centered | |
598 | // The label is truncated if it cannot fit between the two message end | |
599 | // 2*Metrics.MESSAGES_NAME_SPACING = space above the label + space below the label | |
cab6c8ff | 600 | context.setForeground(pref.getFontColor(getColorPrefId())); |
df0b8ff4 | 601 | if (spaceBTWStartEnd > 0) { |
73005152 | 602 | context.drawTextTruncatedCentred(getName(), x, y + height / 2 - (2 * Metrics.MESSAGES_NAME_SPACING + Metrics.getMessageFontHeigth()), width, 2 * Metrics.MESSAGES_NAME_SPACING + Metrics.getMessageFontHeigth(), !isSelected()); |
df0b8ff4 | 603 | } else { |
73005152 | 604 | context.drawTextTruncatedCentred(getName(), x + width, y + height / 2 - (2 * Metrics.MESSAGES_NAME_SPACING + Metrics.getMessageFontHeigth()), -width, 2 * Metrics.MESSAGES_NAME_SPACING + +Metrics.getMessageFontHeigth(), !isSelected()); |
df0b8ff4 | 605 | } |
73005152 BH |
606 | } |
607 | } | |
abbdd66a | 608 | |
73005152 BH |
609 | @Override |
610 | public void draw(IGC context) { | |
df0b8ff4 | 611 | if (!isVisible()) { |
73005152 | 612 | return; |
df0b8ff4 | 613 | } |
abbdd66a | 614 | |
73005152 BH |
615 | // Draw it selected?*/ |
616 | if (isSelected()) { | |
3145ec83 | 617 | ISDPreferences pref = SDViewPref.getInstance(); |
73005152 BH |
618 | /* |
619 | * Draw it twice First time, bigger inverting selection colors Second time, regular drawing using selection | |
620 | * colors This create the highlight effect | |
621 | */ | |
3145ec83 | 622 | context.setForeground(pref.getBackGroundColorSelection()); |
73005152 BH |
623 | context.setLineWidth(Metrics.SELECTION_LINE_WIDTH); |
624 | drawMessage(context); | |
3145ec83 BH |
625 | context.setBackground(pref.getBackGroundColorSelection()); |
626 | context.setForeground(pref.getForeGroundColorSelection()); | |
73005152 BH |
627 | // Second drawing is done after |
628 | } | |
629 | context.setLineWidth(Metrics.NORMAL_LINE_WIDTH); | |
630 | if (hasFocus()) { | |
631 | context.setDrawTextWithFocusStyle(true); | |
632 | } | |
633 | drawMessage(context); | |
634 | int oldStyle = context.getLineStyle(); | |
635 | if (hasFocus()) { | |
636 | context.setDrawTextWithFocusStyle(false); | |
637 | drawFocus(context); | |
638 | } | |
639 | // restore the context | |
640 | context.setLineStyle(oldStyle); | |
641 | } | |
642 | ||
643 | /** | |
644 | * Determine if two messages are identical. This default implementation considers that overlapping messages with | |
645 | * same coordinates are identical. | |
abbdd66a | 646 | * |
73005152 BH |
647 | * @param message - the message to compare with |
648 | * @return true if identical false otherwise | |
abbdd66a | 649 | * |
2bdf0193 | 650 | * @see org.eclipse.tracecompass.tmf.ui.views.uml2sd.core.GraphNode#isSameAs(org.eclipse.tracecompass.tmf.ui.views.uml2sd.core.GraphNode) |
73005152 BH |
651 | */ |
652 | @Override | |
653 | public boolean isSameAs(GraphNode message) { | |
df0b8ff4 | 654 | if (message == null) { |
73005152 | 655 | return false; |
df0b8ff4 BH |
656 | } |
657 | if (!(message instanceof BaseMessage)) { | |
73005152 | 658 | return super.isSameAs(message); |
df0b8ff4 | 659 | } |
eb63f5ff | 660 | return ((getX() == message.getX()) && (getY() == message.getY()) && (getWidth() == message.getWidth()) && (getHeight() == message.getHeight())); |
73005152 BH |
661 | } |
662 | ||
df0b8ff4 BH |
663 | /** |
664 | * Method drawRot. | |
abbdd66a | 665 | * |
df0b8ff4 BH |
666 | * @param x A x coordinate |
667 | * @param y A y coordinate | |
668 | * @param w A width | |
669 | * @param h A height | |
670 | * @param context A graphical context | |
671 | */ | |
73005152 BH |
672 | public void drawRot(int x, int y, int w, int h, IGC context) { |
673 | double angleA = Math.atan2(getHeight(), getWidth()); | |
674 | double cosA = Math.cos(angleA); | |
675 | double sinA = Math.sin(angleA); | |
676 | ||
677 | int gx = getX(); | |
678 | int gy = getY(); | |
679 | ||
eb63f5ff BH |
680 | int localHeight = h; |
681 | localHeight = localHeight / 2; | |
73005152 BH |
682 | |
683 | double cw = Math.sqrt(w * w + getHeight() * getHeight()); | |
684 | ||
685 | int x1 = Math.round((float) ((x - gx) * cosA - (y - gy) * sinA)); | |
686 | int y1 = Math.round((float) ((x - gx) * sinA + (y - gy) * cosA)); | |
687 | ||
688 | int x2 = Math.round((float) (cw * cosA - (y - gy) * sinA)); | |
689 | int y2 = Math.round((float) (cw * sinA + (y - gy) * cosA)); | |
690 | ||
eb63f5ff BH |
691 | int x3 = Math.round((float) (cw * cosA - (localHeight) * sinA)); |
692 | int y3 = Math.round((float) (cw * sinA + (localHeight) * cosA)); | |
73005152 | 693 | |
eb63f5ff BH |
694 | int x4 = Math.round((float) ((x - gx) * cosA - (localHeight) * sinA)); |
695 | int y4 = Math.round((float) ((x - gx) * sinA + (localHeight) * cosA)); | |
73005152 BH |
696 | |
697 | int[] points = { x1 + getX(), y1 + getY(), x2 + getX(), y2 + getY(), x3 + getX(), y3 + getY(), x4 + getX(), y4 + getY() }; | |
698 | context.drawPolygon(points); | |
699 | } | |
700 | ||
701 | @Override | |
702 | public void drawFocus(IGC context) { | |
3145ec83 BH |
703 | |
704 | ISDPreferences pref = SDViewPref.getInstance(); | |
705 | ||
cab6c8ff | 706 | if ((fStartLifeline != fEndLifeline) && (getStartOccurrence() == getEndOccurrence())) { |
73005152 BH |
707 | context.setLineStyle(context.getLineDotStyle()); |
708 | context.setLineWidth(Metrics.NORMAL_LINE_WIDTH); | |
3145ec83 BH |
709 | context.setBackground(pref.getBackGroundColorSelection()); |
710 | context.setForeground(pref.getForeGroundColorSelection()); | |
73005152 | 711 | context.drawFocus(getX(), getY() - 3, getWidth(), getHeight() + 6); |
cab6c8ff | 712 | } else if ((fStartLifeline == fEndLifeline) && (getStartOccurrence() == getEndOccurrence())) { |
73005152 | 713 | context.drawFocus(getX(), getY() - 3, getWidth(), Metrics.SYNC_INTERNAL_MESSAGE_HEIGHT + 6); |
cab6c8ff | 714 | } else if ((fStartLifeline != fEndLifeline) && (getStartOccurrence() != getEndOccurrence())) { |
73005152 BH |
715 | context.setLineStyle(context.getLineDotStyle()); |
716 | context.setLineWidth(Metrics.NORMAL_LINE_WIDTH); | |
3145ec83 BH |
717 | context.setBackground(pref.getBackGroundColor(ISDPreferences.PREF_LIFELINE_HEADER)); |
718 | context.setForeground(pref.getForeGroundColor(ISDPreferences.PREF_LIFELINE_HEADER)); | |
73005152 | 719 | drawRot(getX(), getY() - 5, getWidth(), 10, context); |
df0b8ff4 | 720 | } else { |
73005152 | 721 | super.drawFocus(context); |
df0b8ff4 | 722 | } |
73005152 BH |
723 | } |
724 | } |