Commit | Line | Data |
---|---|---|
73005152 | 1 | /********************************************************************** |
df0b8ff4 BH |
2 | * Copyright (c) 2005, 2008 IBM Corporation and others. |
3 | * Copyright (c) 2011, 2012 Ericsson. | |
a55887ca | 4 | * |
73005152 BH |
5 | * All rights reserved. This program and the accompanying materials |
6 | * are made available under the terms of the Eclipse Public License v1.0 | |
7 | * which accompanies this distribution, and is available at | |
8 | * http://www.eclipse.org/legal/epl-v10.html | |
a55887ca AM |
9 | * |
10 | * Contributors: | |
73005152 BH |
11 | * IBM - Initial API and implementation |
12 | * Bernd Hufmann - Updated for TMF | |
13 | **********************************************************************/ | |
14 | package org.eclipse.linuxtools.tmf.ui.views.uml2sd.core; | |
15 | ||
16 | import java.util.ArrayList; | |
17 | import java.util.Arrays; | |
18 | import java.util.Comparator; | |
19 | import java.util.HashMap; | |
20 | import java.util.Iterator; | |
21 | import java.util.List; | |
eb63f5ff | 22 | import java.util.Map; |
73005152 | 23 | |
d34665f9 | 24 | import org.eclipse.linuxtools.internal.tmf.ui.TmfUiTracer; |
73005152 | 25 | import org.eclipse.linuxtools.tmf.ui.views.uml2sd.drawings.IGC; |
df0b8ff4 | 26 | import org.eclipse.linuxtools.tmf.ui.views.uml2sd.preferences.ISDPreferences; |
3145ec83 | 27 | import org.eclipse.linuxtools.tmf.ui.views.uml2sd.preferences.SDViewPref; |
73005152 BH |
28 | |
29 | /** | |
30 | * The base class used for all UML2 graph nodes displayed in the Sequence Diagram SDWidget. | |
a55887ca | 31 | * |
73005152 BH |
32 | * @author sveyrier |
33 | * @version 1.0 | |
34 | */ | |
73005152 BH |
35 | public abstract class GraphNode { |
36 | ||
df0b8ff4 BH |
37 | // ------------------------------------------------------------------------ |
38 | // Attributes | |
39 | // ------------------------------------------------------------------------ | |
40 | /** | |
41 | * The start event occurrence. | |
42 | */ | |
eb63f5ff | 43 | protected int fStartEventOccurrence = 0; |
df0b8ff4 BH |
44 | /** |
45 | * The event event occurrence. | |
46 | */ | |
eb63f5ff | 47 | protected int fEndEventOccurrence = 0; |
73005152 BH |
48 | /** |
49 | * Preference ColorId to use to draw font | |
50 | */ | |
eb63f5ff | 51 | public String fPrefId = ISDPreferences.PREF_SYNC_MESS; |
73005152 BH |
52 | /** |
53 | * The selection state of the graph node. | |
54 | */ | |
eb63f5ff | 55 | protected boolean fSelected = false; |
73005152 BH |
56 | /** |
57 | * The focus state of the graph node. | |
58 | */ | |
eb63f5ff | 59 | protected boolean fFocused = false; |
df0b8ff4 | 60 | /** |
a55887ca | 61 | * Flag to indicate whether node has children or not. |
df0b8ff4 | 62 | */ |
eb63f5ff | 63 | protected boolean fHasChilden = false; |
73005152 BH |
64 | /** |
65 | * The graph node name used to label the graph node in the View. | |
66 | */ | |
eb63f5ff | 67 | protected String fName = ""; //$NON-NLS-1$ |
df0b8ff4 BH |
68 | /** |
69 | * A map from node name to graph node. | |
70 | */ | |
eb63f5ff | 71 | protected Map<String, List<GraphNode>> fNodes; |
df0b8ff4 BH |
72 | /** |
73 | * A map from node name to graph node for forward sorting | |
74 | */ | |
eb63f5ff | 75 | protected Map<String, List<GraphNode>> fForwardNodes; |
df0b8ff4 BH |
76 | /** |
77 | * A map from node name to graph node for backwards sorting. | |
78 | */ | |
eb63f5ff | 79 | protected Map<String, List<GraphNode>> fBackwardNodes; |
df0b8ff4 BH |
80 | /** |
81 | * A map from node name to index. | |
82 | */ | |
eb63f5ff | 83 | protected Map<String, Integer> fIndexes; |
df0b8ff4 BH |
84 | /** |
85 | * A map from node name to index for forwards sorting. | |
86 | */ | |
eb63f5ff | 87 | protected Map<String, Boolean> fForwardSort; |
df0b8ff4 | 88 | /** |
eb63f5ff | 89 | * A map from node name to index for forwards sorting. |
df0b8ff4 | 90 | */ |
eb63f5ff | 91 | protected Map<String, Boolean> fBackwardSort; |
73005152 | 92 | |
df0b8ff4 BH |
93 | // ------------------------------------------------------------------------ |
94 | // Methods | |
95 | // ------------------------------------------------------------------------ | |
a55887ca | 96 | |
73005152 BH |
97 | /** |
98 | * Reset the internal index of the first visible GraphNode for each ordered GraphNode lists | |
73005152 BH |
99 | */ |
100 | public void resetIndex() { | |
eb63f5ff | 101 | if (!fHasChilden) { |
73005152 | 102 | return; |
df0b8ff4 BH |
103 | } |
104 | ||
eb63f5ff | 105 | Iterator<String> it = fIndexes.keySet().iterator(); |
73005152 BH |
106 | while (it.hasNext()) { |
107 | String nodeType = it.next(); | |
eb63f5ff | 108 | fIndexes.put(nodeType, Integer.valueOf(0)); |
73005152 BH |
109 | } |
110 | } | |
111 | ||
112 | /** | |
113 | * Add a GraphNode into the receiver | |
a55887ca | 114 | * |
73005152 BH |
115 | * @param nodeToAdd the node to add |
116 | */ | |
117 | public void addNode(GraphNode nodeToAdd) { | |
eb63f5ff BH |
118 | if (!fHasChilden) { |
119 | fNodes = new HashMap<String, List<GraphNode>>(2); | |
120 | fForwardNodes = new HashMap<String, List<GraphNode>>(2); | |
121 | fBackwardNodes = new HashMap<String, List<GraphNode>>(2); | |
122 | fIndexes = new HashMap<String, Integer>(2); | |
123 | fBackwardSort = new HashMap<String, Boolean>(2); | |
124 | fForwardSort = new HashMap<String, Boolean>(2); | |
125 | fHasChilden = true; | |
73005152 BH |
126 | } |
127 | ||
128 | // Nothing to add | |
df0b8ff4 | 129 | if (nodeToAdd == null) { |
73005152 | 130 | return; |
df0b8ff4 | 131 | } |
73005152 | 132 | |
eb63f5ff BH |
133 | if (fNodes.get(nodeToAdd.getArrayId()) == null) { |
134 | fNodes.put(nodeToAdd.getArrayId(), new ArrayList<GraphNode>(1)); | |
135 | fIndexes.put(nodeToAdd.getArrayId(), Integer.valueOf(0)); | |
136 | fForwardNodes.put(nodeToAdd.getArrayId(), new ArrayList<GraphNode>(1)); | |
3145ec83 | 137 | fForwardSort.put(nodeToAdd.getArrayId(), Boolean.FALSE); |
73005152 | 138 | if (nodeToAdd.getBackComparator() != null) { |
eb63f5ff | 139 | fBackwardNodes.put(nodeToAdd.getArrayId(), new ArrayList<GraphNode>(1)); |
3145ec83 | 140 | fBackwardSort.put(nodeToAdd.getArrayId(), Boolean.FALSE); |
73005152 BH |
141 | } |
142 | } | |
143 | ||
abbdd66a | 144 | List<GraphNode> fNodeList = fForwardNodes.get(nodeToAdd.getArrayId()); |
73005152 | 145 | List<GraphNode> bNodeList = null; |
eb63f5ff | 146 | if (fBackwardNodes != null) { |
abbdd66a | 147 | bNodeList = fBackwardNodes.get(nodeToAdd.getArrayId()); |
df0b8ff4 | 148 | } |
73005152 BH |
149 | if (fNodeList != null && fNodeList.size() > 0) { |
150 | // check if the nodes are added y ordered | |
151 | // if not, tag the list to sort it later (during draw) | |
abbdd66a | 152 | GraphNode node = fNodeList.get(fNodeList.size() - 1); |
73005152 BH |
153 | Comparator<GraphNode> fcomp = nodeToAdd.getComparator(); |
154 | Comparator<GraphNode> bcomp = nodeToAdd.getBackComparator(); | |
f9a8715c | 155 | if ((fcomp != null) && (fcomp.compare(node, nodeToAdd) > 0)) { |
3145ec83 | 156 | fForwardSort.put(nodeToAdd.getArrayId(), Boolean.TRUE); |
73005152 | 157 | } |
f9a8715c | 158 | if ((bcomp != null) && (bcomp.compare(node, nodeToAdd) > 0)) { |
3145ec83 | 159 | fBackwardSort.put(nodeToAdd.getArrayId(), Boolean.TRUE); |
73005152 BH |
160 | } |
161 | } | |
162 | ||
163 | if (fNodeList == null) { | |
164 | fNodeList = new ArrayList<GraphNode>(); | |
165 | } | |
166 | ||
167 | fNodeList.add(nodeToAdd); | |
eb63f5ff BH |
168 | fNodes.put(nodeToAdd.getArrayId(), fNodeList); |
169 | fForwardNodes.put(nodeToAdd.getArrayId(), fNodeList); | |
73005152 BH |
170 | if (nodeToAdd.getBackComparator() != null) { |
171 | bNodeList.add(nodeToAdd); | |
eb63f5ff | 172 | fBackwardNodes.put(nodeToAdd.getArrayId(), bNodeList); |
73005152 BH |
173 | } |
174 | } | |
175 | ||
176 | /** | |
177 | * Set the graph node name.<br> | |
178 | * It is the name display in the view to label the graph node. | |
a55887ca | 179 | * |
0d9a6d76 | 180 | * @param nodeName the name to set |
73005152 BH |
181 | */ |
182 | public void setName(String nodeName) { | |
eb63f5ff | 183 | fName = nodeName; |
73005152 BH |
184 | } |
185 | ||
186 | /** | |
187 | * Returns the graph node name.<br> | |
188 | * It is the name display in the view to label the graph node. | |
a55887ca | 189 | * |
73005152 BH |
190 | * @return the graph node name |
191 | */ | |
192 | public String getName() { | |
eb63f5ff | 193 | return fName; |
73005152 BH |
194 | } |
195 | ||
196 | /** | |
197 | * Tags the the graph node has selected.<br> | |
198 | * WARNING: This method is only used to draw the graph node using the system selection colors. <br> | |
199 | * To use the complete SDViewer selection mechanism (selection management, notification, etc..) see SDWidget class | |
a55887ca | 200 | * |
73005152 BH |
201 | * @see org.eclipse.linuxtools.tmf.ui.views.uml2sd.SDWidget#addSelection(GraphNode) |
202 | * @see org.eclipse.linuxtools.tmf.ui.views.uml2sd.SDWidget#removeSelection(GraphNode) | |
203 | * @see org.eclipse.linuxtools.tmf.ui.views.uml2sd.SDWidget#clearSelection() | |
204 | * @param selection - true to set selected, false to set unselected | |
205 | */ | |
206 | public void setSelected(boolean selection) { | |
eb63f5ff | 207 | fSelected = selection; |
73005152 BH |
208 | } |
209 | ||
210 | /** | |
211 | * Tags the the graph node as focused.<br> | |
212 | * WARNING: This method is only used to draw the graph node using the system focus style. <br> | |
213 | * To use the complete SDViewer focus mechanism see SDWidget class | |
a55887ca | 214 | * |
73005152 BH |
215 | * @see org.eclipse.linuxtools.tmf.ui.views.uml2sd.SDWidget#addSelection(GraphNode) |
216 | * @see org.eclipse.linuxtools.tmf.ui.views.uml2sd.SDWidget#removeSelection(GraphNode) | |
217 | * @see org.eclipse.linuxtools.tmf.ui.views.uml2sd.SDWidget#clearSelection() | |
218 | * @param focus - true to set focued, false otherwise | |
219 | */ | |
220 | public void setFocused(boolean focus) { | |
eb63f5ff | 221 | fFocused = focus; |
73005152 BH |
222 | } |
223 | ||
224 | /** | |
225 | * Returns true if the graph node is selected, false otherwise.<br> | |
226 | * The returned value is used to highlight the graph node in the View. | |
a55887ca | 227 | * |
73005152 | 228 | * @return true if selected, false otherwise |
73005152 BH |
229 | */ |
230 | public boolean isSelected() { | |
eb63f5ff | 231 | return fSelected; |
73005152 BH |
232 | } |
233 | ||
234 | /** | |
235 | * Returns true if the graph node is focused, false otherwise.<br> | |
236 | * The returned value is used to highlight the graph node in the View. | |
a55887ca AM |
237 | * |
238 | * @return true if focused, false otherwise | |
73005152 BH |
239 | */ |
240 | public boolean hasFocus() { | |
eb63f5ff | 241 | return fFocused; |
73005152 BH |
242 | } |
243 | ||
244 | /** | |
a55887ca AM |
245 | * Returns true if the graph node contains the point given in parameter, |
246 | * return false otherwise. | |
247 | * | |
248 | * @param x | |
249 | * the x coordinate of the point to test containment | |
250 | * @param y | |
251 | * the y coordinate of the point to test containment | |
73005152 BH |
252 | * @return true if contained, false otherwise |
253 | */ | |
254 | abstract public boolean contains(int x, int y); | |
255 | ||
256 | /** | |
257 | * Returns the x coordinate of the graph node | |
a55887ca | 258 | * |
73005152 BH |
259 | * @return the x coordinate |
260 | */ | |
261 | abstract public int getX(); | |
262 | ||
263 | /** | |
264 | * Returns the y coordinate of the graph node | |
a55887ca | 265 | * |
73005152 BH |
266 | * @return the y coordinate |
267 | */ | |
268 | abstract public int getY(); | |
269 | ||
270 | /** | |
271 | * Returns the graph node height | |
a55887ca | 272 | * |
73005152 BH |
273 | * @return the graph node height |
274 | */ | |
275 | abstract public int getHeight(); | |
276 | ||
277 | /** | |
278 | * Returns the graph node width | |
a55887ca | 279 | * |
73005152 BH |
280 | * @return the graph node width |
281 | */ | |
282 | abstract public int getWidth(); | |
283 | ||
284 | /** | |
285 | * Draws the graph node in the given context | |
a55887ca | 286 | * |
73005152 BH |
287 | * @param context the graphical context to draw in |
288 | */ | |
289 | abstract protected void draw(IGC context); | |
290 | ||
291 | /** | |
a55887ca AM |
292 | * Returns the GraphNode visibility for the given visible area. Wrong |
293 | * visibility calculation, may strongly impact drawing performance | |
294 | * | |
0d9a6d76 | 295 | * @param x |
a55887ca | 296 | * The X coordinate |
0d9a6d76 | 297 | * @param y |
a55887ca | 298 | * The Y coordinate |
0d9a6d76 | 299 | * @param width |
a55887ca | 300 | * The width of the area |
0d9a6d76 | 301 | * @param height |
a55887ca AM |
302 | * The height of the area |
303 | * @return true if visible, false otherwise | |
73005152 BH |
304 | */ |
305 | public boolean isVisible(int x, int y, int width, int height) { | |
306 | return true; | |
307 | } | |
308 | ||
309 | /** | |
a55887ca AM |
310 | * Return a comparator to sort the GraphNode of the same type This |
311 | * comparator is used to order the GraphNode array of the given node type. | |
312 | * (see getArrayId). | |
313 | * | |
73005152 BH |
314 | * @return the comparator |
315 | */ | |
316 | public Comparator<GraphNode> getComparator() { | |
317 | return null; | |
318 | } | |
319 | ||
320 | /** | |
a55887ca AM |
321 | * If needed, return a different comparator to backward scan the GraphNode |
322 | * array | |
323 | * | |
73005152 BH |
324 | * @return the backward comparator or null if not needed |
325 | */ | |
326 | public Comparator<GraphNode> getBackComparator() { | |
327 | return null; | |
328 | } | |
329 | ||
330 | /** | |
331 | * Compare two graphNodes | |
a55887ca AM |
332 | * |
333 | * @param node | |
334 | * the node to compare to | |
73005152 BH |
335 | * @return true if equal false otherwise |
336 | */ | |
337 | public boolean isSameAs(GraphNode node) { | |
338 | return false; | |
339 | } | |
340 | ||
341 | /** | |
342 | * Return the node type for all class instances. This id is used to store the same nodes kind in the same ordered | |
343 | * array. | |
a55887ca | 344 | * |
73005152 BH |
345 | * @return the node type identifier |
346 | */ | |
347 | abstract public String getArrayId(); | |
348 | ||
349 | /** | |
350 | * Return true if the distance from the GraphNode to the given point is positive | |
a55887ca | 351 | * |
73005152 BH |
352 | * @param x the point x coordinate |
353 | * @param y the point y coordinate | |
354 | * @return true if positive false otherwise | |
355 | */ | |
356 | public boolean positiveDistanceToPoint(int x, int y) { | |
357 | return false; | |
358 | } | |
359 | ||
360 | /** | |
361 | * Returns the graph node which contains the point given in parameter WARNING: Only graph nodes in the current | |
362 | * visible area can be returned | |
a55887ca | 363 | * |
73005152 BH |
364 | * @param x the x coordinate of the point to test |
365 | * @param y the y coordinate of the point to test | |
366 | * @return the graph node containing the point given in parameter, null otherwise | |
367 | */ | |
368 | public GraphNode getNodeAt(int x, int y) { | |
369 | GraphNode toReturn = null; | |
370 | ||
eb63f5ff | 371 | if (!fHasChilden) { |
73005152 | 372 | return null; |
df0b8ff4 | 373 | } |
73005152 | 374 | |
eb63f5ff | 375 | Iterator<String> it = fNodes.keySet().iterator(); |
73005152 BH |
376 | GraphNode node = null; |
377 | while (it.hasNext()) { | |
378 | Object nodeType = it.next(); | |
abbdd66a AM |
379 | List<GraphNode> list = fNodes.get(nodeType); |
380 | int index = fIndexes.get(nodeType).intValue(); | |
73005152 | 381 | node = getNodeFromListAt(x, y, list, index); |
df0b8ff4 | 382 | if (toReturn == null) { |
73005152 | 383 | toReturn = node; |
df0b8ff4 | 384 | } |
73005152 BH |
385 | if (node != null) { |
386 | GraphNode internalNode = node.getNodeAt(x, y); | |
df0b8ff4 | 387 | if (internalNode != null) { |
73005152 | 388 | return internalNode; |
df0b8ff4 | 389 | } else if (Math.abs(node.getWidth()) < Math.abs(toReturn.getWidth()) || Math.abs(node.getHeight()) < Math.abs(toReturn.getHeight())) { |
73005152 | 390 | toReturn = node; |
df0b8ff4 | 391 | } |
73005152 BH |
392 | } |
393 | } | |
394 | return toReturn; | |
395 | } | |
396 | ||
df0b8ff4 BH |
397 | /** |
398 | * Gets node list from node A to node B | |
399 | ||
400 | * @param from A from node | |
401 | * @param to A to node | |
402 | * @return the list of nodes | |
403 | */ | |
eb63f5ff BH |
404 | public List<GraphNode> getNodeList(GraphNode from, GraphNode to) { |
405 | List<GraphNode> result = new ArrayList<GraphNode>(); | |
73005152 BH |
406 | |
407 | if (from != null) { | |
408 | result.add(from); | |
409 | } else if (to != null) { | |
410 | result.add(to); | |
411 | } | |
412 | ||
eb63f5ff | 413 | if ((from == null) || (to == null)) { |
73005152 | 414 | return result; |
df0b8ff4 | 415 | } |
73005152 | 416 | |
df0b8ff4 | 417 | if (from == to) { |
73005152 | 418 | return result; |
df0b8ff4 | 419 | } |
73005152 BH |
420 | |
421 | int startX = Math.min(from.getX(), Math.min(to.getX(), Math.min(from.getX() + from.getWidth(), to.getX() + to.getWidth()))); | |
422 | int endX = Math.max(from.getX(), Math.max(to.getX(), Math.max(from.getX() + from.getWidth(), to.getX() + to.getWidth()))); | |
423 | int startY = Math.min(from.getY(), Math.min(to.getY(), Math.min(from.getY() + from.getHeight(), to.getY() + to.getHeight()))); | |
424 | int endY = Math.max(from.getY(), Math.max(to.getY(), Math.max(from.getY() + from.getHeight(), to.getY() + to.getHeight()))); | |
425 | ||
eb63f5ff | 426 | if (!fHasChilden) { |
73005152 | 427 | return result; |
df0b8ff4 | 428 | } |
73005152 | 429 | |
eb63f5ff | 430 | Iterator<String> it = fNodes.keySet().iterator(); |
73005152 BH |
431 | while (it.hasNext()) { |
432 | Object nodeType = it.next(); | |
abbdd66a | 433 | List<GraphNode> nodesList = fNodes.get(nodeType); |
df0b8ff4 | 434 | if (nodesList == null || nodesList.isEmpty()) { |
73005152 | 435 | return null; |
df0b8ff4 | 436 | } |
73005152 | 437 | for (int i = 0; i < nodesList.size(); i++) { |
abbdd66a | 438 | GraphNode node = nodesList.get(i); |
73005152 BH |
439 | int nw = node.getWidth(); |
440 | int nh = node.getHeight(); | |
441 | int nx = node.getX(); | |
442 | int ny = node.getY(); | |
df0b8ff4 | 443 | if (contains(startX, startY, endX - startX, endY - startY, nx + 1, ny + 1) && contains(startX, startY, endX - startX, endY - startY, nx + nw - 2, ny + nh - 2)) { |
73005152 | 444 | result.add(node); |
df0b8ff4 | 445 | } |
73005152 BH |
446 | result.addAll(node.getNodeList(from, to)); |
447 | } | |
448 | } | |
eb63f5ff BH |
449 | |
450 | if (!result.contains(to)) { | |
73005152 | 451 | result.add(to); |
df0b8ff4 | 452 | } |
73005152 BH |
453 | return result; |
454 | } | |
455 | ||
456 | /** | |
457 | * Returns the graph node which contains the point given in parameter for the given graph node list and starting the | |
458 | * iteration at the given index<br> | |
459 | * WARNING: Only graph nodes with smaller coordinates than the current visible area can be returned.<br> | |
a55887ca | 460 | * |
73005152 BH |
461 | * @param x the x coordinate of the point to test |
462 | * @param y the y coordinate of the point to test | |
463 | * @param list the list to search in | |
464 | * @param fromIndex list browsing starting point | |
465 | * @return the graph node containing the point given in parameter, null otherwise | |
466 | */ | |
467 | protected GraphNode getNodeFromListAt(int x, int y, List<GraphNode> list, int fromIndex) { | |
df0b8ff4 | 468 | if (list == null) { |
73005152 | 469 | return null; |
df0b8ff4 | 470 | } |
73005152 | 471 | for (int i = fromIndex; i < list.size(); i++) { |
abbdd66a | 472 | GraphNode node = list.get(i); |
df0b8ff4 | 473 | if (node.contains(x, y)) { |
73005152 | 474 | return node; |
df0b8ff4 | 475 | } |
73005152 BH |
476 | } |
477 | return null; | |
478 | } | |
479 | ||
480 | /** | |
481 | * Returns the start event occurrence attached to this graphNode. | |
a55887ca | 482 | * |
73005152 BH |
483 | * @return the start event occurrence attached to the graphNode |
484 | */ | |
485 | public int getStartOccurrence() { | |
eb63f5ff | 486 | return fStartEventOccurrence; |
73005152 BH |
487 | } |
488 | ||
489 | /** | |
490 | * Returns the end event occurrence attached to this graphNode | |
a55887ca | 491 | * |
73005152 BH |
492 | * @return the start event occurrence attached to the graphNode |
493 | */ | |
494 | public int getEndOccurrence() { | |
eb63f5ff | 495 | return fEndEventOccurrence; |
73005152 BH |
496 | } |
497 | ||
498 | /** | |
499 | * Computes the index of the first visible GraphNode for each ordered graph node lists depending on the visible area | |
500 | * given in parameter | |
a55887ca | 501 | * |
73005152 BH |
502 | * @param x visible area top left corner x coordinate |
503 | * @param y visible area top left corner y coordinate | |
504 | * @param width visible area width | |
505 | * @param height visible area height | |
506 | */ | |
507 | public void updateIndex(int x, int y, int width, int height) { | |
eb63f5ff | 508 | if (!fHasChilden) { |
73005152 | 509 | return; |
df0b8ff4 | 510 | } |
73005152 BH |
511 | if(TmfUiTracer.isIndexTraced()) { |
512 | TmfUiTracer.traceIndex("*****************************\n"); //$NON-NLS-1$ | |
513 | TmfUiTracer.traceIndex("Visible area position in virtual screen (x,y)= " + x + " " + y + "\n\n"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ | |
514 | } | |
515 | ||
eb63f5ff | 516 | Iterator<String> it = fNodes.keySet().iterator(); |
73005152 BH |
517 | while (it.hasNext()) { |
518 | String nodeType = it.next(); | |
519 | int direction = 1; | |
abbdd66a | 520 | int drawIndex = fIndexes.get(nodeType).intValue(); |
73005152 BH |
521 | /* |
522 | * if (x==0) { drawIndex = 0; indexes.put(nodeType,new Integer(drawIndex)); } | |
523 | */ | |
abbdd66a AM |
524 | if ((fNodes.get(nodeType) != null) && (fNodes.get(nodeType).size() > 1)) { |
525 | if (fNodes.get(nodeType).get(drawIndex).positiveDistanceToPoint(x, y)) { | |
73005152 | 526 | direction = -1; |
df0b8ff4 | 527 | } |
73005152 | 528 | |
df0b8ff4 | 529 | if (drawIndex == 0) { |
73005152 | 530 | direction = 1; |
df0b8ff4 | 531 | } |
73005152 | 532 | |
eb63f5ff | 533 | if ((direction == -1) && (fBackwardNodes.get(nodeType) != null)) { |
abbdd66a AM |
534 | GraphNode currentNode = fNodes.get(nodeType).get(drawIndex); |
535 | drawIndex = Arrays.binarySearch(fBackwardNodes.get(nodeType).toArray(new GraphNode[fBackwardNodes.get(nodeType).size()]), | |
536 | fNodes.get(nodeType).get(drawIndex), currentNode.getBackComparator()); | |
537 | fNodes.put(nodeType, fBackwardNodes.get(nodeType)); | |
73005152 BH |
538 | if (drawIndex < 0) { |
539 | drawIndex = 0; | |
540 | direction = 1; | |
df0b8ff4 | 541 | } else { |
abbdd66a | 542 | fNodes.put(nodeType, fBackwardNodes.get(nodeType)); |
df0b8ff4 | 543 | } |
73005152 BH |
544 | } |
545 | GraphNode prev = null; | |
546 | ||
abbdd66a | 547 | for (int i = drawIndex; i < fNodes.get(nodeType).size() && i >= 0; i = i + direction) { |
73005152 | 548 | drawIndex = i; |
eb63f5ff | 549 | fIndexes.put(nodeType, Integer.valueOf(i)); |
73005152 | 550 | |
abbdd66a | 551 | GraphNode currentNode = fNodes.get(nodeType).get(i); |
73005152 | 552 | |
df0b8ff4 | 553 | if (prev == null) { |
73005152 | 554 | prev = currentNode; |
df0b8ff4 | 555 | } |
73005152 BH |
556 | |
557 | Comparator<GraphNode> comp = currentNode.getComparator(); | |
eb63f5ff | 558 | Map<String, Boolean> sort = fForwardSort; |
73005152 | 559 | |
eb63f5ff BH |
560 | if ((direction == -1) && (currentNode.getBackComparator() != null)) { |
561 | comp = currentNode.getBackComparator(); | |
562 | sort = fBackwardSort; | |
73005152 BH |
563 | } |
564 | ||
abbdd66a AM |
565 | if (i < fNodes.get(nodeType).size() - 1) { |
566 | GraphNode next = fNodes.get(nodeType).get(i + 1); | |
73005152 | 567 | |
df0b8ff4 | 568 | if ((comp != null) && (comp.compare(currentNode, next) > 0)) { |
3145ec83 | 569 | sort.put(nodeType, Boolean.TRUE); |
df0b8ff4 | 570 | } |
73005152 BH |
571 | } |
572 | if (direction == 1) { | |
abbdd66a | 573 | if (fNodes.get(nodeType).get(i).positiveDistanceToPoint(x, y)) { |
73005152 | 574 | break; |
df0b8ff4 | 575 | } |
73005152 BH |
576 | } else { |
577 | if (currentNode.getBackComparator() == null) { | |
578 | if // (currentNode.isVisible(x,y,width,height) | |
df0b8ff4 | 579 | (!currentNode.positiveDistanceToPoint(x, y)) { |
73005152 | 580 | break; |
df0b8ff4 | 581 | } |
73005152 BH |
582 | } else { |
583 | if (currentNode.isVisible(x, y, width, height) && !currentNode.positiveDistanceToPoint(x, y)) { | |
df0b8ff4 | 584 | if ((comp != null) && (comp.compare(currentNode, prev) <= 0)) { |
73005152 | 585 | break; |
df0b8ff4 BH |
586 | } |
587 | } else if ((comp != null) && (comp.compare(currentNode, prev) <= 0)) { | |
73005152 | 588 | prev = currentNode; |
df0b8ff4 | 589 | } |
73005152 BH |
590 | } |
591 | } | |
592 | } | |
593 | ||
eb63f5ff BH |
594 | fNodes.put(nodeType, fForwardNodes.get(nodeType)); |
595 | if ((fBackwardNodes.get(nodeType) != null) && (direction == -1)) { | |
73005152 | 596 | // nodes.put(nodeType,fnodes.get(nodeType)); |
abbdd66a AM |
597 | int index = fIndexes.get(nodeType).intValue(); |
598 | List<GraphNode> list = fNodes.get(nodeType); | |
599 | List<GraphNode> backList = fBackwardNodes.get(nodeType); | |
600 | GraphNode currentNode = (backList.get(index)); | |
73005152 | 601 | if (index > 0) { |
eb63f5ff | 602 | index = Arrays.binarySearch(list.toArray(new GraphNode[list.size()]), backList.get(index), currentNode.getComparator()); |
df0b8ff4 | 603 | if (index < 0) { |
73005152 | 604 | index = 0; |
df0b8ff4 | 605 | } |
eb63f5ff | 606 | fIndexes.put(nodeType, Integer.valueOf(index)); |
73005152 BH |
607 | } |
608 | } | |
609 | ||
abbdd66a AM |
610 | for (int i = drawIndex; i < fNodes.get(nodeType).size() && i >= 0; i++) { |
611 | GraphNode toDraw = fNodes.get(nodeType).get(i); | |
73005152 | 612 | toDraw.updateIndex(x, y, width, height); |
df0b8ff4 | 613 | if (!toDraw.isVisible(x, y, width, height)) { |
73005152 | 614 | break; |
df0b8ff4 | 615 | } |
73005152 BH |
616 | } |
617 | } | |
618 | if (TmfUiTracer.isIndexTraced()) { | |
a55887ca | 619 | TmfUiTracer.traceIndex("First drawn " + nodeType + " index = " + drawIndex + "\n"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ |
73005152 BH |
620 | TmfUiTracer.traceIndex(nodeType + " found in " + 0 + " iterations\n"); //$NON-NLS-1$ //$NON-NLS-2$ |
621 | } | |
622 | } | |
623 | ||
624 | if (TmfUiTracer.isIndexTraced()) { | |
625 | TmfUiTracer.traceIndex("*****************************\n"); //$NON-NLS-1$ | |
626 | } | |
627 | } | |
628 | ||
629 | /** | |
630 | * Draws the children nodes on the given context.<br> | |
631 | * This method start width GraphNodes ordering if needed.<br> | |
632 | * After, depending on the visible area, only visible GraphNodes are drawn.<br> | |
a55887ca | 633 | * |
73005152 | 634 | * @param context the context to draw to |
73005152 BH |
635 | * @see org.eclipse.linuxtools.tmf.ui.views.uml2sd.core.GraphNode#draw(IGC) |
636 | */ | |
637 | protected void drawChildenNodes(IGC context) { | |
638 | ||
eb63f5ff | 639 | if (!fHasChilden) { |
73005152 | 640 | return; |
df0b8ff4 | 641 | } |
73005152 | 642 | // If the nodes have not been added ordered, the array is ordered |
eb63f5ff | 643 | Iterator<String> it = fForwardSort.keySet().iterator(); |
73005152 BH |
644 | while (it.hasNext()) { |
645 | String nodeType = it.next(); | |
abbdd66a | 646 | boolean sort = fForwardSort.get(nodeType).booleanValue(); |
73005152 | 647 | if (sort) { |
abbdd66a AM |
648 | GraphNode[] temp = fForwardNodes.get(nodeType).toArray(new GraphNode[fForwardNodes.get(nodeType).size()]); |
649 | GraphNode node = fNodes.get(nodeType).get(0); | |
73005152 | 650 | Arrays.sort(temp, node.getComparator()); |
3145ec83 | 651 | fForwardSort.put(nodeType, Boolean.FALSE); |
eb63f5ff BH |
652 | fNodes.put(nodeType, Arrays.asList(temp)); |
653 | fForwardNodes.put(nodeType, Arrays.asList(temp)); | |
df0b8ff4 | 654 | if (TmfUiTracer.isSortingTraced()) { |
73005152 | 655 | TmfUiTracer.traceSorting(nodeType + " array sorted\n"); //$NON-NLS-1$ |
df0b8ff4 | 656 | } |
73005152 BH |
657 | } |
658 | } | |
659 | ||
eb63f5ff | 660 | Iterator<String> it2 = fBackwardSort.keySet().iterator(); |
73005152 BH |
661 | while (it2.hasNext()) { |
662 | String nodeType = it2.next(); | |
abbdd66a | 663 | boolean sort = fBackwardSort.get(nodeType).booleanValue(); |
73005152 | 664 | if (sort) { |
abbdd66a AM |
665 | GraphNode[] temp = fBackwardNodes.get(nodeType).toArray(new GraphNode[fBackwardNodes.get(nodeType).size()]); |
666 | GraphNode node = fNodes.get(nodeType).get(0); | |
73005152 | 667 | Arrays.sort(temp, node.getBackComparator()); |
3145ec83 | 668 | fBackwardSort.put(nodeType, Boolean.FALSE); |
eb63f5ff | 669 | fBackwardNodes.put(nodeType, Arrays.asList(temp)); |
df0b8ff4 | 670 | if (TmfUiTracer.isSortingTraced()) { |
73005152 | 671 | TmfUiTracer.traceSorting(nodeType + " back array sorted\n"); //$NON-NLS-1$ |
df0b8ff4 | 672 | } |
73005152 BH |
673 | } |
674 | } | |
675 | ||
676 | if (TmfUiTracer.isDisplayTraced()) { | |
677 | TmfUiTracer.traceDisplay("*****************************\n"); //$NON-NLS-1$ | |
678 | } | |
679 | ||
680 | int arrayStep = 1; | |
df0b8ff4 | 681 | if ((Metrics.getMessageFontHeigth() + Metrics.MESSAGES_NAME_SPACING * 2) * context.getZoom() < Metrics.MESSAGE_SIGNIFICANT_VSPACING) { |
73005152 | 682 | arrayStep = Math.round(Metrics.MESSAGE_SIGNIFICANT_VSPACING / ((Metrics.getMessageFontHeigth() + Metrics.MESSAGES_NAME_SPACING * 2) * context.getZoom())); |
df0b8ff4 | 683 | } |
73005152 BH |
684 | |
685 | int count = 0; | |
eb63f5ff | 686 | Iterator<String> it3 = fForwardSort.keySet().iterator(); |
73005152 BH |
687 | while (it3.hasNext()) { |
688 | count = 0; | |
689 | Object nodeType = it3.next(); | |
abbdd66a | 690 | GraphNode node = fNodes.get(nodeType).get(0); |
3145ec83 | 691 | context.setFont(SDViewPref.getInstance().getFont(node.fPrefId)); |
abbdd66a AM |
692 | int index = fIndexes.get(nodeType).intValue(); |
693 | count = drawNodes(context, fNodes.get(nodeType), index, arrayStep); | |
df0b8ff4 | 694 | if (TmfUiTracer.isDisplayTraced()) { |
73005152 | 695 | TmfUiTracer.traceDisplay(count + " " + nodeType + " drawn, starting from index " + index + "\r\n"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ |
df0b8ff4 | 696 | } |
73005152 BH |
697 | } |
698 | if (TmfUiTracer.isDisplayTraced()) { | |
699 | TmfUiTracer.traceDisplay("*****************************\n"); //$NON-NLS-1$ | |
700 | } | |
701 | ||
702 | } | |
703 | ||
704 | /** | |
705 | * Draw the GraphNode stored in the given list, starting at index startIndex with the given step | |
a55887ca | 706 | * |
73005152 BH |
707 | * @param context the context to draw to |
708 | * @param list the GraphNodes list | |
709 | * @param startIndex the start index | |
710 | * @param step the step to browse the list | |
711 | * @return the number of GraphNodes drawn | |
712 | */ | |
713 | protected int drawNodes(IGC context, List<GraphNode> list, int startIndex, int step) { | |
eb63f5ff | 714 | if (!fHasChilden) { |
73005152 | 715 | return 0; |
df0b8ff4 | 716 | } |
73005152 BH |
717 | |
718 | GraphNode last = null; | |
719 | int nodesCount = 0; | |
df0b8ff4 | 720 | if (list.size() < 0) { |
73005152 | 721 | return 0; |
df0b8ff4 | 722 | } |
73005152 | 723 | |
abbdd66a | 724 | GraphNode node = list.get(0); |
3145ec83 | 725 | context.setFont(SDViewPref.getInstance().getFont(node.fPrefId)); |
73005152 BH |
726 | Comparator<GraphNode> comparator = node.getComparator(); |
727 | for (int i = startIndex; i < list.size(); i = i + step) { | |
abbdd66a | 728 | GraphNode toDraw = list.get(i); |
73005152 | 729 | if (i < list.size() - 1) { |
abbdd66a | 730 | GraphNode next = list.get(i + 1); |
f9a8715c | 731 | if ((comparator != null) && (comparator.compare(toDraw, next) > 0)) { |
3145ec83 | 732 | fForwardSort.put(next.getArrayId(), Boolean.TRUE); |
73005152 BH |
733 | } |
734 | } | |
735 | int cx = context.getContentsX(); | |
736 | int cy = context.getContentsY(); | |
737 | int cw = context.getVisibleWidth(); | |
738 | int ch = context.getVisibleHeight(); | |
739 | // The arrays should be ordered, no needs to continue for this one | |
df0b8ff4 | 740 | if (!toDraw.isVisible(cx, cy, cw, ch) && toDraw.positiveDistanceToPoint(cx + cw, cy + ch)) { |
73005152 | 741 | break; |
df0b8ff4 | 742 | } |
73005152 BH |
743 | // ***Common*** nodes visibility |
744 | if ((!toDraw.isSameAs(last) || toDraw.isSelected()) && (toDraw.isVisible(context.getContentsX(), context.getContentsY(), context.getVisibleWidth(), context.getVisibleHeight()))) { | |
745 | nodesCount++; | |
a55887ca | 746 | |
73005152 | 747 | toDraw.draw(context); |
df0b8ff4 | 748 | if (hasFocus()) { |
73005152 | 749 | toDraw.drawFocus(context); |
df0b8ff4 | 750 | } |
73005152 BH |
751 | } |
752 | last = toDraw; | |
753 | } | |
754 | return nodesCount; | |
755 | } | |
756 | ||
df0b8ff4 BH |
757 | /** |
758 | * Draws the focus within the graphical context. | |
a55887ca | 759 | * |
df0b8ff4 | 760 | * @param context |
a55887ca | 761 | * The context |
df0b8ff4 | 762 | */ |
73005152 BH |
763 | public void drawFocus(IGC context) { |
764 | context.drawFocus(getX(), getY(), getWidth(), getHeight()); | |
765 | } | |
766 | ||
767 | /** | |
768 | * Determine if the given point (px,py) is contained in the rectangle (x,y,width,height) | |
a55887ca | 769 | * |
73005152 BH |
770 | * @param x the rectangle x coordinate |
771 | * @param y the rectangle y coordinate | |
772 | * @param width the rectangle width | |
773 | * @param height the rectangle height | |
774 | * @param px the x coordinate of the point to test | |
775 | * @param py the y coordinate of the point to test | |
776 | * @return true if contained false otherwise | |
777 | */ | |
778 | public static boolean contains(int x, int y, int width, int height, int px, int py) { | |
779 | int locX = x; | |
780 | int locY = y; | |
781 | int locWidth = width; | |
782 | int locHeight = height; | |
783 | ||
784 | if (width < 0) { | |
785 | locX = locX + width; | |
786 | locWidth = -locWidth; | |
787 | } | |
788 | ||
789 | if (height < 0) { | |
790 | locY = locY + height; | |
791 | locHeight = -locHeight; | |
792 | } | |
793 | return (px >= locX) && (py >= locY) && ((px - locX) <= locWidth) && ((py - locY) <= locHeight); | |
794 | } | |
795 | } |