Graphing - (various fixes; see below)

-fixed bug that prevented actions being added to sub graphs
-subgraph gets bad tab text
-properties documentation
-fixed incorrect vertex shape function applied to lightweight renderer
-dispose actions on close
This commit is contained in:
dragonmacher 2021-02-04 14:04:39 -05:00
parent 4041c3693b
commit e983784753
10 changed files with 262 additions and 179 deletions

View file

@ -68,9 +68,8 @@ public interface GraphDisplayBroker {
/**
* A convenience method for getting a {@link GraphDisplay} from the currently active provider
*
* <p>This method allows users to override default graph properties defined by
* <b>jungrapht</b>. See that library for a complete list of available properties.
* Default properties can be changed in the {@code jungrapht.properties} file.
* <p>This method allows users to override default graph properties for the graph provider
* being created. See the graph provider implementation for a list of supported properties
*
* @param reuseGraph if true, the provider will attempt to re-use a current graph display
* @param properties a {@code Map} of property key/values that can be used to customize the display

View file

@ -19,7 +19,7 @@ import java.util.*;
import org.jgrapht.Graph;
import docking.action.DockingAction;
import docking.action.DockingActionIf;
import docking.widgets.EventTrigger;
import ghidra.app.services.GraphDisplayBroker;
import ghidra.framework.plugintool.PluginTool;
@ -59,8 +59,6 @@ class ExportAttributedGraphDisplay implements GraphDisplay {
listener.dispose();
}
/**
* set the {@link AttributedGraph} for visualization
* @param attributedGraph the {@link AttributedGraph} to visualize
@ -90,7 +88,8 @@ class ExportAttributedGraphDisplay implements GraphDisplay {
}
@Override
public void setVertexLabelAttribute(String attributeName, int alignment, int size, boolean monospace,
public void setVertexLabelAttribute(String attributeName, int alignment, int size,
boolean monospace,
int maxLines) {
// no effect
}
@ -122,7 +121,7 @@ class ExportAttributedGraphDisplay implements GraphDisplay {
}
@Override
public void addAction(DockingAction action) {
public void addAction(DockingActionIf action) {
// do nothing, actions are not supported by this display
}

View file

@ -19,10 +19,12 @@ import static org.jungrapht.visualization.MultiLayerTransformer.Layer.*;
import static org.jungrapht.visualization.renderers.BiModalRenderer.*;
import java.awt.*;
import java.awt.Dimension;
import java.awt.event.*;
import java.awt.geom.Point2D;
import java.util.*;
import java.util.List;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.logging.Logger;
import java.util.stream.Collectors;
@ -43,9 +45,11 @@ import org.jungrapht.visualization.layout.algorithms.LayoutAlgorithm;
import org.jungrapht.visualization.layout.algorithms.util.InitialDimensionFunction;
import org.jungrapht.visualization.layout.model.LayoutModel;
import org.jungrapht.visualization.layout.model.Point;
import org.jungrapht.visualization.layout.model.Rectangle;
import org.jungrapht.visualization.renderers.*;
import org.jungrapht.visualization.renderers.Renderer;
import org.jungrapht.visualization.renderers.Renderer.VertexLabel;
import org.jungrapht.visualization.renderers.Renderer.VertexLabel.Position;
import org.jungrapht.visualization.selection.MutableSelectedState;
import org.jungrapht.visualization.selection.VertexEndpointsSelectedEdgeSelectedState;
import org.jungrapht.visualization.transform.*;
@ -54,7 +58,8 @@ import org.jungrapht.visualization.transform.shape.MagnifyShapeTransformer;
import org.jungrapht.visualization.util.RectangleUtils;
import docking.ActionContext;
import docking.action.DockingAction;
import docking.DockingActionProxy;
import docking.action.DockingActionIf;
import docking.action.ToggleDockingAction;
import docking.action.builder.*;
import docking.menu.ActionState;
@ -75,6 +80,24 @@ import resources.Icons;
/**
* Delegates to a {@link VisualizationViewer} to draw a graph visualization
*
* <P>This graph uses the following properties:
* <UL>
* <LI>selectedVertexColor - hex color using '0x' or '#', with 6 digits
* </LI>
* <LI>selectedEdgeColor - hex color using '0x' or '#', with 6 digits
* </LI>
* <LI>displayVerticesAsIcons - if true, shapes will be used to draw vertices based upon
* {@link GhidraIconCache}; false, then vertex shapes will be created from
* {@link ProgramGraphFunctions#getVertexShape(Attributed)}
* </LI>
* <LI>vertexLabelPosition - see {@link Position}
* </LI>
* <LI>initialLayoutAlgorithm - the name of the layout algorithm to be used for the initial
* graph layout
* </LI>
* </UL>
*
*/
public class DefaultGraphDisplay implements GraphDisplay {
@ -83,7 +106,7 @@ public class DefaultGraphDisplay implements GraphDisplay {
private static final String FAVORED_EDGE = "Fall-Through";
/*
A handful of jungrapht properties that re used by this graph
A handful of properties that can be set via the constructor
*/
private static final String SELECTED_VERTEX_COLOR = "selectedVertexColor";
private static final String SELECTED_EDGE_COLOR = "selectedEdgeColor";
@ -98,6 +121,7 @@ public class DefaultGraphDisplay implements GraphDisplay {
private Logger log = Logger.getLogger(DefaultGraphDisplay.class.getName());
private Map<String, String> displayProperties = new HashMap<>();
private Set<DockingActionIf> addedActions = new LinkedHashSet<>();
private GraphDisplayListener listener = new DummyGraphDisplayListener();
private String title;
@ -175,8 +199,6 @@ public class DefaultGraphDisplay implements GraphDisplay {
private PopupRegulator<AttributedVertex, AttributedEdge> popupRegulator;
private GhidraGraphCollapser graphCollapser;
private Set<DockingAction> addedActions = new LinkedHashSet<>();
/**
* Create the initial display, the graph-less visualization viewer, and its controls
* @param displayProvider provides a {@link PluginTool} for Docking features
@ -223,14 +245,14 @@ public class DefaultGraphDisplay implements GraphDisplay {
}
private Color getSelectedVertexColor() {
return Colors.getHexColor(displayProperties.getOrDefault(SELECTED_VERTEX_COLOR,
"0xFF0000"));
String property = displayProperties.getOrDefault(SELECTED_VERTEX_COLOR, "0xFF0000");
return Colors.getHexColor(property);
}
// private Color getSelectedEdgeColor() {
// return Colors
// .getHexColor(displayProperties.getOrDefault(SELECTED_EDGE_COLOR, "0xFF0000"));
// }
private Color getSelectedEdgeColor() {
String property = displayProperties.getOrDefault(SELECTED_EDGE_COLOR, "0xFF0000");
return Colors.getHexColor(property);
}
JComponent getComponent() {
JComponent component = viewer.getComponent();
@ -565,9 +587,9 @@ public class DefaultGraphDisplay implements GraphDisplay {
private void createAndDisplaySubGraph() {
GraphDisplay display = graphDisplayProvider.getGraphDisplay(false, TaskMonitor.DUMMY);
try {
display.setGraph(createSubGraph(), "SubGraph", false, TaskMonitor.DUMMY);
display.setGraph(createSubGraph(), title + " - Sub-graph", false, TaskMonitor.DUMMY);
display.setGraphDisplayListener(listener.cloneWith(display));
addedActions.forEach(display::addAction);
copyActionsToNewGraph((DefaultGraphDisplay) display);
}
catch (CancelledException e) {
// using Dummy, so can't happen
@ -580,11 +602,11 @@ public class DefaultGraphDisplay implements GraphDisplay {
AttributedGraph newGraph = new AttributedGraph();
subGraph.vertexSet().forEach(newGraph::addVertex);
subGraph.edgeSet().forEach(e -> {
for (AttributedEdge e : subGraph.edgeSet()) {
AttributedVertex source = subGraph.getEdgeSource(e);
AttributedVertex target = subGraph.getEdgeTarget(e);
newGraph.addEdge(source, target, e);
});
}
return newGraph;
}
@ -599,10 +621,10 @@ public class DefaultGraphDisplay implements GraphDisplay {
private Set<AttributedVertex> getSourceVerticesFromSelected() {
Set<AttributedVertex> sources = new HashSet<>();
Set<AttributedVertex> selectedVertices = getSelectedVertices();
selectedVertices.forEach(v -> {
for (AttributedVertex v : selectedVertices) {
Set<AttributedEdge> edges = graph.incomingEdgesOf(v);
edges.forEach(e -> sources.add(graph.getEdgeSource(e)));
});
}
return sources;
}
@ -617,10 +639,10 @@ public class DefaultGraphDisplay implements GraphDisplay {
private Set<AttributedVertex> getTargetVerticesFromSelected() {
Set<AttributedVertex> targets = new HashSet<>();
Set<AttributedVertex> selectedVertices = getSelectedVertices();
selectedVertices.forEach(v -> {
for (AttributedVertex v : selectedVertices) {
Set<AttributedEdge> edges = graph.outgoingEdgesOf(v);
edges.forEach(e -> targets.add(graph.getEdgeTarget(e)));
});
}
return targets;
}
@ -665,14 +687,14 @@ public class DefaultGraphDisplay implements GraphDisplay {
try {
MutableSelectedState<AttributedVertex> selectedVertexState =
viewer.getSelectedVertexState();
graph.vertexSet().forEach(v -> {
for (AttributedVertex v : graph.vertexSet()) {
if (selectedVertexState.isSelected(v)) {
selectedVertexState.deselect(v);
}
else {
selectedVertexState.select(v);
}
});
}
Set<AttributedVertex> selected = selectedVertexState.getSelected();
notifySelectionChanged(selected);
}
@ -1231,6 +1253,7 @@ public class DefaultGraphDisplay implements GraphDisplay {
RenderContext<AttributedVertex, AttributedEdge> renderContext = vv.getRenderContext();
setVertexPreferences(vv);
// the selectedEdgeState will be controlled by the vertices that are selected.
// if both endpoints of an edge are selected, select that edge.
vv.setSelectedEdgeState(
@ -1239,22 +1262,17 @@ public class DefaultGraphDisplay implements GraphDisplay {
// selected edges will be drawn with a wider stroke
renderContext.setEdgeStrokeFunction(
e -> vv.getSelectedEdges().contains(e) ? new BasicStroke(20.f)
e -> isSelected(e) ? new BasicStroke(20.f)
: ProgramGraphFunctions.getEdgeStroke(e));
// selected edges will be drawn in red (instead of default)
Color selectedEdgeColor =
Colors.getHexColor(
displayProperties.getOrDefault("selectedEdgeColor", "0xFF0000"));
Color selectedEdgeColor = getSelectedEdgeColor();
renderContext.setEdgeDrawPaintFunction(
e -> vv.getSelectedEdges().contains(e) ? selectedEdgeColor
: Colors.getColor(e));
e -> isSelected(e) ? selectedEdgeColor : Colors.getColor(e));
renderContext.setArrowDrawPaintFunction(
e -> vv.getSelectedEdges().contains(e) ? selectedEdgeColor
: Colors.getColor(e));
e -> isSelected(e) ? selectedEdgeColor : Colors.getColor(e));
renderContext.setArrowFillPaintFunction(
e -> vv.getSelectedEdges().contains(e) ? selectedEdgeColor
: Colors.getColor(e));
e -> isSelected(e) ? selectedEdgeColor : Colors.getColor(e));
// assign the shapes to the modal renderer
ModalRenderer<AttributedVertex, AttributedEdge> modalRenderer = vv.getRenderer();
@ -1262,12 +1280,16 @@ public class DefaultGraphDisplay implements GraphDisplay {
Renderer.Vertex<AttributedVertex, AttributedEdge> vertexRenderer =
modalRenderer.getVertexRenderer(LIGHTWEIGHT);
// cause the lightweight (optimized) renderer to use the vertex shapes instead
// of using default shapes.
if (vertexRenderer instanceof LightweightVertexRenderer) {
Function<AttributedVertex, Shape> vertexShapeFunction =
renderContext.getVertexShapeFunction();
LightweightVertexRenderer<AttributedVertex, AttributedEdge> lightweightVertexRenderer =
(LightweightVertexRenderer<AttributedVertex, AttributedEdge>) vertexRenderer;
lightweightVertexRenderer.setVertexShapeFunction(ProgramGraphFunctions::getVertexShape);
lightweightVertexRenderer.setVertexShapeFunction(vertexShapeFunction);
}
renderContext.setVertexLabelRenderer(new JLabelVertexLabelRenderer(Color.black));
@ -1294,27 +1316,25 @@ public class DefaultGraphDisplay implements GraphDisplay {
RenderContext<AttributedVertex, AttributedEdge> renderContext = vv.getRenderContext();
String useIcons =
displayProperties.getOrDefault(DISPLAY_VERTICES_AS_ICONS, Boolean.TRUE.toString());
Function<Shape, Rectangle> toRectangle = s -> RectangleUtils.convert(s.getBounds2D());
if (Boolean.parseBoolean(useIcons)) {
// set up the shape and color functions
IconShapeFunction<AttributedVertex> nodeImageShapeFunction =
IconShapeFunction<AttributedVertex> nodeShaper =
new IconShapeFunction<>(new EllipseShapeFunction<>());
nodeImageShapeFunction.setIconFunction(iconCache::get);
renderContext.setVertexShapeFunction(nodeImageShapeFunction);
nodeShaper.setIconFunction(iconCache::get);
renderContext.setVertexShapeFunction(nodeShaper);
renderContext.setVertexIconFunction(iconCache::get);
vv.setInitialDimensionFunction(InitialDimensionFunction
.builder(
nodeImageShapeFunction
.andThen(s -> RectangleUtils.convert(s.getBounds2D())))
.builder(nodeShaper.andThen(toRectangle))
.build());
}
else {
vv.getRenderContext().setVertexShapeFunction(ProgramGraphFunctions::getVertexShape);
vv.setInitialDimensionFunction(InitialDimensionFunction
.builder(
renderContext.getVertexShapeFunction()
.andThen(s -> RectangleUtils.convert(s.getBounds2D())))
.builder(renderContext.getVertexShapeFunction()
.andThen(toRectangle))
.build());
vv.getRenderContext().setVertexLabelFunction(Object::toString);
vv.getRenderContext()
@ -1324,52 +1344,40 @@ public class DefaultGraphDisplay implements GraphDisplay {
}
}
/**
* Item listener for selection changes in the graph with the additional
* capability of being able to disable the listener without removing it.
*/
class SwitchableSelectionItemListener implements ItemListener {
boolean enabled = true;
private void copyActionsToNewGraph(DefaultGraphDisplay display) {
@Override
public void itemStateChanged(ItemEvent e) {
if (enabled) {
Swing.runLater(() -> run(e));
}
for (DockingActionIf action : addedActions) {
if (display.containsAction(action)) {
// ignore actions added by the graph itself and any actions that the end user may
// accidentally add more than once
continue;
}
private void run(ItemEvent e) {
// there was a change in the set of selected vertices.
// if the focused vertex is null, set it from one of the selected
// vertices
if (e.getStateChange() == ItemEvent.SELECTED) {
Set<AttributedVertex> selectedVertices = getSelectedVertices();
notifySelectionChanged(new HashSet<AttributedVertex>(selectedVertices));
if (selectedVertices.size() == 1) {
// if only one vertex was selected, make it the focused vertex
setFocusedVertex(selectedVertices.stream().findFirst().get());
}
else if (DefaultGraphDisplay.this.focusedVertex == null) {
// if there is currently no focused Vertex, attempt to get
// one from the selectedVertices
setFocusedVertex(selectedVertices.stream().findFirst().orElse(null));
}
}
else if (e.getStateChange() == ItemEvent.DESELECTED) {
Set<AttributedVertex> selectedVertices = getSelectedVertices();
notifySelectionChanged(selectedVertices);
}
viewer.repaint();
display.addAction(new DockingActionProxy(action));
}
void setEnabled(boolean enabled) {
this.enabled = enabled;
}
private boolean containsAction(DockingActionIf action) {
String name = action.getFullName(); // name and owner
for (DockingActionIf existingAction : addedActions) {
if (name.equals(existingAction.getFullName())) {
return true;
}
}
return false;
}
@Override
public void addAction(DockingAction action) {
public void addAction(DockingActionIf action) {
if (containsAction(action)) {
Msg.warn(this, "Action with same name and owner already exixts in graph: " +
action.getFullName());
return;
}
addedActions.add(action);
Swing.runLater(() -> componentProvider.addLocalAction(action));
}
@ -1456,6 +1464,10 @@ public class DefaultGraphDisplay implements GraphDisplay {
});
}
//==================================================================================================
// Inner Classes
//==================================================================================================
// class passed to the PopupRegulator to help construct info popups for the graph
private class GraphDisplayPopupSource implements PopupSource<AttributedVertex, AttributedEdge> {
@ -1554,4 +1566,49 @@ public class DefaultGraphDisplay implements GraphDisplay {
// this graph display does not have a notion of emphasizing
}
}
/**
* Item listener for selection changes in the graph with the additional
* capability of being able to disable the listener without removing it.
*/
private class SwitchableSelectionItemListener implements ItemListener {
boolean enabled = true;
@Override
public void itemStateChanged(ItemEvent e) {
if (enabled) {
Swing.runLater(() -> run(e));
}
}
private void run(ItemEvent e) {
// there was a change in the set of selected vertices.
// if the focused vertex is null, set it from one of the selected
// vertices
if (e.getStateChange() == ItemEvent.SELECTED) {
Set<AttributedVertex> selectedVertices = getSelectedVertices();
notifySelectionChanged(new HashSet<AttributedVertex>(selectedVertices));
if (selectedVertices.size() == 1) {
// if only one vertex was selected, make it the focused vertex
setFocusedVertex(selectedVertices.stream().findFirst().get());
}
else if (DefaultGraphDisplay.this.focusedVertex == null) {
// if there is currently no focused Vertex, attempt to get
// one from the selectedVertices
setFocusedVertex(selectedVertices.stream().findFirst().orElse(null));
}
}
else if (e.getStateChange() == ItemEvent.DESELECTED) {
Set<AttributedVertex> selectedVertices = getSelectedVertices();
notifySelectionChanged(selectedVertices);
}
viewer.repaint();
}
void setEnabled(boolean enabled) {
this.enabled = enabled;
}
}
}

View file

@ -57,10 +57,11 @@ public class DefaultGraphDisplayComponentProvider extends ComponentProviderAdapt
public void closeComponent() {
if (display != null) {
super.closeComponent();
// to prevent looping, null out display before callings its close method.
// to prevent looping, null out display before calling its close method.
GraphDisplay closingDisplay = display;
display = null;
closingDisplay.close();
removeAllLocalActions();
}
}

View file

@ -362,9 +362,9 @@
<BLOCKQUOTE>
<H3><A NAME="Rename_Vertex"></A>Rename Vertex</H3>
<H3><A NAME="Rename_Symbol"></A>Rename Symbol</H3>
<BLOCKQUOTE>
<P>Allows the user to rename the symbol represented by the given vertex.
<P>Allows the user to rename the symbol in the program represented by the given vertex.
</P>
</BLOCKQUOTE>

View file

@ -18,8 +18,10 @@ package ghidra.graph.program;
import java.awt.Color;
import java.util.*;
import docking.action.builder.ActionBuilder;
import docking.widgets.EventTrigger;
import ghidra.app.plugin.core.colorizer.ColorizingService;
import ghidra.app.util.AddEditDialog;
import ghidra.framework.plugintool.PluginTool;
import ghidra.program.model.address.*;
import ghidra.program.model.block.*;
@ -28,8 +30,7 @@ import ghidra.program.model.symbol.*;
import ghidra.program.util.ProgramLocation;
import ghidra.program.util.ProgramSelection;
import ghidra.service.graph.*;
import ghidra.util.HTMLUtilities;
import ghidra.util.Msg;
import ghidra.util.*;
import ghidra.util.exception.CancelledException;
import ghidra.util.exception.GraphException;
import ghidra.util.task.Task;
@ -145,6 +146,7 @@ public class BlockGraphTask extends Task {
GraphDisplay display = graphProvider.getGraphDisplay(reuseGraph, monitor);
BlockModelGraphDisplayListener listener =
new BlockModelGraphDisplayListener(tool, blockModel, display);
addActions(display, v -> listener.getAddress(v));
display.setGraphDisplayListener(listener);
if (showCode) {
@ -175,6 +177,37 @@ public class BlockGraphTask extends Task {
}
}
private void addActions(GraphDisplay display,
java.util.function.Function<AttributedVertex, Address> addressFunction) {
display.addAction(new ActionBuilder("Rename Symbol", "Block Graph")
.popupMenuPath("Rename Symbol")
.withContext(VertexGraphActionContext.class)
.helpLocation(new HelpLocation("ProgramGraphPlugin", "Rename_Symbol"))
// only enable action when vertex corresponds to an address
.enabledWhen(c -> addressFunction.apply(c.getClickedVertex()) != null)
.onAction(c -> updateVertexName(addressFunction, c))
.build());
}
private void updateVertexName(
java.util.function.Function<AttributedVertex, Address> addressFunction,
VertexGraphActionContext context) {
AttributedVertex vertex = context.getClickedVertex();
Address address = addressFunction.apply(vertex);
Symbol symbol = program.getSymbolTable().getPrimarySymbol(address);
if (symbol == null) {
AddEditDialog dialog = new AddEditDialog("Create Label", tool);
dialog.addLabel(address, program, context.getComponentProvider());
}
else {
AddEditDialog dialog = new AddEditDialog("Edit Label", tool);
dialog.editLabel(symbol, program, context.getComponentProvider());
}
}
/**
* Set the maximum number of code lines which will be used per block when
* showCode is enabled.
@ -318,10 +351,8 @@ public class BlockGraphTask extends Task {
CodeBlockReference cbRef = refIter.next();
CodeBlock db = cbRef.getDestinationBlock();
// must be a reference to a data block
if (db == null) {
continue;
continue; // must be a reference to a data block
}
// don't include destination if it does not overlap selection
@ -336,7 +367,6 @@ public class BlockGraphTask extends Task {
}
// put the edge in the graph
String edgeAddr = cbRef.getReferent().toString();
AttributedEdge newEdge = graph.addEdge(fromVertex, toVertex);
// set it's attributes (really its name)

View file

@ -17,16 +17,13 @@ package ghidra.graph.program;
import java.util.*;
import docking.action.builder.ActionBuilder;
import ghidra.app.plugin.core.graph.AddressBasedGraphDisplayListener;
import ghidra.app.util.AddEditDialog;
import ghidra.framework.plugintool.PluginTool;
import ghidra.program.model.address.*;
import ghidra.program.model.block.*;
import ghidra.program.model.symbol.Symbol;
import ghidra.program.model.symbol.SymbolTable;
import ghidra.service.graph.*;
import ghidra.util.HelpLocation;
import ghidra.util.exception.CancelledException;
import ghidra.util.task.TaskMonitor;
@ -41,18 +38,11 @@ public class BlockModelGraphDisplayListener extends AddressBasedGraphDisplayList
GraphDisplay display) {
super(tool, blockModel.getProgram(), display);
this.blockModel = blockModel;
addActions(display);
}
private void addActions(GraphDisplay display) {
display.addAction(new ActionBuilder("Rename Vertex", "Block Graph")
.popupMenuPath("Rename Vertex")
.withContext(VertexGraphActionContext.class)
.helpLocation(new HelpLocation("ProgramGraphPlugin", "Rename Vertex"))
// only enable action when vertex corresponds to an address
.enabledWhen(c -> getAddress(c.getClickedVertex().getId()) != null)
.onAction(this::updateVertexName)
.build());
@Override
public Address getAddress(AttributedVertex vertex) {
return super.getAddress(vertex);
}
@Override
@ -79,11 +69,24 @@ public class BlockModelGraphDisplayListener extends AddressBasedGraphDisplayList
// Identify all blocks which have an entry point within the selection address set
Set<AttributedVertex> vertices = new HashSet<>();
try {
addVerticesForAddresses(addrSet, vertices);
}
catch (CancelledException e) {
// Will not happen with dummyMonitor
// Model has already done the work when the graph was created
}
return vertices;
}
private void addVerticesForAddresses(AddressSetView addrSet, Set<AttributedVertex> vertices)
throws CancelledException {
SymbolTable symTable = program.getSymbolTable();
CodeBlockIterator cbIter =
CodeBlockIterator it =
blockModel.getCodeBlocksContaining(addrSet, TaskMonitor.DUMMY);
while (cbIter.hasNext()) {
CodeBlock block = cbIter.next();
while (it.hasNext()) {
CodeBlock block = it.next();
String addrString;
Address addr = block.getFirstStartAddress();
if (addr.isExternalAddress()) {
@ -99,26 +102,33 @@ public class BlockModelGraphDisplayListener extends AddressBasedGraphDisplayList
}
}
}
catch (CancelledException e) {
// Will not happen with dummyMonitor
// Model has already done the work when the graph was created
}
return vertices;
}
@Override
protected AddressSet getAddresses(Set<AttributedVertex> vertices) {
AddressSet addrSet = new AddressSet();
AddressSet addrSet = new AddressSet();
try {
// for each address string, translate it into a block
// and add it to the address set.
for (AttributedVertex vertex : vertices) {
addBlockAddresses(addrSet, vertex);
}
}
catch (CancelledException e) {
// Will not happen with dummyMonitor
// Model has already done the work when the graph was created
}
return addrSet;
}
private void addBlockAddresses(AddressSet addrSet, AttributedVertex vertex)
throws CancelledException {
Address blockAddr = getAddress(vertex);
if (!isValidAddress(blockAddr)) {
continue;
return;
}
CodeBlock blocks[] = null;
if (blockModel != null) {
CodeBlock block = blockModel.getCodeBlockAt(blockAddr, TaskMonitor.DUMMY);
@ -139,13 +149,6 @@ public class BlockModelGraphDisplayListener extends AddressBasedGraphDisplayList
addrSet.addRange(blockAddr, blockAddr);
}
}
}
catch (CancelledException e) {
// Will not happen with dummyMonitor
// Model has already done the work when the graph was created
}
return addrSet;
}
protected boolean isValidAddress(Address addr) {
if (addr == null || program == null) {
@ -154,21 +157,6 @@ public class BlockModelGraphDisplayListener extends AddressBasedGraphDisplayList
return program.getMemory().contains(addr) || addr.isExternalAddress();
}
private void updateVertexName(VertexGraphActionContext context) {
AttributedVertex vertex = context.getClickedVertex();
Address address = getAddress(vertex);
Symbol symbol = program.getSymbolTable().getPrimarySymbol(address);
if (symbol == null) {
AddEditDialog dialog = new AddEditDialog("Create Label", tool);
dialog.addLabel(address, program, context.getComponentProvider());
}
else {
AddEditDialog dialog = new AddEditDialog("Edit Label", tool);
dialog.editLabel(symbol, program, context.getComponentProvider());
}
}
@Override
public GraphDisplayListener cloneWith(GraphDisplay newGraphDisplay) {
return new BlockModelGraphDisplayListener(tool, blockModel, newGraphDisplay);

View file

@ -18,7 +18,7 @@ package ghidra.graph.program;
import java.util.HashSet;
import java.util.Set;
import docking.action.DockingAction;
import docking.action.DockingActionIf;
import docking.widgets.EventTrigger;
import ghidra.service.graph.*;
import ghidra.util.exception.CancelledException;
@ -74,7 +74,8 @@ public class TestGraphDisplay implements GraphDisplay {
}
@Override
public void setVertexLabelAttribute(String attributeName, int alignment, int size, boolean monospace,
public void setVertexLabelAttribute(String attributeName, int alignment, int size,
boolean monospace,
int maxLines) {
// nothing
}
@ -116,8 +117,7 @@ public class TestGraphDisplay implements GraphDisplay {
}
@Override
public void addAction(DockingAction action) {
public void addAction(DockingActionIf action) {
// do nothing, actions are not supported by this display
}
}

View file

@ -17,7 +17,7 @@ package ghidra.service.graph;
import java.util.Set;
import docking.action.DockingAction;
import docking.action.DockingActionIf;
import docking.widgets.EventTrigger;
import ghidra.util.exception.CancelledException;
import ghidra.util.task.TaskMonitor;
@ -43,7 +43,7 @@ public interface GraphDisplay {
public void setGraphDisplayListener(GraphDisplayListener listener);
/**
* Tells the graph display window to focus the vertex with the given id.
* Tells the graph display window to focus the vertex with the given id
*
* @param vertex the vertex to focus
* @param eventTrigger Provides a hint to the GraphDisplay as to why we are updating the
@ -63,7 +63,8 @@ public interface GraphDisplay {
/**
* Returns the currently focused vertex or null if no vertex is focused
* @return the currently focused vertex or null if no vertex is focused.
*
* @return the currently focused vertex or null if no vertex is focused
*/
public AttributedVertex getFocusedVertex();
@ -82,6 +83,7 @@ public interface GraphDisplay {
/**
* Returns a set of vertex ids for all the currently selected vertices
*
* @return a set of vertex ids for all the currently selected vertices
*/
public Set<AttributedVertex> getSelectedVertices();
@ -94,7 +96,7 @@ public interface GraphDisplay {
/**
* Defines a vertex attribute type for this graph window
*
* @param name the name of the attribute which may be attached to vertices.
* @param name the name of the attribute which may be attached to vertices
*/
public void defineVertexAttribute(String name);
@ -106,22 +108,25 @@ public interface GraphDisplay {
public void defineEdgeAttribute(String name);
/**
* Sets the name of the attribute which should be used as the primary vertex label in the display.
* @param attributeName the name of the attribute to use as the display label for vertices.
* Sets the name of the attribute which should be used as the primary vertex label
*
* @param attributeName the name of the attribute to use as the display label for vertices
* @param alignment (ALIGN_LEFT, ALIGN_RIGHT, or ALIGN_CENTER)
* @param size the font size to use for the display label
* @param monospace true if the font should be monospaced
* @param maxLines the maximum number lines to display in the vertex labels
*/
public void setVertexLabelAttribute(String attributeName, int alignment, int size, boolean monospace,
public void setVertexLabelAttribute(String attributeName, int alignment, int size,
boolean monospace,
int maxLines);
/**
* Sets the graph to be displayed or consumed by this graph display
*
* @param graph the graph to display or consume
* @param title a title for the graph
* @param monitor a {@link TaskMonitor} which can be used to cancel the graphing operation
* @param append if true, append the new graph to any existing graph.
* @param append if true, append the new graph to any existing graph
* @throws CancelledException thrown if the graphing operation was cancelled
*/
public void setGraph(AttributedGraph graph, String title, boolean append,
@ -135,6 +140,7 @@ public interface GraphDisplay {
/**
* Updates a vertex to a new name
*
* @param vertex the vertex to rename
* @param newName the new name for the vertex
*/
@ -142,6 +148,7 @@ public interface GraphDisplay {
/**
* Returns the title of the current graph
*
* @return the title of the current graph
*/
public String getGraphTitle();
@ -149,7 +156,8 @@ public interface GraphDisplay {
/**
* Adds the action to the graph display. Not all GraphDisplays support adding custom
* actions, so this may have no effect.
* @param action the action to add.
*
* @param action the action to add
*/
public void addAction(DockingAction action);
public void addAction(DockingActionIf action);
}

View file

@ -15,6 +15,7 @@
*/
package ghidra.service.graph;
import java.util.Objects;
import java.util.Set;
import docking.ComponentProvider;
@ -31,7 +32,7 @@ public class VertexGraphActionContext extends GraphActionContext {
AttributedVertex locatedVertex, AttributedVertex clickedVertex) {
super(componentProvider, graph, selectedVertices, locatedVertex);
this.clickedVertex = clickedVertex;
this.clickedVertex = Objects.requireNonNull(clickedVertex);
}
/**