1 /**********************************************************************
2 * Copyright (c) 2005, 2008 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
9 * IBM - Initial API and implementation
10 * Bernd Hufmann - Updated for TMF
11 **********************************************************************/
12 package org
.eclipse
.linuxtools
.tmf
.ui
.views
.uml2sd
.core
;
14 import java
.util
.Comparator
;
16 import org
.eclipse
.linuxtools
.tmf
.core
.event
.ITmfTimestamp
;
17 import org
.eclipse
.linuxtools
.tmf
.core
.event
.TmfTimestamp
;
18 import org
.eclipse
.linuxtools
.tmf
.ui
.views
.uml2sd
.drawings
.IGC
;
19 import org
.eclipse
.linuxtools
.tmf
.ui
.views
.uml2sd
.preferences
.ISDPreferences
;
20 import org
.eclipse
.linuxtools
.tmf
.ui
.views
.uml2sd
.preferences
.SDViewPref
;
21 import org
.eclipse
.linuxtools
.tmf
.ui
.views
.uml2sd
.util
.SortAsyncForBackward
;
22 import org
.eclipse
.linuxtools
.tmf
.ui
.views
.uml2sd
.util
.SortAsyncMessageComparator
;
25 * A AsyncMessage is a asynchronous message which appear at two different event occurrences on each lifeline ends (sender
36 * AsyncMessage message = new AsyncMessage();
37 * // Create a new event occurrence on each lifeline
38 * lifeline1.getNewOccurrenceIndex();
39 * lifeline2.getNewOccurrenceIndex();
40 * // Set the message sender and receiver
41 * message.setStartLifeline(lifeLine1);
42 * message.setEndLifline(lifeline2);
43 * message.setName("Message label");
44 * // add the message to the frame
45 * frame.addMessage(message);
48 * @see Lifeline Lifeline for more event occurence details
52 public class AsyncMessage
extends BaseMessage
implements ITimeRange
{
54 // ------------------------------------------------------------------------
56 // ------------------------------------------------------------------------
58 * The grahNode ID constant
60 public static final String ASYNC_MESS_TAG
= "AsyncMessage"; //$NON-NLS-1$
62 // ------------------------------------------------------------------------
64 // ------------------------------------------------------------------------
66 * Flag whether message has time information or not.
68 protected boolean fHasTime
= false;
70 * The time when the message begin
72 protected ITmfTimestamp fEndTime
= new TmfTimestamp();
74 * The time when the message end
76 protected ITmfTimestamp fStartTime
= new TmfTimestamp();
78 * The associated message.
80 protected AsyncMessageReturn fMessageReturn
= null;
82 // ------------------------------------------------------------------------
84 // ------------------------------------------------------------------------
88 public AsyncMessage() {
89 fPrefId
= ISDPreferences
.PREF_ASYNC_MESS
;
92 // ------------------------------------------------------------------------
94 // ------------------------------------------------------------------------
97 * @see org.eclipse.linuxtools.tmf.ui.views.uml2sd.core.BaseMessage#getX()
101 int x
= super.getX(true);
102 int activationWidth
= Metrics
.EXECUTION_OCCURRENCE_WIDTH
/ 2;
103 if ((fStartLifeline
!= null) && (fEndLifeline
!= null) && (fStartLifeline
.getX() > fEndLifeline
.getX())) {
104 activationWidth
= -activationWidth
;
107 if (isMessageStartInActivation(fStartEventOccurrence
)) {
108 x
= x
+ activationWidth
;
115 * @see org.eclipse.linuxtools.tmf.ui.views.uml2sd.core.BaseMessage#getY()
119 if ((fStartLifeline
!= null) && (fEndLifeline
!= null)) {
120 return fEndLifeline
.getY() + fEndLifeline
.getHeight() + (Metrics
.getMessageFontHeigth() + Metrics
.getMessagesSpacing()) * fStartEventOccurrence
;
127 * @see org.eclipse.linuxtools.tmf.ui.views.uml2sd.core.BaseMessage#getWidth()
130 public int getWidth() {
131 int width
= super.getWidth(true);
132 int activationWidth
= Metrics
.EXECUTION_OCCURRENCE_WIDTH
/ 2;
133 if ((fStartLifeline
!= null) && (fEndLifeline
!= null) && (fStartLifeline
.getX() > fEndLifeline
.getX())) {
134 activationWidth
= -activationWidth
;
137 if (isMessageStartInActivation(fStartEventOccurrence
)) {
138 width
= width
- activationWidth
;
141 if (isMessageEndInActivation(fEndEventOccurrence
)) {
142 width
= width
- activationWidth
;
150 * @see org.eclipse.linuxtools.tmf.ui.views.uml2sd.core.BaseMessage#getHeight()
153 public int getHeight() {
154 if ((fStartLifeline
!= null) && (fEndLifeline
!= null)) {
155 return (fEndLifeline
.getY() + fEndLifeline
.getHeight() + (Metrics
.getMessageFontHeigth() + Metrics
.getMessagesSpacing()) * fEndEventOccurrence
) - getY();
157 return super.getHeight();
161 * Set the message return associated with this message.
163 * @param message the message return to associate
165 protected void setMessageReturn(AsyncMessageReturn message
) {
166 fMessageReturn
= message
;
170 * Set the event occurrence attached to this message for its end lifeline
172 * @param occurrence the event occurrence to set
174 public void setEndOccurrence(int occurrence
) {
175 fEndEventOccurrence
= occurrence
;
176 if (getStartLifeline() == null) {
177 fStartEventOccurrence
= occurrence
;
179 informFrame(getEndLifeline(), occurrence
);
183 * Informs the given lifeline about the maximum occurrence if applicable.
188 protected void informFrame(Lifeline lifeLine
, int occurrence
) {
189 if ((lifeLine
!= null) && (lifeLine
.getFrame() != null) && (lifeLine
.getFrame().getMaxEventOccurrence() < occurrence
)) {
190 lifeLine
.getFrame().setMaxEventOccurrence(occurrence
);
195 * Set the event occurrence attached to this message for its start lifeline
197 * @param occurrence the event occurrence to set
199 public void setStartOccurrence(int occurrence
) {
200 fStartEventOccurrence
= occurrence
;
201 if (getEndLifeline() == null) {
202 fEndEventOccurrence
= fStartEventOccurrence
;
204 informFrame(getStartLifeline(), occurrence
);
208 * Set the lifeLine which has sent the message.<br>
209 * A new EventOccurence will be create on this lifeLine.<br>
211 * @param lifeline the message sender
213 public void autoSetStartLifeline(Lifeline lifeline
) {
214 lifeline
.getNewEventOccurrence();
215 setStartLifeline(lifeline
);
219 * Set the lifeLine which has received the message.<br>
220 * A new EventOccurence will be create on this lifeLine.<br>
222 * @param lifeline the message receiver
224 public void autoSetEndLifeline(Lifeline lifeline
) {
225 lifeline
.getNewEventOccurrence();
226 setEndLifeline(lifeline
);
231 * @see org.eclipse.linuxtools.tmf.ui.views.uml2sd.core.BaseMessage#setStartLifeline(org.eclipse.linuxtools.tmf.ui.views.uml2sd.core.Lifeline)
234 public void setStartLifeline(Lifeline lifeline
) {
235 super.setStartLifeline(lifeline
);
236 setStartOccurrence(getStartLifeline().getEventOccurrence());
237 if (getEndLifeline() == null) {
238 fEndEventOccurrence
= fStartEventOccurrence
;
244 * @see org.eclipse.linuxtools.tmf.ui.views.uml2sd.core.BaseMessage#setEndLifeline(org.eclipse.linuxtools.tmf.ui.views.uml2sd.core.Lifeline)
247 public void setEndLifeline(Lifeline lifeline
) {
248 super.setEndLifeline(lifeline
);
249 setEventOccurrence(getEndLifeline().getEventOccurrence());
253 * Returns true if the point C is on the segment defined with the point A and B
255 * @param xA point A x coordinate
256 * @param yA point A y coordinate
257 * @param xB point B x coordinate
258 * @param yB point B y coordinate
259 * @param xC point C x coordinate
260 * @param yC point C y coordinate
261 * @return Return true if the point C is on the segment defined with the point A and B, else otherwise
263 protected boolean isNearSegment(int xA
, int yA
, int xB
, int yB
, int xC
, int yC
) {
264 if ((xA
> xB
) && (xC
> xA
)) {
267 if ((xA
< xB
) && (xC
> xB
)) {
270 if ((xA
< xB
) && (xC
< xA
)) {
273 if ((xA
> xB
) && (xC
< xB
)) {
276 double distAB
= Math
.sqrt((xB
- xA
) * (xB
- xA
) + (yB
- yA
) * (yB
- yA
));
277 double scalar
= ((xB
- xA
) * (xC
- xA
) + (yB
- yA
) * (yC
- yA
)) / distAB
;
278 double distAC
= Math
.sqrt((xC
- xA
) * (xC
- xA
) + (yC
- yA
) * (yC
- yA
));
279 double distToSegment
= Math
.sqrt(Math
.abs(distAC
* distAC
- scalar
* scalar
));
280 if (distToSegment
<= Metrics
.MESSAGE_SELECTION_TOLERANCE
) {
288 * @see org.eclipse.linuxtools.tmf.ui.views.uml2sd.core.BaseMessage#contains(int, int)
291 public boolean contains(int x
, int y
) {
292 // Is it a self message?
293 if (fStartLifeline
== fEndLifeline
) {
294 return super.contains(x
, y
);
296 if (isNearSegment(getX(), getY(), getX() + getWidth(), getY() + getHeight(), x
, y
)) {
299 int messageMaxWidth
= Metrics
.swimmingLaneWidth() - Metrics
.EXECUTION_OCCURRENCE_WIDTH
;
300 int nameWidth
= getName().length() * Metrics
.getAverageCharWidth();
301 if (getName().length() * Metrics
.getAverageCharWidth() > messageMaxWidth
) {
302 if (Frame
.contains(getX(), getY() - Metrics
.MESSAGES_NAME_SPACING
- Metrics
.getMessageFontHeigth(), messageMaxWidth
, Metrics
.getMessageFontHeigth(), x
, y
)) {
306 if (Frame
.contains(getX() + (messageMaxWidth
- nameWidth
) / 2, getY() + getHeight() / 2 - Metrics
.MESSAGES_NAME_SPACING
- Metrics
.getMessageFontHeigth(), nameWidth
, Metrics
.getMessageFontHeigth(), x
, y
)) {
314 * Draws the asynchronous message using giving graphical context.
316 * @param context A graphical context to draw in.
318 protected void drawAsyncMessage(IGC context
) {
319 if (fStartLifeline
!= null && fEndLifeline
!= null && fStartLifeline
== fEndLifeline
&& (fStartEventOccurrence
!= fEndEventOccurrence
)) {
322 int height
= getHeight();
324 boolean startInActivation
= isMessageStartInActivation(fStartEventOccurrence
);
325 boolean endInActivation
= isMessageEndInActivation(fEndEventOccurrence
);
327 if (endInActivation
&& !startInActivation
) {
328 tempx
= Metrics
.EXECUTION_OCCURRENCE_WIDTH
/ 2;
330 if (startInActivation
&& !endInActivation
) {
331 tempx
= -Metrics
.EXECUTION_OCCURRENCE_WIDTH
/ 2;
334 int tempy
= Metrics
.INTERNAL_MESSAGE_WIDTH
/ 2;
335 if (getHeight() <= Metrics
.INTERNAL_MESSAGE_WIDTH
) {
336 tempy
= getHeight() / 2;
339 context
.drawLine(x
, y
, x
+ Metrics
.INTERNAL_MESSAGE_WIDTH
/ 2, y
);
340 context
.drawLine(x
+ Metrics
.INTERNAL_MESSAGE_WIDTH
, y
+ tempy
, x
+ Metrics
.INTERNAL_MESSAGE_WIDTH
, y
+ height
- tempy
);
341 context
.drawLine(x
+ tempx
, y
+ height
, x
+ Metrics
.INTERNAL_MESSAGE_WIDTH
/ 2, y
+ height
);
343 Double xt
= Double
.valueOf(Math
.cos(0.75) * 7);
344 Double yt
= Double
.valueOf(Math
.sin(0.75) * 7);
346 context
.drawLine(x
+ xt
.intValue() + tempx
, y
+ height
+ yt
.intValue(), x
+ tempx
, y
+ height
);
347 context
.drawArc(x
, y
, Metrics
.INTERNAL_MESSAGE_WIDTH
, 2 * tempy
, 0, 90);
348 context
.drawArc(x
, y
+ height
, Metrics
.INTERNAL_MESSAGE_WIDTH
, -2 * tempy
, 0, -90);
349 context
.drawLine(x
+ xt
.intValue() + tempx
, y
+ height
- yt
.intValue(), x
+ tempx
, y
+ height
);
351 context
.drawTextTruncated(getName(), x
+ Metrics
.INTERNAL_MESSAGE_WIDTH
+ Metrics
.INTERNAL_MESSAGE_V_MARGIN
, y
, Metrics
.swimmingLaneWidth() - Metrics
.EXECUTION_OCCURRENCE_WIDTH
+ -Metrics
.INTERNAL_MESSAGE_WIDTH
,
352 +Metrics
.MESSAGES_NAME_SPACING
- Metrics
.getMessageFontHeigth(), !isSelected());
360 * @see org.eclipse.linuxtools.tmf.ui.views.uml2sd.core.BaseMessage#draw(org.eclipse.linuxtools.tmf.ui.views.uml2sd.drawings.IGC)
363 public void draw(IGC context
) {
368 ISDPreferences pref
= SDViewPref
.getInstance();
371 if (isSelected() && (fStartLifeline
!= null && fEndLifeline
!= null && fStartLifeline
== fEndLifeline
&& (fStartEventOccurrence
!= fEndEventOccurrence
))) {
373 * Draw it twice First time, bigger inverting selection colors Second time, regular drawing using selection
374 * colors This create the highlight effect
376 context
.setForeground(pref
.getBackGroundColorSelection());
377 context
.setLineWidth(Metrics
.SELECTION_LINE_WIDTH
);
378 drawAsyncMessage(context
);
379 context
.setBackground(pref
.getBackGroundColorSelection());
380 context
.setForeground(pref
.getForeGroundColorSelection());
381 // Second drawing is done after the else
383 context
.setBackground(pref
.getBackGroundColor(fPrefId
));
384 context
.setForeground(pref
.getForeGroundColor(fPrefId
));
387 context
.setDrawTextWithFocusStyle(true);
389 context
.setLineWidth(Metrics
.NORMAL_LINE_WIDTH
);
390 drawAsyncMessage(context
);
392 context
.setDrawTextWithFocusStyle(false);
397 * Set the time when the message end
399 * @param time the time when the message end
401 public void setEndTime(ITmfTimestamp time
) {
402 fEndTime
= time
.clone();
404 if (getStartLifeline() != null && getStartLifeline().getFrame() != null) {
405 getStartLifeline().getFrame().setHasTimeInfo(true);
406 } else if (getEndLifeline() != null && getEndLifeline().getFrame() != null) {
407 getEndLifeline().getFrame().setHasTimeInfo(true);
412 * Set the time when the message start
414 * @param time the time when the message start
416 public void setStartTime(ITmfTimestamp time
) {
417 fStartTime
= time
.clone();
419 if (getStartLifeline() != null && getStartLifeline().getFrame() != null) {
420 getStartLifeline().getFrame().setHasTimeInfo(true);
421 } else if (getEndLifeline() != null && getEndLifeline().getFrame() != null) {
422 getEndLifeline().getFrame().setHasTimeInfo(true);
428 * @see org.eclipse.linuxtools.tmf.ui.views.uml2sd.core.ITimeRange#getEndTime()
431 public ITmfTimestamp
getEndTime() {
437 * @see org.eclipse.linuxtools.tmf.ui.views.uml2sd.core.ITimeRange#getStartTime()
440 public ITmfTimestamp
getStartTime() {
446 * @see org.eclipse.linuxtools.tmf.ui.views.uml2sd.core.ITimeRange#hasTimeInfo()
449 public boolean hasTimeInfo() {
455 * @see org.eclipse.linuxtools.tmf.ui.views.uml2sd.core.BaseMessage#isVisible(int, int, int, int)
458 public boolean isVisible(int x
, int y
, int width
, int height
) {
459 int toDrawY
= getY();
460 int toDrawHeight
= getHeight();
461 if ((toDrawY
> y
+ height
+ Metrics
.MESSAGES_NAME_SPACING
+ Metrics
.getMessageFontHeigth()) && (toDrawY
+ toDrawHeight
> y
+ height
+ Metrics
.MESSAGES_NAME_SPACING
+ Metrics
.getMessageFontHeigth())) {
464 if (toDrawY
< y
&& (toDrawY
+ toDrawHeight
< y
)) {
467 return super.isVisible(x
, y
, width
, height
);
472 * @see org.eclipse.linuxtools.tmf.ui.views.uml2sd.core.GraphNode#getComparator()
475 public Comparator
<GraphNode
> getComparator() {
476 return new SortAsyncMessageComparator();
481 * @see org.eclipse.linuxtools.tmf.ui.views.uml2sd.core.GraphNode#getArrayId()
484 public String
getArrayId() {
485 return ASYNC_MESS_TAG
;
490 * @see org.eclipse.linuxtools.tmf.ui.views.uml2sd.core.GraphNode#getBackComparator()
493 public Comparator
<GraphNode
> getBackComparator() {
494 return new SortAsyncForBackward();
499 * @see org.eclipse.linuxtools.tmf.ui.views.uml2sd.core.GraphNode#positiveDistanceToPoint(int, int)
502 public boolean positiveDistanceToPoint(int x
, int y
) {
504 int mH
= getHeight();
505 if ((mY
> y
) || (mY
+ mH
> y
)) {