1 /**********************************************************************
2 * Copyright (c) 2005, 2013 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
9 * IBM - Initial API and implementation
10 * Bernd Hufmann - Updated for TMF
11 **********************************************************************/
13 package org
.eclipse
.tracecompass
.tmf
.ui
.views
.uml2sd
.core
;
15 import java
.util
.Comparator
;
17 import org
.eclipse
.tracecompass
.tmf
.core
.timestamp
.ITmfTimestamp
;
18 import org
.eclipse
.tracecompass
.tmf
.core
.timestamp
.TmfTimestamp
;
19 import org
.eclipse
.tracecompass
.tmf
.ui
.views
.uml2sd
.drawings
.IGC
;
20 import org
.eclipse
.tracecompass
.tmf
.ui
.views
.uml2sd
.preferences
.ISDPreferences
;
21 import org
.eclipse
.tracecompass
.tmf
.ui
.views
.uml2sd
.preferences
.SDViewPref
;
22 import org
.eclipse
.tracecompass
.tmf
.ui
.views
.uml2sd
.util
.SortAsyncForBackward
;
23 import org
.eclipse
.tracecompass
.tmf
.ui
.views
.uml2sd
.util
.SortAsyncMessageComparator
;
26 * A AsyncMessage is a asynchronous message which appear at two different event occurrences on each lifeline ends (sender
37 * AsyncMessage message = new AsyncMessage();
38 * // Create a new event occurrence on each lifeline
39 * lifeline1.getNewOccurrenceIndex();
40 * lifeline2.getNewOccurrenceIndex();
41 * // Set the message sender and receiver
42 * message.setStartLifeline(lifeLine1);
43 * message.setEndLifline(lifeline2);
44 * message.setName("Message label");
45 * // add the message to the frame
46 * frame.addMessage(message);
49 * @see Lifeline Lifeline for more event occurence details
54 public class AsyncMessage
extends BaseMessage
implements ITimeRange
{
56 // ------------------------------------------------------------------------
58 // ------------------------------------------------------------------------
60 * The grahNode ID constant
62 public static final String ASYNC_MESS_TAG
= "AsyncMessage"; //$NON-NLS-1$
64 // ------------------------------------------------------------------------
66 // ------------------------------------------------------------------------
68 * Flag whether message has time information or not.
70 private boolean fHasTime
= false;
72 * The time when the message begin
74 private ITmfTimestamp fEndTime
= new TmfTimestamp();
76 * The time when the message end
78 private ITmfTimestamp fStartTime
= new TmfTimestamp();
80 * The associated message.
82 protected AsyncMessageReturn fMessageReturn
= null;
84 // ------------------------------------------------------------------------
86 // ------------------------------------------------------------------------
90 public AsyncMessage() {
91 setColorPrefId(ISDPreferences
.PREF_ASYNC_MESS
);
94 // ------------------------------------------------------------------------
96 // ------------------------------------------------------------------------
100 int x
= super.getX(true);
101 int activationWidth
= Metrics
.EXECUTION_OCCURRENCE_WIDTH
/ 2;
102 if ((getStartLifeline() != null) && (getEndLifeline() != null) && (getStartLifeline().getX() > getEndLifeline().getX())) {
103 activationWidth
= -activationWidth
;
106 if (isMessageStartInActivation(getStartOccurrence())) {
107 x
= x
+ activationWidth
;
114 if ((getStartLifeline() != null) && (getEndLifeline() != null)) {
115 return getEndLifeline().getY() + getEndLifeline().getHeight() + (Metrics
.getMessageFontHeigth() + Metrics
.getMessagesSpacing()) * getStartOccurrence();
121 public int getWidth() {
122 int width
= super.getWidth(true);
123 int activationWidth
= Metrics
.EXECUTION_OCCURRENCE_WIDTH
/ 2;
124 if ((getStartLifeline() != null) && (getEndLifeline() != null) && (getStartLifeline().getX() > getEndLifeline().getX())) {
125 activationWidth
= -activationWidth
;
128 if (isMessageStartInActivation(getStartOccurrence())) {
129 width
= width
- activationWidth
;
132 if (isMessageEndInActivation(getEndOccurrence())) {
133 width
= width
- activationWidth
;
140 public int getHeight() {
141 if ((getStartLifeline() != null) && (getEndLifeline() != null)) {
142 return (getEndLifeline().getY() + getEndLifeline().getHeight() + (Metrics
.getMessageFontHeigth() + Metrics
.getMessagesSpacing()) * getEndOccurrence()) - getY();
144 return super.getHeight();
148 * Set the message return associated with this message.
150 * @param message the message return to associate
152 protected void setMessageReturn(AsyncMessageReturn message
) {
153 fMessageReturn
= message
;
157 * Set the event occurrence attached to this message for its end lifeline
159 * @param occurrence the event occurrence to set
162 public void setEndOccurrence(int occurrence
) {
163 super.setEndOccurrence(occurrence
);
164 if (getStartLifeline() == null) {
165 setStartOccurrence(occurrence
);
167 informFrame(getEndLifeline(), occurrence
);
171 * Informs the given lifeline about the maximum occurrence if applicable.
178 protected void informFrame(Lifeline lifeLine
, int occurrence
) {
179 if ((lifeLine
!= null) && (lifeLine
.getFrame() != null) && (lifeLine
.getFrame().getMaxEventOccurrence() < occurrence
)) {
180 lifeLine
.getFrame().setMaxEventOccurrence(occurrence
);
185 * Set the event occurrence attached to this message for its start lifeline
187 * @param occurrence the event occurrence to set
190 public void setStartOccurrence(int occurrence
) {
191 super.setStartOccurrence(occurrence
);
192 if (getEndLifeline() == null) {
193 setEndOccurrence(getStartOccurrence());
195 informFrame(getStartLifeline(), occurrence
);
199 * Set the lifeLine which has sent the message.<br>
200 * A new EventOccurence will be create on this lifeLine.<br>
202 * @param lifeline the message sender
204 public void autoSetStartLifeline(Lifeline lifeline
) {
205 lifeline
.getNewEventOccurrence();
206 setStartLifeline(lifeline
);
210 * Set the lifeLine which has received the message.<br>
211 * A new EventOccurence will be create on this lifeLine.<br>
213 * @param lifeline the message receiver
215 public void autoSetEndLifeline(Lifeline lifeline
) {
216 lifeline
.getNewEventOccurrence();
217 setEndLifeline(lifeline
);
221 public void setStartLifeline(Lifeline lifeline
) {
222 super.setStartLifeline(lifeline
);
223 setStartOccurrence(getStartLifeline().getEventOccurrence());
224 if (getEndLifeline() == null) {
225 setEndOccurrence(getStartOccurrence());
230 public void setEndLifeline(Lifeline lifeline
) {
231 super.setEndLifeline(lifeline
);
232 setEventOccurrence(getEndLifeline().getEventOccurrence());
236 * Returns true if the point C is on the segment defined with the point A and B
238 * @param xA point A x coordinate
239 * @param yA point A y coordinate
240 * @param xB point B x coordinate
241 * @param yB point B y coordinate
242 * @param xC point C x coordinate
243 * @param yC point C y coordinate
244 * @return Return true if the point C is on the segment defined with the point A and B, else otherwise
246 protected boolean isNearSegment(int xA
, int yA
, int xB
, int yB
, int xC
, int yC
) {
247 if ((xA
> xB
) && (xC
> xA
)) {
250 if ((xA
< xB
) && (xC
> xB
)) {
253 if ((xA
< xB
) && (xC
< xA
)) {
256 if ((xA
> xB
) && (xC
< xB
)) {
259 double distAB
= Math
.sqrt((xB
- xA
) * (xB
- xA
) + (yB
- yA
) * (yB
- yA
));
260 double scalar
= ((xB
- xA
) * (xC
- xA
) + (yB
- yA
) * (yC
- yA
)) / distAB
;
261 double distAC
= Math
.sqrt((xC
- xA
) * (xC
- xA
) + (yC
- yA
) * (yC
- yA
));
262 double distToSegment
= Math
.sqrt(Math
.abs(distAC
* distAC
- scalar
* scalar
));
263 if (distToSegment
<= Metrics
.MESSAGE_SELECTION_TOLERANCE
) {
270 public boolean contains(int x
, int y
) {
271 // Is it a self message?
272 if (getStartLifeline() == getEndLifeline()) {
273 return super.contains(x
, y
);
275 if (isNearSegment(getX(), getY(), getX() + getWidth(), getY() + getHeight(), x
, y
)) {
278 int messageMaxWidth
= Metrics
.swimmingLaneWidth() - Metrics
.EXECUTION_OCCURRENCE_WIDTH
;
279 int nameWidth
= getName().length() * Metrics
.getAverageCharWidth();
280 if (getName().length() * Metrics
.getAverageCharWidth() > messageMaxWidth
) {
281 if (GraphNode
.contains(getX(), getY() - Metrics
.MESSAGES_NAME_SPACING
- Metrics
.getMessageFontHeigth(), messageMaxWidth
, Metrics
.getMessageFontHeigth(), x
, y
)) {
285 if (GraphNode
.contains(getX() + (messageMaxWidth
- nameWidth
) / 2, getY() + getHeight() / 2 - Metrics
.MESSAGES_NAME_SPACING
- Metrics
.getMessageFontHeigth(), nameWidth
, Metrics
.getMessageFontHeigth(), x
, y
)) {
293 * Draws the asynchronous message using giving graphical context.
295 * @param context A graphical context to draw in.
297 protected void drawAsyncMessage(IGC context
) {
298 if (getStartLifeline() != null && getEndLifeline() != null && getStartLifeline() == getEndLifeline() && (getStartOccurrence() != getEndOccurrence())) {
301 int height
= getHeight();
303 boolean startInActivation
= isMessageStartInActivation(getStartOccurrence());
304 boolean endInActivation
= isMessageEndInActivation(getEndOccurrence());
306 if (endInActivation
&& !startInActivation
) {
307 tempx
= Metrics
.EXECUTION_OCCURRENCE_WIDTH
/ 2;
309 if (startInActivation
&& !endInActivation
) {
310 tempx
= -Metrics
.EXECUTION_OCCURRENCE_WIDTH
/ 2;
313 int tempy
= Metrics
.INTERNAL_MESSAGE_WIDTH
/ 2;
314 if (getHeight() <= Metrics
.INTERNAL_MESSAGE_WIDTH
) {
315 tempy
= getHeight() / 2;
318 context
.drawLine(x
, y
, x
+ Metrics
.INTERNAL_MESSAGE_WIDTH
/ 2, y
);
319 context
.drawLine(x
+ Metrics
.INTERNAL_MESSAGE_WIDTH
, y
+ tempy
, x
+ Metrics
.INTERNAL_MESSAGE_WIDTH
, y
+ height
- tempy
);
320 context
.drawLine(x
+ tempx
, y
+ height
, x
+ Metrics
.INTERNAL_MESSAGE_WIDTH
/ 2, y
+ height
);
322 Double xt
= Double
.valueOf(Math
.cos(0.75) * 7);
323 Double yt
= Double
.valueOf(Math
.sin(0.75) * 7);
325 context
.drawLine(x
+ xt
.intValue() + tempx
, y
+ height
+ yt
.intValue(), x
+ tempx
, y
+ height
);
326 context
.drawArc(x
, y
, Metrics
.INTERNAL_MESSAGE_WIDTH
, 2 * tempy
, 0, 90);
327 context
.drawArc(x
, y
+ height
, Metrics
.INTERNAL_MESSAGE_WIDTH
, -2 * tempy
, 0, -90);
328 context
.drawLine(x
+ xt
.intValue() + tempx
, y
+ height
- yt
.intValue(), x
+ tempx
, y
+ height
);
330 context
.drawTextTruncated(getName(), x
+ Metrics
.INTERNAL_MESSAGE_WIDTH
+ Metrics
.INTERNAL_MESSAGE_V_MARGIN
, y
, Metrics
.swimmingLaneWidth() - Metrics
.EXECUTION_OCCURRENCE_WIDTH
+ -Metrics
.INTERNAL_MESSAGE_WIDTH
,
331 +Metrics
.MESSAGES_NAME_SPACING
- Metrics
.getMessageFontHeigth(), !isSelected());
338 public void draw(IGC context
) {
343 ISDPreferences pref
= SDViewPref
.getInstance();
346 if (isSelected() && (getStartLifeline() != null && getEndLifeline() != null && getStartLifeline() == getEndLifeline() && (getStartOccurrence() != getEndOccurrence()))) {
348 * Draw it twice First time, bigger inverting selection colors Second time, regular drawing using selection
349 * colors This create the highlight effect
351 context
.setForeground(pref
.getBackGroundColorSelection());
352 context
.setLineWidth(Metrics
.SELECTION_LINE_WIDTH
);
353 drawAsyncMessage(context
);
354 context
.setBackground(pref
.getBackGroundColorSelection());
355 context
.setForeground(pref
.getForeGroundColorSelection());
356 // Second drawing is done after the else
358 context
.setBackground(pref
.getBackGroundColor(getColorPrefId()));
359 context
.setForeground(pref
.getForeGroundColor(getColorPrefId()));
362 context
.setDrawTextWithFocusStyle(true);
364 context
.setLineWidth(Metrics
.NORMAL_LINE_WIDTH
);
365 drawAsyncMessage(context
);
367 context
.setDrawTextWithFocusStyle(false);
372 * Set the time when the message end
374 * @param time the time when the message end
377 public void setEndTime(ITmfTimestamp time
) {
380 if (getStartLifeline() != null && getStartLifeline().getFrame() != null) {
381 getStartLifeline().getFrame().setHasTimeInfo(true);
382 } else if (getEndLifeline() != null && getEndLifeline().getFrame() != null) {
383 getEndLifeline().getFrame().setHasTimeInfo(true);
388 * Set the time when the message start
390 * @param time the time when the message start
393 public void setStartTime(ITmfTimestamp time
) {
396 if (getStartLifeline() != null && getStartLifeline().getFrame() != null) {
397 getStartLifeline().getFrame().setHasTimeInfo(true);
398 } else if (getEndLifeline() != null && getEndLifeline().getFrame() != null) {
399 getEndLifeline().getFrame().setHasTimeInfo(true);
407 public ITmfTimestamp
getEndTime() {
415 public ITmfTimestamp
getStartTime() {
420 public boolean hasTimeInfo() {
425 * @return message return instance or null
428 public AsyncMessageReturn
getMessageReturn() {
429 return fMessageReturn
;
433 public boolean isVisible(int x
, int y
, int width
, int height
) {
434 int toDrawY
= getY();
435 int toDrawHeight
= getHeight();
436 if ((toDrawY
> y
+ height
+ Metrics
.MESSAGES_NAME_SPACING
+ Metrics
.getMessageFontHeigth()) && (toDrawY
+ toDrawHeight
> y
+ height
+ Metrics
.MESSAGES_NAME_SPACING
+ Metrics
.getMessageFontHeigth())) {
439 if (toDrawY
< y
&& (toDrawY
+ toDrawHeight
< y
)) {
442 return super.isVisible(x
, y
, width
, height
);
446 public Comparator
<GraphNode
> getComparator() {
447 return new SortAsyncMessageComparator();
451 public String
getArrayId() {
452 return ASYNC_MESS_TAG
;
456 public Comparator
<GraphNode
> getBackComparator() {
457 return new SortAsyncForBackward();
461 public boolean positiveDistanceToPoint(int x
, int y
) {
463 int mH
= getHeight();
464 if ((mY
> y
) || (mY
+ mH
> y
)) {