Commit | Line | Data |
---|---|---|
73005152 BH |
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: AsyncMessage.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 java.util.Comparator; | |
16 | ||
4df4581d | 17 | import org.eclipse.linuxtools.tmf.core.event.ITmfTimestamp; |
6c13869b | 18 | import org.eclipse.linuxtools.tmf.core.event.TmfTimestamp; |
73005152 BH |
19 | import org.eclipse.linuxtools.tmf.ui.views.uml2sd.drawings.IGC; |
20 | import org.eclipse.linuxtools.tmf.ui.views.uml2sd.drawings.ISDPreferences; | |
21 | import org.eclipse.linuxtools.tmf.ui.views.uml2sd.util.SortAsyncForBackward; | |
22 | import org.eclipse.linuxtools.tmf.ui.views.uml2sd.util.SortAsyncMessageComparator; | |
23 | ||
24 | /** | |
25 | * A AsyncMessage is a asynchronous message which appear at two different event occurrences on each lifeline ends (sender | |
26 | * and receiver).<br> | |
27 | * <br> | |
28 | * <br> | |
29 | * Usage example: | |
30 | * | |
31 | * <pre> | |
32 | * Frame frame; | |
33 | * Lifeline lifeLine1; | |
34 | * Lifeline lifeLine2; | |
35 | * | |
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); | |
46 | * </pre> | |
47 | * | |
48 | * @see Lifeline Lifeline for more event occurence details | |
49 | * @author sveyrier | |
50 | * | |
51 | */ | |
52 | public class AsyncMessage extends BaseMessage implements ITimeRange { | |
53 | ||
54 | protected boolean hasTime = false; | |
55 | /** | |
56 | * The time when the message begin | |
57 | */ | |
4df4581d | 58 | protected ITmfTimestamp endTime = new TmfTimestamp(); |
73005152 BH |
59 | |
60 | /** | |
61 | * The time when the message end | |
62 | */ | |
4df4581d | 63 | protected ITmfTimestamp startTime = new TmfTimestamp(); |
73005152 BH |
64 | |
65 | /** | |
66 | * The associated message. | |
67 | */ | |
68 | protected AsyncMessageReturn messageReturn = null; | |
69 | ||
70 | public static final String ASYNC_MESS_TAG = "AsyncMessage"; //$NON-NLS-1$ | |
71 | ||
72 | public AsyncMessage() { | |
73 | prefId = ISDPreferences.PREF_ASYNC_MESS; | |
74 | } | |
75 | ||
76 | @Override | |
77 | public int getX() { | |
78 | int x = super.getX(true); | |
79 | int activationWidth = Metrics.EXECUTION_OCCURRENCE_WIDTH / 2; | |
80 | if ((startLifeline != null) && (endLifeline != null) && (startLifeline.getX() > endLifeline.getX())) { | |
81 | activationWidth = -activationWidth; | |
82 | } | |
83 | ||
84 | if (isMessageStartInActivation(startEventOccurrence)) { | |
85 | x = x + activationWidth; | |
86 | } | |
87 | return x; | |
88 | } | |
89 | ||
90 | @Override | |
91 | public int getY() { | |
92 | if ((startLifeline != null) && (endLifeline != null)) { | |
93 | return endLifeline.getY() + endLifeline.getHeight() + (Metrics.getMessageFontHeigth() + Metrics.getMessagesSpacing()) * startEventOccurrence; | |
94 | } | |
95 | return super.getY(); | |
96 | } | |
97 | ||
98 | @Override | |
99 | public int getWidth() { | |
100 | int width = super.getWidth(true); | |
101 | int activationWidth = Metrics.EXECUTION_OCCURRENCE_WIDTH / 2; | |
102 | if ((startLifeline != null) && (endLifeline != null) && (startLifeline.getX() > endLifeline.getX())) { | |
103 | activationWidth = -activationWidth; | |
104 | } | |
105 | ||
106 | if (isMessageStartInActivation(startEventOccurrence)) | |
107 | width = width - activationWidth; | |
108 | ||
109 | if (isMessageEndInActivation(endEventOccurrence)) | |
110 | width = width - activationWidth; | |
111 | ||
112 | return width; | |
113 | } | |
114 | ||
115 | @Override | |
116 | public int getHeight() { | |
117 | if ((startLifeline != null) && (endLifeline != null)) { | |
118 | return (endLifeline.getY() + endLifeline.getHeight() + (Metrics.getMessageFontHeigth() + Metrics.getMessagesSpacing()) * endEventOccurrence) - getY(); | |
119 | } | |
120 | return super.getHeight(); | |
121 | } | |
122 | ||
123 | /** | |
124 | * Set the message return associated with this message. | |
125 | * | |
126 | * @param message the message return to associate | |
127 | */ | |
128 | protected void setMessageReturn(AsyncMessageReturn message) { | |
129 | messageReturn = message; | |
130 | } | |
131 | ||
132 | /** | |
133 | * Set the event occurrence attached to this message for its end lifeline | |
134 | * | |
135 | * @param occurrence the event occurrence to set | |
136 | */ | |
137 | public void setEndOccurrence(int occurrence) { | |
138 | endEventOccurrence = occurrence; | |
139 | if (getStartLifeline() == null) | |
140 | startEventOccurrence = occurrence; | |
141 | informFrame(getEndLifeline(), occurrence); | |
142 | } | |
143 | ||
144 | protected void informFrame(Lifeline lifeLine, int occurrence) { | |
145 | if ((lifeLine != null) && (lifeLine.getFrame() != null)) | |
146 | if (lifeLine.getFrame().getMaxEventOccurrence() < occurrence) | |
147 | lifeLine.getFrame().setMaxEventOccurrence(occurrence); | |
148 | } | |
149 | ||
150 | /** | |
151 | * Set the event occurrence attached to this message for its start lifeline | |
152 | * | |
153 | * @param occurrence the event occurrence to set | |
154 | */ | |
155 | public void setStartOccurrence(int occurrence) { | |
156 | startEventOccurrence = occurrence; | |
157 | if (getEndLifeline() == null) | |
158 | endEventOccurrence = startEventOccurrence; | |
159 | informFrame(getStartLifeline(), occurrence); | |
160 | } | |
161 | ||
162 | /** | |
163 | * Set the lifeLine which has sent the message.<br> | |
164 | * A new EventOccurence will be create on this lifeLine.<br> | |
165 | * | |
166 | * @param lifeline the message sender | |
167 | * @param autoCreateEvent if true, create an eventOccurence lifeline given in parameter | |
168 | */ | |
169 | public void autoSetStartLifeline(Lifeline lifeline) { | |
170 | lifeline.getNewEventOccurrence(); | |
171 | setStartLifeline(lifeline); | |
172 | } | |
173 | ||
174 | /** | |
175 | * Set the lifeLine which has received the message.<br> | |
176 | * A new EventOccurence will be create on this lifeLine.<br> | |
177 | * | |
178 | * @param lifeline the message receiver | |
179 | * @param autoCreateEvent if true, create an eventOccurence lifeline given in parameter | |
180 | */ | |
181 | public void autoSetEndLifeline(Lifeline lifeline) { | |
182 | lifeline.getNewEventOccurrence(); | |
183 | setEndLifeline(lifeline); | |
184 | } | |
185 | ||
186 | /** | |
187 | * Set the lifeLine which has sent the message.<br> | |
188 | * | |
189 | * @param lifeline the message sender | |
190 | */ | |
191 | @Override | |
192 | public void setStartLifeline(Lifeline lifeline) { | |
193 | super.setStartLifeline(lifeline); | |
194 | setStartOccurrence(getStartLifeline().getEventOccurrence()); | |
195 | if (getEndLifeline() == null) | |
196 | endEventOccurrence = startEventOccurrence; | |
197 | } | |
198 | ||
199 | /** | |
200 | * Set the lifeLine which has received the message.<br> | |
201 | * | |
202 | * @param lifeline the message receiver | |
203 | */ | |
204 | @Override | |
205 | public void setEndLifeline(Lifeline lifeline) { | |
206 | super.setEndLifeline(lifeline); | |
207 | setEventOccurrence(getEndLifeline().getEventOccurrence()); | |
208 | } | |
209 | ||
210 | /** | |
211 | * Returns true if the point C is on the segment defined with the point A and B | |
212 | * | |
213 | * @param xA point A x coordinate | |
214 | * @param yA point A y coordinate | |
215 | * @param xB point B x coordinate | |
216 | * @param yB point B y coordinate | |
217 | * @param xC point C x coordinate | |
218 | * @param yC point C y coordinate | |
219 | * @return Return true if the point C is on the segment defined with the point A and B, else otherwise | |
220 | */ | |
221 | protected boolean isNearSegment(int xA, int yA, int xB, int yB, int xC, int yC) { | |
222 | if ((xA > xB) && (xC > xA)) | |
223 | return false; | |
224 | if ((xA < xB) && (xC > xB)) | |
225 | return false; | |
226 | if ((xA < xB) && (xC < xA)) | |
227 | return false; | |
228 | if ((xA > xB) && (xC < xB)) | |
229 | return false; | |
230 | double distAB = Math.sqrt((xB - xA) * (xB - xA) + (yB - yA) * (yB - yA)); | |
231 | double scalar = ((xB - xA) * (xC - xA) + (yB - yA) * (yC - yA)) / distAB; | |
232 | double distAC = Math.sqrt((xC - xA) * (xC - xA) + (yC - yA) * (yC - yA)); | |
233 | double distToSegment = Math.sqrt(Math.abs(distAC * distAC - scalar * scalar)); | |
234 | if (distToSegment <= Metrics.MESSAGE_SELECTION_TOLERANCE) | |
235 | return true; | |
236 | return false; | |
237 | } | |
238 | ||
239 | @Override | |
240 | public boolean contains(int x, int y) { | |
241 | // Is it a self message? | |
242 | if (startLifeline == endLifeline) { | |
243 | return super.contains(x, y); | |
244 | } | |
245 | if (isNearSegment(getX(), getY(), getX() + getWidth(), getY() + getHeight(), x, y)) | |
246 | return true; | |
247 | int messageMaxWidth = Metrics.swimmingLaneWidth() - Metrics.EXECUTION_OCCURRENCE_WIDTH; | |
248 | int nameWidth = getName().length() * Metrics.getAverageCharWidth(); | |
249 | if (getName().length() * Metrics.getAverageCharWidth() > messageMaxWidth) { | |
250 | if (Frame.contains(getX(), getY() - Metrics.MESSAGES_NAME_SPACING - Metrics.getMessageFontHeigth(), messageMaxWidth, Metrics.getMessageFontHeigth(), x, y)) | |
251 | return true; | |
252 | } else { | |
253 | if (Frame.contains(getX() + (messageMaxWidth - nameWidth) / 2, getY() + getHeight() / 2 - Metrics.MESSAGES_NAME_SPACING - Metrics.getMessageFontHeigth(), nameWidth, Metrics.getMessageFontHeigth(), x, y)) | |
254 | return true; | |
255 | } | |
256 | return false; | |
257 | } | |
258 | ||
259 | protected void drawAsyncMessage(IGC context) { | |
260 | if (startLifeline != null && endLifeline != null && startLifeline == endLifeline && (startEventOccurrence != endEventOccurrence)) { | |
261 | int x = getX(); | |
262 | int y = getY(); | |
263 | int height = getHeight(); | |
264 | int tempx = 0; | |
265 | boolean startInActivation = isMessageStartInActivation(startEventOccurrence); | |
266 | boolean endInActivation = isMessageEndInActivation(endEventOccurrence); | |
267 | ||
268 | if (endInActivation && !startInActivation) | |
269 | tempx = Metrics.EXECUTION_OCCURRENCE_WIDTH / 2; | |
270 | if (startInActivation && !endInActivation) | |
271 | tempx = -Metrics.EXECUTION_OCCURRENCE_WIDTH / 2; | |
272 | ||
273 | int tempy = Metrics.INTERNAL_MESSAGE_WIDTH / 2; | |
274 | if (getHeight() <= Metrics.INTERNAL_MESSAGE_WIDTH) | |
275 | tempy = getHeight() / 2; | |
276 | ||
277 | context.drawLine(x, y, x + Metrics.INTERNAL_MESSAGE_WIDTH / 2, y); | |
278 | context.drawLine(x + Metrics.INTERNAL_MESSAGE_WIDTH, y + tempy, x + Metrics.INTERNAL_MESSAGE_WIDTH, y + height - tempy); | |
279 | context.drawLine(x + tempx, y + height, x + Metrics.INTERNAL_MESSAGE_WIDTH / 2, y + height); | |
280 | ||
281 | Double xt = new Double(Math.cos(0.75) * 7); | |
282 | Double yt = new Double(Math.sin(0.75) * 7); | |
283 | ||
284 | context.drawLine(x + xt.intValue() + tempx, y + height + yt.intValue(), x + tempx, y + height); | |
285 | context.drawArc(x, y, Metrics.INTERNAL_MESSAGE_WIDTH, 2 * tempy, 0, 90); | |
286 | context.drawArc(x, y + height, Metrics.INTERNAL_MESSAGE_WIDTH, -2 * tempy, 0, -90); | |
287 | context.drawLine(x + xt.intValue() + tempx, y + height - yt.intValue(), x + tempx, y + height); | |
288 | ||
289 | context.drawTextTruncated(getName(), x + Metrics.INTERNAL_MESSAGE_WIDTH + Metrics.INTERNAL_MESSAGE_V_MARGIN, y, Metrics.swimmingLaneWidth() - Metrics.EXECUTION_OCCURRENCE_WIDTH + -Metrics.INTERNAL_MESSAGE_WIDTH, | |
290 | +Metrics.MESSAGES_NAME_SPACING - Metrics.getMessageFontHeigth(), !isSelected()); | |
291 | } else | |
292 | super.draw(context); | |
293 | } | |
294 | ||
295 | /** | |
296 | * Draws the asynchronous message in the given GC | |
297 | */ | |
298 | @Override | |
299 | public void draw(IGC context) { | |
300 | if (!isVisible()) | |
301 | return; | |
302 | // Draw it selected? | |
303 | if (isSelected() && (startLifeline != null && endLifeline != null && startLifeline == endLifeline && (startEventOccurrence != endEventOccurrence))) { | |
304 | /* | |
305 | * Draw it twice First time, bigger inverting selection colors Second time, regular drawing using selection | |
306 | * colors This create the highlight effect | |
307 | */ | |
308 | context.setForeground(Frame.getUserPref().getBackGroundColorSelection()); | |
309 | context.setLineWidth(Metrics.SELECTION_LINE_WIDTH); | |
310 | drawAsyncMessage(context); | |
311 | context.setBackground(Frame.getUserPref().getBackGroundColorSelection()); | |
312 | context.setForeground(Frame.getUserPref().getForeGroundColorSelection()); | |
313 | // Second drawing is done after the else | |
314 | } else { | |
315 | context.setBackground(Frame.getUserPref().getBackGroundColor(prefId)); | |
316 | context.setForeground(Frame.getUserPref().getForeGroundColor(prefId)); | |
317 | } | |
318 | if (hasFocus()) { | |
319 | context.setDrawTextWithFocusStyle(true); | |
320 | } | |
321 | context.setLineWidth(Metrics.NORMAL_LINE_WIDTH); | |
322 | drawAsyncMessage(context); | |
323 | if (hasFocus()) { | |
324 | context.setDrawTextWithFocusStyle(false); | |
325 | } | |
326 | } | |
327 | ||
328 | /** | |
329 | * Set the time when the message end | |
330 | * | |
331 | * @param time the time when the message end | |
332 | */ | |
4df4581d | 333 | public void setEndTime(ITmfTimestamp time) { |
73005152 BH |
334 | endTime = time.clone(); |
335 | hasTime = true; | |
336 | if (getStartLifeline() != null && getStartLifeline().getFrame() != null) | |
337 | getStartLifeline().getFrame().setHasTimeInfo(true); | |
338 | else if (getEndLifeline() != null && getEndLifeline().getFrame() != null) | |
339 | getEndLifeline().getFrame().setHasTimeInfo(true); | |
340 | } | |
341 | ||
342 | /** | |
343 | * Set the time when the message start | |
344 | * | |
345 | * @param time the time when the message start | |
346 | */ | |
4df4581d | 347 | public void setStartTime(ITmfTimestamp time) { |
73005152 BH |
348 | startTime = time.clone(); |
349 | hasTime = true; | |
350 | if (getStartLifeline() != null && getStartLifeline().getFrame() != null) | |
351 | getStartLifeline().getFrame().setHasTimeInfo(true); | |
352 | else if (getEndLifeline() != null && getEndLifeline().getFrame() != null) | |
353 | getEndLifeline().getFrame().setHasTimeInfo(true); | |
354 | } | |
355 | ||
356 | /** | |
357 | * Returns the time when the message begin | |
358 | * | |
359 | * @return the time | |
360 | */ | |
361 | @Override | |
4df4581d | 362 | public ITmfTimestamp getEndTime() { |
73005152 BH |
363 | return endTime; |
364 | } | |
365 | ||
366 | /** | |
367 | * Returns the time when the message end | |
368 | * | |
369 | * @return the time | |
370 | */ | |
371 | @Override | |
4df4581d | 372 | public ITmfTimestamp getStartTime() { |
73005152 BH |
373 | return startTime; |
374 | } | |
375 | ||
376 | @Override | |
377 | public boolean hasTimeInfo() { | |
378 | return hasTime; | |
379 | } | |
380 | ||
381 | @Override | |
382 | public boolean isVisible(int x, int y, int width, int height) { | |
383 | int toDrawY = getY(); | |
384 | int toDrawHeight = getHeight(); | |
385 | if ((toDrawY > y + height + Metrics.MESSAGES_NAME_SPACING + Metrics.getMessageFontHeigth()) && (toDrawY + toDrawHeight > y + height + Metrics.MESSAGES_NAME_SPACING + Metrics.getMessageFontHeigth())) | |
386 | return false; | |
387 | if (toDrawY < y && (toDrawY + toDrawHeight < y)) | |
388 | return false; | |
389 | return super.isVisible(x, y, width, height); | |
390 | } | |
391 | ||
392 | @Override | |
393 | public Comparator<GraphNode> getComparator() { | |
394 | return new SortAsyncMessageComparator(); | |
395 | } | |
396 | ||
397 | @Override | |
398 | public String getArrayId() { | |
399 | return ASYNC_MESS_TAG; | |
400 | } | |
401 | ||
402 | @Override | |
403 | public Comparator<GraphNode> getBackComparator() { | |
404 | return new SortAsyncForBackward(); | |
405 | } | |
406 | ||
407 | @Override | |
408 | public boolean positiveDistanceToPoint(int x, int y) { | |
409 | int mY = getY(); | |
410 | int mH = getHeight(); | |
411 | if ((mY > y) || (mY + mH > y)) | |
412 | return true; | |
413 | return false; | |
414 | } | |
415 | } |