| /* |
| * Copyright (c) 2008, Oracle and/or its affiliates. All rights reserved. |
| * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. |
| * |
| * This code is free software; you can redistribute it and/or modify it |
| * under the terms of the GNU General Public License version 2 only, as |
| * published by the Free Software Foundation. |
| * |
| * This code is distributed in the hope that it will be useful, but WITHOUT |
| * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
| * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
| * version 2 for more details (a copy is included in the LICENSE file that |
| * accompanied this code). |
| * |
| * You should have received a copy of the GNU General Public License version |
| * 2 along with this work; if not, write to the Free Software Foundation, |
| * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. |
| * |
| * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA |
| * or visit www.oracle.com if you need additional information or have any |
| * questions. |
| * |
| */ |
| package com.sun.hotspot.igv.controlflow; |
| |
| import com.sun.hotspot.igv.data.InputBlock; |
| import com.sun.hotspot.igv.data.InputBlockEdge; |
| import com.sun.hotspot.igv.data.InputGraph; |
| import com.sun.hotspot.igv.data.services.InputGraphProvider; |
| import com.sun.hotspot.igv.data.InputNode; |
| import java.awt.Color; |
| import java.awt.Point; |
| import java.awt.Rectangle; |
| import java.util.ArrayList; |
| import java.util.HashSet; |
| import java.util.HashMap; |
| import java.util.Set; |
| import javax.swing.BorderFactory; |
| import org.netbeans.api.visual.action.ActionFactory; |
| import org.netbeans.api.visual.action.MoveProvider; |
| import org.netbeans.api.visual.action.RectangularSelectDecorator; |
| import org.netbeans.api.visual.action.RectangularSelectProvider; |
| import org.netbeans.api.visual.action.SelectProvider; |
| import org.netbeans.api.visual.action.WidgetAction; |
| import org.netbeans.api.visual.anchor.AnchorFactory; |
| import org.netbeans.api.visual.anchor.AnchorShape; |
| import org.netbeans.api.visual.layout.LayoutFactory; |
| import org.netbeans.api.visual.router.RouterFactory; |
| import org.netbeans.api.visual.widget.LayerWidget; |
| import org.netbeans.api.visual.widget.Widget; |
| import org.netbeans.api.visual.graph.GraphScene; |
| import org.netbeans.api.visual.graph.layout.GraphLayout; |
| import org.netbeans.api.visual.layout.SceneLayout; |
| import org.netbeans.api.visual.widget.ConnectionWidget; |
| import org.openide.util.Lookup; |
| |
| /** |
| * |
| * @author Thomas Wuerthinger |
| */ |
| public class ControlFlowScene extends GraphScene<InputBlock, InputBlockEdge> implements SelectProvider, MoveProvider, RectangularSelectDecorator, RectangularSelectProvider { |
| |
| private HashSet<BlockWidget> selection; |
| private HashMap<InputBlock, BlockWidget> blockMap; |
| private InputGraph oldGraph; |
| private LayerWidget edgeLayer; |
| private LayerWidget mainLayer; |
| private LayerWidget selectLayer; |
| private WidgetAction hoverAction = this.createWidgetHoverAction(); |
| private WidgetAction selectAction = ActionFactory.createSelectAction(this); |
| private WidgetAction moveAction = ActionFactory.createMoveAction(null, this); |
| |
| public ControlFlowScene() { |
| selection = new HashSet<BlockWidget>(); |
| |
| this.getInputBindings().setZoomActionModifiers(0); |
| this.setLayout(LayoutFactory.createAbsoluteLayout()); |
| |
| mainLayer = new LayerWidget(this); |
| this.addChild(mainLayer); |
| |
| edgeLayer = new LayerWidget(this); |
| this.addChild(edgeLayer); |
| |
| selectLayer = new LayerWidget(this); |
| this.addChild(selectLayer); |
| |
| this.getActions().addAction(hoverAction); |
| this.getActions().addAction(selectAction); |
| this.getActions().addAction(ActionFactory.createRectangularSelectAction(this, selectLayer, this)); |
| this.getActions().addAction(ActionFactory.createMouseCenteredZoomAction(1.1)); |
| } |
| |
| public void setGraph(InputGraph g) { |
| if (g == oldGraph) { |
| return; |
| } |
| oldGraph = g; |
| |
| ArrayList<InputBlock> blocks = new ArrayList<InputBlock>(this.getNodes()); |
| for (InputBlock b : blocks) { |
| removeNode(b); |
| } |
| |
| ArrayList<InputBlockEdge> edges = new ArrayList<InputBlockEdge>(this.getEdges()); |
| for (InputBlockEdge e : edges) { |
| removeEdge(e); |
| } |
| |
| for (InputBlock b : g.getBlocks()) { |
| addNode(b); |
| } |
| |
| for (InputBlock b : g.getBlocks()) { |
| for (InputBlockEdge e : b.getOutputs()) { |
| addEdge(e); |
| assert g.getBlocks().contains(e.getFrom()); |
| assert g.getBlocks().contains(e.getTo()); |
| this.setEdgeSource(e, e.getFrom()); |
| this.setEdgeTarget(e, e.getTo()); |
| } |
| } |
| |
| GraphLayout layout = new HierarchicalGraphLayout();//GridGraphLayout(); |
| SceneLayout sceneLayout = LayoutFactory.createSceneGraphLayout(this, layout); |
| sceneLayout.invokeLayout(); |
| |
| this.validate(); |
| } |
| |
| public BlockWidget getBlockWidget(InputBlock b) { |
| return blockMap.get(b); |
| } |
| |
| public void clearSelection() { |
| for (BlockWidget w : selection) { |
| w.setState(w.getState().deriveSelected(false)); |
| } |
| selection.clear(); |
| selectionChanged(); |
| } |
| |
| public void selectionChanged() { |
| InputGraphProvider p = Lookup.getDefault().lookup(InputGraphProvider.class); |
| if (p != null) { |
| Set<InputNode> inputNodes = new HashSet<InputNode>(); |
| for (BlockWidget w : selection) { |
| inputNodes.addAll(w.getBlock().getNodes()); |
| } |
| p.setSelectedNodes(inputNodes); |
| } |
| } |
| |
| public void addToSelection(BlockWidget widget) { |
| widget.setState(widget.getState().deriveSelected(true)); |
| selection.add(widget); |
| selectionChanged(); |
| } |
| |
| public void removeFromSelection(BlockWidget widget) { |
| widget.setState(widget.getState().deriveSelected(false)); |
| selection.remove(widget); |
| selectionChanged(); |
| } |
| |
| public boolean isAimingAllowed(Widget widget, Point point, boolean b) { |
| return false; |
| } |
| |
| public boolean isSelectionAllowed(Widget widget, Point point, boolean b) { |
| return true; |
| } |
| |
| public void select(Widget widget, Point point, boolean change) { |
| if (widget == this) { |
| clearSelection(); |
| } else { |
| |
| assert widget instanceof BlockWidget; |
| BlockWidget bw = (BlockWidget) widget; |
| if (change) { |
| if (selection.contains(bw)) { |
| removeFromSelection(bw); |
| } else { |
| addToSelection(bw); |
| } |
| } else { |
| if (!selection.contains(bw)) { |
| clearSelection(); |
| addToSelection(bw); |
| } |
| } |
| } |
| } |
| |
| public void movementStarted(Widget widget) { |
| } |
| |
| public void movementFinished(Widget widget) { |
| } |
| |
| public Point getOriginalLocation(Widget widget) { |
| return widget.getPreferredLocation(); |
| } |
| |
| public void setNewLocation(Widget widget, Point location) { |
| Point originalLocation = getOriginalLocation(widget); |
| int xOffset = location.x - originalLocation.x; |
| int yOffset = location.y - originalLocation.y; |
| for (Widget w : this.selection) { |
| Point p = new Point(w.getPreferredLocation()); |
| p.translate(xOffset, yOffset); |
| w.setPreferredLocation(p); |
| } |
| |
| } |
| |
| public Widget createSelectionWidget() { |
| Widget widget = new Widget(this); |
| widget.setOpaque(false); |
| widget.setBorder(BorderFactory.createLineBorder(Color.black, 2)); |
| widget.setForeground(Color.red); |
| return widget; |
| } |
| |
| public void performSelection(Rectangle rectangle) { |
| |
| if (rectangle.width < 0) { |
| rectangle.x += rectangle.width; |
| rectangle.width *= -1; |
| } |
| |
| if (rectangle.height < 0) { |
| rectangle.y += rectangle.height; |
| rectangle.height *= -1; |
| } |
| |
| boolean changed = false; |
| for (InputBlock b : this.getNodes()) { |
| BlockWidget w = (BlockWidget) findWidget(b); |
| Rectangle r = new Rectangle(w.getBounds()); |
| r.setLocation(w.getLocation()); |
| if (r.intersects(rectangle)) { |
| if (!selection.contains(w)) { |
| changed = true; |
| selection.add(w); |
| w.setState(w.getState().deriveSelected(true)); |
| } |
| } else { |
| if (selection.contains(w)) { |
| changed = true; |
| selection.remove(w); |
| w.setState(w.getState().deriveSelected(false)); |
| } |
| } |
| } |
| |
| if (changed) { |
| selectionChanged(); |
| } |
| |
| } |
| |
| protected Widget attachNodeWidget(InputBlock node) { |
| BlockWidget w = new BlockWidget(this, node); |
| mainLayer.addChild(w); |
| w.getActions().addAction(hoverAction); |
| w.getActions().addAction(selectAction); |
| w.getActions().addAction(moveAction); |
| return w; |
| } |
| |
| protected Widget attachEdgeWidget(InputBlockEdge edge) { |
| ConnectionWidget w = new BlockConnectionWidget(this, edge); |
| w.setRouter(RouterFactory.createDirectRouter()); |
| w.setTargetAnchorShape(AnchorShape.TRIANGLE_FILLED); |
| edgeLayer.addChild(w); |
| return w; |
| } |
| |
| protected void attachEdgeSourceAnchor(InputBlockEdge edge, InputBlock oldSourceNode, InputBlock sourceNode) { |
| Widget w = this.findWidget(edge); |
| assert w instanceof ConnectionWidget; |
| ConnectionWidget cw = (ConnectionWidget) w; |
| cw.setSourceAnchor(AnchorFactory.createRectangularAnchor(findWidget(sourceNode))); |
| |
| } |
| |
| protected void attachEdgeTargetAnchor(InputBlockEdge edge, InputBlock oldTargetNode, InputBlock targetNode) { |
| Widget w = this.findWidget(edge); |
| assert w instanceof ConnectionWidget; |
| ConnectionWidget cw = (ConnectionWidget) w; |
| cw.setTargetAnchor(AnchorFactory.createRectangularAnchor(findWidget(targetNode))); |
| } |
| } |