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