Mercurial > hg > truffle
comparison visualizer/View/src/com/sun/hotspot/igv/view/widgets/LineWidget.java @ 4512:015fb895586b
Moved visualizer to new directory.
author | Thomas Wuerthinger <thomas.wuerthinger@oracle.com> |
---|---|
date | Tue, 07 Feb 2012 22:41:09 +0100 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
4511:6cb549627941 | 4512:015fb895586b |
---|---|
1 /* | |
2 * Copyright (c) 2008, Oracle and/or its affiliates. All rights reserved. | |
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. | |
4 * | |
5 * This code is free software; you can redistribute it and/or modify it | |
6 * under the terms of the GNU General Public License version 2 only, as | |
7 * published by the Free Software Foundation. | |
8 * | |
9 * This code is distributed in the hope that it will be useful, but WITHOUT | |
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | |
12 * version 2 for more details (a copy is included in the LICENSE file that | |
13 * accompanied this code). | |
14 * | |
15 * You should have received a copy of the GNU General Public License version | |
16 * 2 along with this work; if not, write to the Free Software Foundation, | |
17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. | |
18 * | |
19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA | |
20 * or visit www.oracle.com if you need additional information or have any | |
21 * questions. | |
22 * | |
23 */ | |
24 package com.sun.hotspot.igv.view.widgets; | |
25 | |
26 import com.sun.hotspot.igv.graph.Connection; | |
27 import com.sun.hotspot.igv.graph.Figure; | |
28 import com.sun.hotspot.igv.graph.InputSlot; | |
29 import com.sun.hotspot.igv.graph.OutputSlot; | |
30 import com.sun.hotspot.igv.view.scene.DiagramScene; | |
31 import java.awt.*; | |
32 import java.awt.geom.Line2D; | |
33 import java.util.ArrayList; | |
34 import java.util.HashSet; | |
35 import java.util.List; | |
36 import java.util.Set; | |
37 import javax.swing.JPopupMenu; | |
38 import javax.swing.event.PopupMenuEvent; | |
39 import javax.swing.event.PopupMenuListener; | |
40 import org.netbeans.api.visual.action.ActionFactory; | |
41 import org.netbeans.api.visual.action.PopupMenuProvider; | |
42 import org.netbeans.api.visual.action.SelectProvider; | |
43 import org.netbeans.api.visual.animator.SceneAnimator; | |
44 import org.netbeans.api.visual.model.ObjectState; | |
45 import org.netbeans.api.visual.widget.Widget; | |
46 | |
47 /** | |
48 * | |
49 * @author Thomas Wuerthinger | |
50 */ | |
51 public class LineWidget extends Widget implements PopupMenuProvider { | |
52 | |
53 public final int BORDER = 5; | |
54 public final int ARROW_SIZE = 6; | |
55 public final int BOLD_ARROW_SIZE = 7; | |
56 public final int HOVER_ARROW_SIZE = 8; | |
57 public final int BOLD_STROKE_WIDTH = 2; | |
58 public final int HOVER_STROKE_WIDTH = 3; | |
59 private static double ZOOM_FACTOR = 0.1; | |
60 private OutputSlot outputSlot; | |
61 private DiagramScene scene; | |
62 private List<Connection> connections; | |
63 private Point from; | |
64 private Point to; | |
65 private Rectangle clientArea; | |
66 private Color color = Color.BLACK; | |
67 private LineWidget predecessor; | |
68 private List<LineWidget> successors; | |
69 private boolean highlighted; | |
70 private boolean popupVisible; | |
71 private boolean isBold; | |
72 private boolean isDashed; | |
73 | |
74 public LineWidget(DiagramScene scene, OutputSlot s, List<Connection> connections, Point from, Point to, LineWidget predecessor, SceneAnimator animator, boolean isBold, boolean isDashed) { | |
75 super(scene); | |
76 this.scene = scene; | |
77 this.outputSlot = s; | |
78 this.connections = connections; | |
79 this.from = from; | |
80 this.to = to; | |
81 this.predecessor = predecessor; | |
82 this.successors = new ArrayList<>(); | |
83 if (predecessor != null) { | |
84 predecessor.addSuccessor(this); | |
85 } | |
86 | |
87 this.isBold = isBold; | |
88 this.isDashed = isDashed; | |
89 | |
90 int minX = from.x; | |
91 int minY = from.y; | |
92 int maxX = to.x; | |
93 int maxY = to.y; | |
94 if (minX > maxX) { | |
95 int tmp = minX; | |
96 minX = maxX; | |
97 maxX = tmp; | |
98 } | |
99 | |
100 if (minY > maxY) { | |
101 int tmp = minY; | |
102 minY = maxY; | |
103 maxY = tmp; | |
104 } | |
105 | |
106 clientArea = new Rectangle(minX, minY, maxX - minX + 1, maxY - minY + 1); | |
107 clientArea.grow(BORDER, BORDER); | |
108 | |
109 if (connections.size() > 0) { | |
110 color = connections.get(0).getColor(); | |
111 } | |
112 | |
113 this.setToolTipText("<HTML>" + generateToolTipText(this.connections) + "</HTML>"); | |
114 | |
115 this.setCheckClipping(true); | |
116 | |
117 this.getActions().addAction(ActionFactory.createPopupMenuAction(this)); | |
118 if (animator == null) { | |
119 this.setBackground(color); | |
120 } else { | |
121 this.setBackground(Color.WHITE); | |
122 animator.animateBackgroundColor(this, color); | |
123 } | |
124 | |
125 this.getActions().addAction(ActionFactory.createSelectAction(new SelectProvider() { | |
126 | |
127 @Override | |
128 public boolean isAimingAllowed(Widget arg0, Point arg1, boolean arg2) { | |
129 return true; | |
130 } | |
131 | |
132 @Override | |
133 public boolean isSelectionAllowed(Widget arg0, Point arg1, boolean arg2) { | |
134 return true; | |
135 } | |
136 | |
137 @Override | |
138 public void select(Widget arg0, Point arg1, boolean arg2) { | |
139 Set<Figure> set = new HashSet<>(); | |
140 for (Connection c : LineWidget.this.connections) { | |
141 set.add(c.getInputSlot().getFigure()); | |
142 set.add(c.getOutputSlot().getFigure()); | |
143 } | |
144 LineWidget.this.scene.setSelectedObjects(set); | |
145 } | |
146 })); | |
147 } | |
148 | |
149 private String generateToolTipText(List<Connection> conn) { | |
150 StringBuilder sb = new StringBuilder(); | |
151 for (Connection c : conn) { | |
152 sb.append(c.getToolTipText()); | |
153 sb.append("<br>"); | |
154 } | |
155 return sb.toString(); | |
156 } | |
157 | |
158 public Point getFrom() { | |
159 return from; | |
160 } | |
161 | |
162 public Point getTo() { | |
163 return to; | |
164 } | |
165 | |
166 private void addSuccessor(LineWidget widget) { | |
167 this.successors.add(widget); | |
168 } | |
169 | |
170 @Override | |
171 protected Rectangle calculateClientArea() { | |
172 return clientArea; | |
173 } | |
174 | |
175 @Override | |
176 protected void paintWidget() { | |
177 if (scene.getZoomFactor() < ZOOM_FACTOR) { | |
178 return; | |
179 } | |
180 | |
181 Graphics2D g = getScene().getGraphics(); | |
182 g.setPaint(this.getBackground()); | |
183 float width = 1.0f; | |
184 | |
185 if (isBold) { | |
186 width = BOLD_STROKE_WIDTH; | |
187 } | |
188 | |
189 if (highlighted || popupVisible) { | |
190 width = HOVER_STROKE_WIDTH; | |
191 } | |
192 | |
193 Stroke oldStroke = g.getStroke(); | |
194 if (isDashed) { | |
195 float[] dashPattern = {5, 5, 5, 5}; | |
196 g.setStroke(new BasicStroke(width, BasicStroke.CAP_BUTT, | |
197 BasicStroke.JOIN_MITER, 10, | |
198 dashPattern, 0)); | |
199 } else { | |
200 g.setStroke(new BasicStroke(width)); | |
201 } | |
202 | |
203 g.drawLine(from.x, from.y, to.x, to.y); | |
204 | |
205 boolean sameFrom = false; | |
206 boolean sameTo = successors.size() == 0; | |
207 for (LineWidget w : successors) { | |
208 if (w.getFrom().equals(getTo())) { | |
209 sameTo = true; | |
210 } | |
211 } | |
212 | |
213 if (predecessor == null || predecessor.getTo().equals(getFrom())) { | |
214 sameFrom = true; | |
215 } | |
216 | |
217 | |
218 int size = ARROW_SIZE; | |
219 if (isBold) { | |
220 size = BOLD_ARROW_SIZE; | |
221 } | |
222 if (highlighted || popupVisible) { | |
223 size = HOVER_ARROW_SIZE; | |
224 } | |
225 if (!sameFrom) { | |
226 g.fillPolygon( | |
227 new int[]{from.x - size / 2, from.x + size / 2, from.x}, | |
228 new int[]{from.y - size / 2, from.y - size / 2, from.y + size / 2}, | |
229 3); | |
230 } | |
231 if (!sameTo) { | |
232 g.fillPolygon( | |
233 new int[]{to.x - size / 2, to.x + size / 2, to.x}, | |
234 new int[]{to.y - size / 2, to.y - size / 2, to.y + size / 2}, | |
235 3); | |
236 } | |
237 g.setStroke(oldStroke); | |
238 } | |
239 | |
240 private void setHighlighted(boolean b) { | |
241 this.highlighted = b; | |
242 Set<Object> highlightedObjects = new HashSet<>(scene.getHighlightedObjects()); | |
243 Set<Object> highlightedObjectsChange = new HashSet<>(); | |
244 for (Connection c : connections) { | |
245 highlightedObjectsChange.add(c.getInputSlot().getFigure()); | |
246 highlightedObjectsChange.add(c.getInputSlot()); | |
247 highlightedObjectsChange.add(c.getOutputSlot().getFigure()); | |
248 highlightedObjectsChange.add(c.getOutputSlot()); | |
249 } | |
250 if(b) { | |
251 highlightedObjects.addAll(highlightedObjectsChange); | |
252 } else { | |
253 highlightedObjects.removeAll(highlightedObjectsChange); | |
254 } | |
255 scene.setHighlightedObjects(highlightedObjects); | |
256 this.revalidate(true); | |
257 } | |
258 | |
259 private void setPopupVisible(boolean b) { | |
260 this.popupVisible = b; | |
261 this.revalidate(true); | |
262 } | |
263 | |
264 @Override | |
265 public boolean isHitAt(Point localPoint) { | |
266 return Line2D.ptLineDistSq(from.x, from.y, to.x, to.y, localPoint.x, localPoint.y) <= BORDER * BORDER; | |
267 } | |
268 | |
269 @Override | |
270 protected void notifyStateChanged(ObjectState previousState, ObjectState state) { | |
271 if (previousState.isHovered() != state.isHovered()) { | |
272 setRecursiveHighlighted(state.isHovered()); | |
273 } | |
274 } | |
275 | |
276 private void setRecursiveHighlighted(boolean b) { | |
277 LineWidget cur = predecessor; | |
278 while (cur != null) { | |
279 cur.setHighlighted(b); | |
280 cur = cur.predecessor; | |
281 } | |
282 | |
283 highlightSuccessors(b); | |
284 this.setHighlighted(b); | |
285 } | |
286 | |
287 private void highlightSuccessors(boolean b) { | |
288 for (LineWidget s : successors) { | |
289 s.setHighlighted(b); | |
290 s.highlightSuccessors(b); | |
291 } | |
292 } | |
293 | |
294 private void setRecursivePopupVisible(boolean b) { | |
295 LineWidget cur = predecessor; | |
296 while (cur != null) { | |
297 cur.setPopupVisible(b); | |
298 cur = cur.predecessor; | |
299 } | |
300 | |
301 popupVisibleSuccessors(b); | |
302 setPopupVisible(b); | |
303 } | |
304 | |
305 private void popupVisibleSuccessors(boolean b) { | |
306 for (LineWidget s : successors) { | |
307 s.setPopupVisible(b); | |
308 s.popupVisibleSuccessors(b); | |
309 } | |
310 } | |
311 | |
312 @Override | |
313 public JPopupMenu getPopupMenu(Widget widget, Point localLocation) { | |
314 JPopupMenu menu = new JPopupMenu(); | |
315 menu.add(scene.createGotoAction(outputSlot.getFigure())); | |
316 menu.addSeparator(); | |
317 | |
318 for (Connection c : connections) { | |
319 InputSlot s = c.getInputSlot(); | |
320 menu.add(scene.createGotoAction(s.getFigure())); | |
321 } | |
322 | |
323 final LineWidget w = this; | |
324 menu.addPopupMenuListener(new PopupMenuListener() { | |
325 | |
326 @Override | |
327 public void popupMenuWillBecomeVisible(PopupMenuEvent e) { | |
328 w.setRecursivePopupVisible(true); | |
329 } | |
330 | |
331 @Override | |
332 public void popupMenuWillBecomeInvisible(PopupMenuEvent e) { | |
333 w.setRecursivePopupVisible(false); | |
334 } | |
335 | |
336 @Override | |
337 public void popupMenuCanceled(PopupMenuEvent e) { | |
338 } | |
339 }); | |
340 | |
341 return menu; | |
342 } | |
343 } |