Mercurial > hg > truffle
diff src/share/tools/IdealGraphVisualizer/ControlFlow/src/com/sun/hotspot/igv/controlflow/ControlFlowScene.java @ 21146:33ff6b03fad1
add support for control flow window and basic block view on graphs
Contributed-by: Michael Haupt <michael.haupt@oracle.com>
Contributed-by: Peter Hofer <peter.hofer@jku.at>
Contributed-by: Thomas Wuerthinger <thomas.wuerthinger@oracle.com>
author | Michael Haupt <michael.haupt@oracle.com> |
---|---|
date | Wed, 29 Apr 2015 08:31:28 +0200 |
parents | |
children |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/share/tools/IdealGraphVisualizer/ControlFlow/src/com/sun/hotspot/igv/controlflow/ControlFlowScene.java Wed Apr 29 08:31:28 2015 +0200 @@ -0,0 +1,299 @@ +/* + * 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.InputBlockEdge; +import com.sun.hotspot.igv.data.InputBlock; +import com.sun.hotspot.igv.data.InputGraph; +import com.sun.hotspot.igv.data.services.InputGraphProvider; +import com.sun.hotspot.igv.data.InputNode; +import com.sun.hotspot.igv.util.LookupHistory; +import java.awt.Color; +import java.awt.Point; +import java.awt.Rectangle; +import java.util.ArrayList; +import java.util.HashSet; +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.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.LayoutFactory; +import org.netbeans.api.visual.layout.SceneLayout; +import org.netbeans.api.visual.widget.ConnectionWidget; + +/** + * + * @author Thomas Wuerthinger + */ +public class ControlFlowScene extends GraphScene<InputBlock, InputBlockEdge> implements SelectProvider, MoveProvider, RectangularSelectDecorator, RectangularSelectProvider { + + private HashSet<BlockWidget> selection; + private InputGraph oldGraph; + private LayerWidget edgeLayer; + private LayerWidget mainLayer; + private LayerWidget selectLayer; + private WidgetAction hoverAction = this.createWidgetHoverAction(); + private WidgetAction selectAction = new DoubleClickSelectAction(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 (InputBlockEdge e : g.getBlockEdges()) { + 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<InputBlock, InputBlockEdge> layout = new HierarchicalGraphLayout<InputBlock, InputBlockEdge>();//GridGraphLayout(); + SceneLayout sceneLayout = LayoutFactory.createSceneGraphLayout(this, layout); + sceneLayout.invokeLayout(); + + this.validate(); + } + + public void clearSelection() { + for (BlockWidget w : selection) { + w.setState(w.getState().deriveSelected(false)); + } + selection.clear(); + selectionChanged(); + } + + public void selectionChanged() { + InputGraphProvider p = LookupHistory.getLast(InputGraphProvider.class);//)Utilities.actionsGlobalContext().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) { + if (selection.contains(widget)) { + // move entire selection + Point originalLocation = getOriginalLocation(widget); + int xOffset = location.x - originalLocation.x; + int yOffset = location.y - originalLocation.y; + for (Widget w : selection) { + Point p = new Point(w.getPreferredLocation()); + p.translate(xOffset, yOffset); + w.setPreferredLocation(p); + } + } else { + widget.setPreferredLocation(location); + } + } + + 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) { + BlockConnectionWidget w = new BlockConnectionWidget(this, edge); + switch (edge.getState()) { + case NEW: + w.setBold(true); + break; + case DELETED: + w.setDashed(true); + break; + } + 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))); + } +}