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 }