1 /* 2 * Copyright (c) 2008, 2015, 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.controlflow; 25 26 import com.sun.hotspot.igv.data.InputBlockEdge; 27 import com.sun.hotspot.igv.data.InputBlock; 28 import com.sun.hotspot.igv.data.InputGraph; 29 import com.sun.hotspot.igv.data.services.InputGraphProvider; 30 import com.sun.hotspot.igv.data.InputNode; 31 import com.sun.hotspot.igv.util.LookupHistory; 32 import java.awt.Color; 33 import java.awt.Point; 34 import java.awt.Rectangle; 35 import java.util.ArrayList; 36 import java.util.HashSet; 37 import java.util.Set; 38 import javax.swing.BorderFactory; 39 import org.netbeans.api.visual.action.ActionFactory; 40 import org.netbeans.api.visual.action.MoveProvider; 41 import org.netbeans.api.visual.action.RectangularSelectDecorator; 42 import org.netbeans.api.visual.action.RectangularSelectProvider; 43 import org.netbeans.api.visual.action.SelectProvider; 44 import org.netbeans.api.visual.action.WidgetAction; 45 import org.netbeans.api.visual.anchor.AnchorFactory; 46 import org.netbeans.api.visual.anchor.AnchorShape; 47 import org.netbeans.api.visual.router.RouterFactory; 48 import org.netbeans.api.visual.widget.LayerWidget; 49 import org.netbeans.api.visual.widget.Widget; 50 import org.netbeans.api.visual.graph.GraphScene; 51 import org.netbeans.api.visual.graph.layout.GraphLayout; 52 import org.netbeans.api.visual.layout.LayoutFactory; 53 import org.netbeans.api.visual.layout.SceneLayout; 54 import org.netbeans.api.visual.widget.ConnectionWidget; 55 56 /** 57 * 58 * @author Thomas Wuerthinger 59 */ 60 public class ControlFlowScene extends GraphScene<InputBlock, InputBlockEdge> implements SelectProvider, MoveProvider, RectangularSelectDecorator, RectangularSelectProvider { 61 62 private HashSet<BlockWidget> selection; 63 private InputGraph oldGraph; 64 private LayerWidget edgeLayer; 65 private LayerWidget mainLayer; 66 private LayerWidget selectLayer; 67 private WidgetAction hoverAction = this.createWidgetHoverAction(); 68 private WidgetAction selectAction = new DoubleClickSelectAction(this); 69 private WidgetAction moveAction = ActionFactory.createMoveAction(null, this); 70 ControlFlowScene()71 public ControlFlowScene() { 72 selection = new HashSet<BlockWidget>(); 73 74 this.getInputBindings().setZoomActionModifiers(0); 75 this.setLayout(LayoutFactory.createAbsoluteLayout()); 76 77 mainLayer = new LayerWidget(this); 78 this.addChild(mainLayer); 79 80 edgeLayer = new LayerWidget(this); 81 this.addChild(edgeLayer); 82 83 selectLayer = new LayerWidget(this); 84 this.addChild(selectLayer); 85 86 this.getActions().addAction(hoverAction); 87 this.getActions().addAction(selectAction); 88 this.getActions().addAction(ActionFactory.createRectangularSelectAction(this, selectLayer, this)); 89 this.getActions().addAction(ActionFactory.createMouseCenteredZoomAction(1.1)); 90 } 91 setGraph(InputGraph g)92 public void setGraph(InputGraph g) { 93 if (g == oldGraph) { 94 return; 95 } 96 oldGraph = g; 97 98 ArrayList<InputBlock> blocks = new ArrayList<InputBlock>(this.getNodes()); 99 for (InputBlock b : blocks) { 100 removeNode(b); 101 } 102 103 ArrayList<InputBlockEdge> edges = new ArrayList<InputBlockEdge>(this.getEdges()); 104 for (InputBlockEdge e : edges) { 105 removeEdge(e); 106 } 107 108 for (InputBlock b : g.getBlocks()) { 109 addNode(b); 110 } 111 112 for (InputBlockEdge e : g.getBlockEdges()) { 113 addEdge(e); 114 assert g.getBlocks().contains(e.getFrom()); 115 assert g.getBlocks().contains(e.getTo()); 116 this.setEdgeSource(e, e.getFrom()); 117 this.setEdgeTarget(e, e.getTo()); 118 } 119 120 GraphLayout<InputBlock, InputBlockEdge> layout = new HierarchicalGraphLayout<InputBlock, InputBlockEdge>();//GridGraphLayout(); 121 SceneLayout sceneLayout = LayoutFactory.createSceneGraphLayout(this, layout); 122 sceneLayout.invokeLayout(); 123 124 this.validate(); 125 } 126 clearSelection()127 public void clearSelection() { 128 for (BlockWidget w : selection) { 129 w.setState(w.getState().deriveSelected(false)); 130 } 131 selection.clear(); 132 selectionChanged(); 133 } 134 selectionChanged()135 public void selectionChanged() { 136 InputGraphProvider p = LookupHistory.getLast(InputGraphProvider.class);//)Utilities.actionsGlobalContext().lookup(InputGraphProvider.class); 137 if (p != null) { 138 Set<InputNode> inputNodes = new HashSet<InputNode>(); 139 for (BlockWidget w : selection) { 140 inputNodes.addAll(w.getBlock().getNodes()); 141 } 142 p.setSelectedNodes(inputNodes); 143 } 144 } 145 addToSelection(BlockWidget widget)146 public void addToSelection(BlockWidget widget) { 147 widget.setState(widget.getState().deriveSelected(true)); 148 selection.add(widget); 149 selectionChanged(); 150 } 151 removeFromSelection(BlockWidget widget)152 public void removeFromSelection(BlockWidget widget) { 153 widget.setState(widget.getState().deriveSelected(false)); 154 selection.remove(widget); 155 selectionChanged(); 156 } 157 isAimingAllowed(Widget widget, Point point, boolean b)158 public boolean isAimingAllowed(Widget widget, Point point, boolean b) { 159 return false; 160 } 161 isSelectionAllowed(Widget widget, Point point, boolean b)162 public boolean isSelectionAllowed(Widget widget, Point point, boolean b) { 163 return true; 164 } 165 select(Widget widget, Point point, boolean change)166 public void select(Widget widget, Point point, boolean change) { 167 if (widget == this) { 168 clearSelection(); 169 } else { 170 171 assert widget instanceof BlockWidget; 172 BlockWidget bw = (BlockWidget) widget; 173 if (change) { 174 if (selection.contains(bw)) { 175 removeFromSelection(bw); 176 } else { 177 addToSelection(bw); 178 } 179 } else { 180 if (!selection.contains(bw)) { 181 clearSelection(); 182 addToSelection(bw); 183 } 184 } 185 } 186 } 187 movementStarted(Widget widget)188 public void movementStarted(Widget widget) { 189 } 190 movementFinished(Widget widget)191 public void movementFinished(Widget widget) { 192 } 193 getOriginalLocation(Widget widget)194 public Point getOriginalLocation(Widget widget) { 195 return widget.getPreferredLocation(); 196 } 197 setNewLocation(Widget widget, Point location)198 public void setNewLocation(Widget widget, Point location) { 199 if (selection.contains(widget)) { 200 // move entire selection 201 Point originalLocation = getOriginalLocation(widget); 202 int xOffset = location.x - originalLocation.x; 203 int yOffset = location.y - originalLocation.y; 204 for (Widget w : selection) { 205 Point p = new Point(w.getPreferredLocation()); 206 p.translate(xOffset, yOffset); 207 w.setPreferredLocation(p); 208 } 209 } else { 210 widget.setPreferredLocation(location); 211 } 212 } 213 createSelectionWidget()214 public Widget createSelectionWidget() { 215 Widget widget = new Widget(this); 216 widget.setOpaque(false); 217 widget.setBorder(BorderFactory.createLineBorder(Color.black, 2)); 218 widget.setForeground(Color.red); 219 return widget; 220 } 221 performSelection(Rectangle rectangle)222 public void performSelection(Rectangle rectangle) { 223 224 if (rectangle.width < 0) { 225 rectangle.x += rectangle.width; 226 rectangle.width *= -1; 227 } 228 229 if (rectangle.height < 0) { 230 rectangle.y += rectangle.height; 231 rectangle.height *= -1; 232 } 233 234 boolean changed = false; 235 for (InputBlock b : this.getNodes()) { 236 BlockWidget w = (BlockWidget) findWidget(b); 237 Rectangle r = new Rectangle(w.getBounds()); 238 r.setLocation(w.getLocation()); 239 if (r.intersects(rectangle)) { 240 if (!selection.contains(w)) { 241 changed = true; 242 selection.add(w); 243 w.setState(w.getState().deriveSelected(true)); 244 } 245 } else { 246 if (selection.contains(w)) { 247 changed = true; 248 selection.remove(w); 249 w.setState(w.getState().deriveSelected(false)); 250 } 251 } 252 } 253 254 if (changed) { 255 selectionChanged(); 256 } 257 258 } 259 attachNodeWidget(InputBlock node)260 protected Widget attachNodeWidget(InputBlock node) { 261 BlockWidget w = new BlockWidget(this, node); 262 mainLayer.addChild(w); 263 w.getActions().addAction(hoverAction); 264 w.getActions().addAction(selectAction); 265 w.getActions().addAction(moveAction); 266 return w; 267 } 268 attachEdgeWidget(InputBlockEdge edge)269 protected Widget attachEdgeWidget(InputBlockEdge edge) { 270 BlockConnectionWidget w = new BlockConnectionWidget(this, edge); 271 switch (edge.getState()) { 272 case NEW: 273 w.setBold(true); 274 break; 275 case DELETED: 276 w.setDashed(true); 277 break; 278 } 279 w.setRouter(RouterFactory.createDirectRouter()); 280 w.setTargetAnchorShape(AnchorShape.TRIANGLE_FILLED); 281 edgeLayer.addChild(w); 282 return w; 283 } 284 attachEdgeSourceAnchor(InputBlockEdge edge, InputBlock oldSourceNode, InputBlock sourceNode)285 protected void attachEdgeSourceAnchor(InputBlockEdge edge, InputBlock oldSourceNode, InputBlock sourceNode) { 286 Widget w = this.findWidget(edge); 287 assert w instanceof ConnectionWidget; 288 ConnectionWidget cw = (ConnectionWidget) w; 289 cw.setSourceAnchor(AnchorFactory.createRectangularAnchor(findWidget(sourceNode))); 290 291 } 292 attachEdgeTargetAnchor(InputBlockEdge edge, InputBlock oldTargetNode, InputBlock targetNode)293 protected void attachEdgeTargetAnchor(InputBlockEdge edge, InputBlock oldTargetNode, InputBlock targetNode) { 294 Widget w = this.findWidget(edge); 295 assert w instanceof ConnectionWidget; 296 ConnectionWidget cw = (ConnectionWidget) w; 297 cw.setTargetAnchor(AnchorFactory.createRectangularAnchor(findWidget(targetNode))); 298 } 299 } 300