mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2025-10-05 19:42:36 +02:00
Merge remote-tracking branch 'origin/patch'
This commit is contained in:
commit
3c11555a76
8 changed files with 169 additions and 116 deletions
|
@ -54,7 +54,9 @@ public interface GraphDisplayBroker {
|
||||||
public void removeGraphDisplayBrokerLisetener(GraphDisplayBrokerListener listener);
|
public void removeGraphDisplayBrokerLisetener(GraphDisplayBrokerListener listener);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A convenience method for getting a {@link GraphDisplay} from the currently active provider
|
* A convenience method for getting a {@link GraphDisplay} from the currently active provider.
|
||||||
|
* This method is intended to be used to display a new graph.
|
||||||
|
*
|
||||||
* @param reuseGraph if true, the provider will attempt to re-use a current graph display
|
* @param reuseGraph if true, the provider will attempt to re-use a current graph display
|
||||||
* @param monitor the {@link TaskMonitor} that can be used to cancel the operation
|
* @param monitor the {@link TaskMonitor} that can be used to cancel the operation
|
||||||
* @return a {@link GraphDisplay} object to sends graphs to be displayed or exported.
|
* @return a {@link GraphDisplay} object to sends graphs to be displayed or exported.
|
||||||
|
|
|
@ -15,6 +15,9 @@
|
||||||
*/
|
*/
|
||||||
package ghidra.graph.export;
|
package ghidra.graph.export;
|
||||||
|
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
import ghidra.framework.options.Options;
|
import ghidra.framework.options.Options;
|
||||||
import ghidra.framework.plugintool.PluginTool;
|
import ghidra.framework.plugintool.PluginTool;
|
||||||
import ghidra.service.graph.GraphDisplay;
|
import ghidra.service.graph.GraphDisplay;
|
||||||
|
@ -51,10 +54,19 @@ public class ExportAttributedGraphDisplayProvider implements GraphDisplayProvide
|
||||||
@Override
|
@Override
|
||||||
public GraphDisplay getGraphDisplay(boolean reuseGraph,
|
public GraphDisplay getGraphDisplay(boolean reuseGraph,
|
||||||
TaskMonitor monitor) {
|
TaskMonitor monitor) {
|
||||||
|
|
||||||
return new ExportAttributedGraphDisplay(this);
|
return new ExportAttributedGraphDisplay(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public GraphDisplay getActiveGraphDisplay() {
|
||||||
|
return null; // one-time graph; no active graph
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<GraphDisplay> getAllGraphDisplays() {
|
||||||
|
return Collections.emptyList(); // one-time graph; no active displays
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void initialize(PluginTool tool, Options graphOptions) {
|
public void initialize(PluginTool tool, Options graphOptions) {
|
||||||
this.pluginTool = tool;
|
this.pluginTool = tool;
|
||||||
|
|
|
@ -37,7 +37,6 @@ import org.jungrapht.visualization.layout.algorithms.LayoutAlgorithm;
|
||||||
import org.jungrapht.visualization.layout.algorithms.util.InitialDimensionFunction;
|
import org.jungrapht.visualization.layout.algorithms.util.InitialDimensionFunction;
|
||||||
import org.jungrapht.visualization.layout.model.LayoutModel;
|
import org.jungrapht.visualization.layout.model.LayoutModel;
|
||||||
import org.jungrapht.visualization.layout.model.Point;
|
import org.jungrapht.visualization.layout.model.Point;
|
||||||
import org.jungrapht.visualization.renderers.Renderer.VertexLabel.Position;
|
|
||||||
import org.jungrapht.visualization.selection.MutableSelectedState;
|
import org.jungrapht.visualization.selection.MutableSelectedState;
|
||||||
import org.jungrapht.visualization.transform.*;
|
import org.jungrapht.visualization.transform.*;
|
||||||
import org.jungrapht.visualization.transform.shape.MagnifyImageLensSupport;
|
import org.jungrapht.visualization.transform.shape.MagnifyImageLensSupport;
|
||||||
|
@ -71,24 +70,6 @@ import resources.Icons;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Delegates to a {@link VisualizationViewer} to draw a graph visualization
|
* 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 {
|
public class DefaultGraphDisplay implements GraphDisplay {
|
||||||
|
|
||||||
|
@ -125,9 +106,8 @@ public class DefaultGraphDisplay implements GraphDisplay {
|
||||||
private final DefaultGraphDisplayComponentProvider componentProvider;
|
private final DefaultGraphDisplayComponentProvider componentProvider;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Whether to ensure the focused vertex is visible, scrolling if necessary
|
* Whether to ensure the focused vertex is visible, scrolling if necessary the visualization in
|
||||||
* the visualization in order to center the selected vertex
|
* order to center the selected vertex or the center of the set of selected vertices
|
||||||
* or the center of the set of selected vertices
|
|
||||||
*/
|
*/
|
||||||
private boolean ensureVertexIsVisible = false;
|
private boolean ensureVertexIsVisible = false;
|
||||||
|
|
||||||
|
@ -150,9 +130,6 @@ public class DefaultGraphDisplay implements GraphDisplay {
|
||||||
*/
|
*/
|
||||||
private final GraphJobRunner jobRunner = new GraphJobRunner();
|
private final GraphJobRunner jobRunner = new GraphJobRunner();
|
||||||
|
|
||||||
/**
|
|
||||||
* a satellite view that shows in the lower left corner as a birds-eye view of the graph display
|
|
||||||
*/
|
|
||||||
private final SatelliteVisualizationViewer<AttributedVertex, AttributedEdge> satelliteViewer;
|
private final SatelliteVisualizationViewer<AttributedVertex, AttributedEdge> satelliteViewer;
|
||||||
|
|
||||||
private FilterDialog filterDialog;
|
private FilterDialog filterDialog;
|
||||||
|
@ -299,9 +276,6 @@ public class DefaultGraphDisplay implements GraphDisplay {
|
||||||
.build();
|
.build();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* create the highlighters ({@code Paintable}s to show which vertices have been selected or focused)
|
|
||||||
*/
|
|
||||||
private void buildHighlighers() {
|
private void buildHighlighers() {
|
||||||
|
|
||||||
viewer.removePostRenderPaintable(multiSelectedVertexPaintable);
|
viewer.removePostRenderPaintable(multiSelectedVertexPaintable);
|
||||||
|
@ -358,10 +332,10 @@ public class DefaultGraphDisplay implements GraphDisplay {
|
||||||
((AbstractButton) context.getSourceObject()).isSelected())
|
((AbstractButton) context.getSourceObject()).isSelected())
|
||||||
.buildAndInstallLocal(componentProvider);
|
.buildAndInstallLocal(componentProvider);
|
||||||
|
|
||||||
this.ensureVertexIsVisible = true; // since we intialized action to selected
|
this.ensureVertexIsVisible = true; // since we initialized action to selected
|
||||||
|
|
||||||
// create a toggle for enabling 'free-form' selection: selection is
|
// create a toggle for enabling 'free-form' selection: selection is inside of a traced
|
||||||
// inside of a traced shape instead of a rectangle
|
// shape instead of a rectangle
|
||||||
new ToggleActionBuilder("Free-Form Selection", ACTION_OWNER)
|
new ToggleActionBuilder("Free-Form Selection", ACTION_OWNER)
|
||||||
.toolBarIcon(DefaultDisplayGraphIcons.LASSO_ICON)
|
.toolBarIcon(DefaultDisplayGraphIcons.LASSO_ICON)
|
||||||
.description("Trace Free-Form Shape to select multiple vertices (CTRL-click-drag)")
|
.description("Trace Free-Form Shape to select multiple vertices (CTRL-click-drag)")
|
||||||
|
@ -594,9 +568,6 @@ public class DefaultGraphDisplay implements GraphDisplay {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Group the selected vertices into one vertex that represents them all
|
|
||||||
*/
|
|
||||||
private void groupSelectedVertices() {
|
private void groupSelectedVertices() {
|
||||||
AttributedVertex vertex = graphCollapser.groupSelectedVertices();
|
AttributedVertex vertex = graphCollapser.groupSelectedVertices();
|
||||||
if (vertex != null) {
|
if (vertex != null) {
|
||||||
|
@ -615,9 +586,8 @@ public class DefaultGraphDisplay implements GraphDisplay {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Ungroup the selected vertices. If the focusedVertex is no longer
|
* Ungroup the selected vertices. If the focusedVertex is no longer in the graph, null it. This
|
||||||
* in the graph, null it. This will happen if the focusedVertex was
|
* will happen if the focusedVertex was the GroupVertex
|
||||||
* the GroupVertex
|
|
||||||
*/
|
*/
|
||||||
private void ungroupSelectedVertices() {
|
private void ungroupSelectedVertices() {
|
||||||
graphCollapser.ungroupSelectedVertices();
|
graphCollapser.ungroupSelectedVertices();
|
||||||
|
@ -678,18 +648,16 @@ public class DefaultGraphDisplay implements GraphDisplay {
|
||||||
|
|
||||||
// select all the edges that connect the supplied vertices
|
// select all the edges that connect the supplied vertices
|
||||||
private void selectEdgesConnecting(Collection<AttributedVertex> vertices) {
|
private void selectEdgesConnecting(Collection<AttributedVertex> vertices) {
|
||||||
viewer.getSelectedEdgeState()
|
Set<AttributedEdge> edges = graph.edgeSet()
|
||||||
.select(
|
.stream()
|
||||||
graph.edgeSet()
|
.filter(
|
||||||
.stream()
|
e -> {
|
||||||
.filter(
|
AttributedVertex source = graph.getEdgeSource(e);
|
||||||
e -> {
|
AttributedVertex target = graph.getEdgeTarget(e);
|
||||||
AttributedVertex source = graph.getEdgeSource(e);
|
return vertices.contains(source) && vertices.contains(target);
|
||||||
AttributedVertex target = graph.getEdgeTarget(e);
|
})
|
||||||
return vertices.contains(source) && vertices.contains(target);
|
.collect(Collectors.toSet());
|
||||||
})
|
viewer.getSelectedEdgeState().select(edges);
|
||||||
.collect(Collectors.toSet()));
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean isAllSelected(Set<AttributedVertex> vertices) {
|
private boolean isAllSelected(Set<AttributedVertex> vertices) {
|
||||||
|
@ -919,9 +887,6 @@ public class DefaultGraphDisplay implements GraphDisplay {
|
||||||
viewer.getSelectedVertexState().select(Set.of(source, target));
|
viewer.getSelectedVertexState().select(Set.of(source, target));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* connect the selection state to to the visualization
|
|
||||||
*/
|
|
||||||
private void connectSelectionStateListeners() {
|
private void connectSelectionStateListeners() {
|
||||||
switchableSelectionListener = new SwitchableSelectionItemListener();
|
switchableSelectionListener = new SwitchableSelectionItemListener();
|
||||||
viewer.getSelectedVertexState().addItemListener(switchableSelectionListener);
|
viewer.getSelectedVertexState().addItemListener(switchableSelectionListener);
|
||||||
|
@ -1188,7 +1153,7 @@ public class DefaultGraphDisplay implements GraphDisplay {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* cause the graph to be centered and scaled nicely for the view window
|
* Cause the graph to be centered and scaled nicely for the view window
|
||||||
*/
|
*/
|
||||||
public void centerAndScale() {
|
public void centerAndScale() {
|
||||||
viewer.scaleToLayout();
|
viewer.scaleToLayout();
|
||||||
|
@ -1460,6 +1425,11 @@ public class DefaultGraphDisplay implements GraphDisplay {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return getClass().getSimpleName() + " " + displayId;
|
||||||
|
}
|
||||||
|
|
||||||
//==================================================================================================
|
//==================================================================================================
|
||||||
// Inner Classes
|
// Inner Classes
|
||||||
//==================================================================================================
|
//==================================================================================================
|
||||||
|
@ -1545,9 +1515,8 @@ public class DefaultGraphDisplay implements GraphDisplay {
|
||||||
}
|
}
|
||||||
|
|
||||||
private void run(ItemEvent e) {
|
private void run(ItemEvent e) {
|
||||||
// there was a change in the set of selected vertices.
|
// There was a change in the set of selected vertices. If the focused vertex is null,
|
||||||
// if the focused vertex is null, set it from one of the selected
|
// set it from one of the selected vertices
|
||||||
// vertices
|
|
||||||
if (e.getStateChange() == ItemEvent.SELECTED) {
|
if (e.getStateChange() == ItemEvent.SELECTED) {
|
||||||
Set<AttributedVertex> selectedVertices = getSelectedVertices();
|
Set<AttributedVertex> selectedVertices = getSelectedVertices();
|
||||||
notifySelectionChanged(new HashSet<>(selectedVertices));
|
notifySelectionChanged(new HashSet<>(selectedVertices));
|
||||||
|
|
|
@ -15,8 +15,8 @@
|
||||||
*/
|
*/
|
||||||
package ghidra.graph.visualization;
|
package ghidra.graph.visualization;
|
||||||
|
|
||||||
import java.util.HashSet;
|
import java.util.*;
|
||||||
import java.util.Set;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
import ghidra.framework.options.Options;
|
import ghidra.framework.options.Options;
|
||||||
import ghidra.framework.options.PreferenceState;
|
import ghidra.framework.options.PreferenceState;
|
||||||
|
@ -55,7 +55,7 @@ public class DefaultGraphDisplayProvider implements GraphDisplayProvider {
|
||||||
public GraphDisplay getGraphDisplay(boolean reuseGraph, TaskMonitor monitor) {
|
public GraphDisplay getGraphDisplay(boolean reuseGraph, TaskMonitor monitor) {
|
||||||
|
|
||||||
if (reuseGraph && !displays.isEmpty()) {
|
if (reuseGraph && !displays.isEmpty()) {
|
||||||
DefaultGraphDisplay visibleGraph = getVisibleGraph();
|
DefaultGraphDisplay visibleGraph = (DefaultGraphDisplay) getActiveGraphDisplay();
|
||||||
visibleGraph.restoreToDefaultSetOfActions();
|
visibleGraph.restoreToDefaultSetOfActions();
|
||||||
return visibleGraph;
|
return visibleGraph;
|
||||||
}
|
}
|
||||||
|
@ -66,6 +66,22 @@ public class DefaultGraphDisplayProvider implements GraphDisplayProvider {
|
||||||
return display;
|
return display;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public GraphDisplay getActiveGraphDisplay() {
|
||||||
|
if (displays.isEmpty()) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return getAllGraphDisplays().get(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<GraphDisplay> getAllGraphDisplays() {
|
||||||
|
return displays.stream()
|
||||||
|
.filter(d -> d.getComponent().isShowing())
|
||||||
|
.sorted((d1, d2) -> -(d1.getId() - d2.getId())) // largest/newest IDs come first
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void initialize(PluginTool tool, Options graphOptions) {
|
public void initialize(PluginTool tool, Options graphOptions) {
|
||||||
this.pluginTool = tool;
|
this.pluginTool = tool;
|
||||||
|
@ -78,20 +94,6 @@ public class DefaultGraphDisplayProvider implements GraphDisplayProvider {
|
||||||
defaultSatelliteState = preferences.getBoolean(DEFAULT_SATELLITE_STATE, false);
|
defaultSatelliteState = preferences.getBoolean(DEFAULT_SATELLITE_STATE, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Get a {@code GraphDisplay} that is 'showing', assuming that is the one the user
|
|
||||||
* wishes to append to.
|
|
||||||
* Called only when displays is not empty. If there are no 'showing' displays,
|
|
||||||
* return one from the Set via its iterator
|
|
||||||
* @return a display that is showing
|
|
||||||
*/
|
|
||||||
private DefaultGraphDisplay getVisibleGraph() {
|
|
||||||
return displays.stream()
|
|
||||||
.filter(d -> d.getComponent().isShowing())
|
|
||||||
.findAny()
|
|
||||||
.orElse(displays.iterator().next());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void optionsChanged(Options graphOptions) {
|
public void optionsChanged(Options graphOptions) {
|
||||||
// no supported options
|
// no supported options
|
||||||
|
|
|
@ -37,11 +37,13 @@ public interface GraphDisplay {
|
||||||
/**
|
/**
|
||||||
* values are color names or rgb in hex '0xFF0000' is red
|
* values are color names or rgb in hex '0xFF0000' is red
|
||||||
*/
|
*/
|
||||||
String SELECTED_VERTEX_COLOR = "selectedVertexColor";
|
public static final String SELECTED_VERTEX_COLOR = "selectedVertexColor";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* values are color names or rgb in hex '0xFF0000' is red
|
* values are color names or rgb in hex '0xFF0000' is red
|
||||||
*/
|
*/
|
||||||
String SELECTED_EDGE_COLOR = "selectedEdgeColor";
|
public static final String SELECTED_EDGE_COLOR = "selectedEdgeColor";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* values are defined as String symbols in LayoutFunction class
|
* values are defined as String symbols in LayoutFunction class
|
||||||
*
|
*
|
||||||
|
@ -52,33 +54,38 @@ public interface GraphDisplay {
|
||||||
*
|
*
|
||||||
* may have no meaning for a different graph visualization library
|
* may have no meaning for a different graph visualization library
|
||||||
*/
|
*/
|
||||||
String INITIAL_LAYOUT_ALGORITHM = "initialLayoutAlgorithm";
|
public static final String INITIAL_LAYOUT_ALGORITHM = "initialLayoutAlgorithm";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* true or false
|
* true or false
|
||||||
* may have no meaning for a different graph visualization library
|
* may have no meaning for a different graph visualization library
|
||||||
*/
|
*/
|
||||||
String DISPLAY_VERTICES_AS_ICONS = "displayVerticesAsIcons";
|
public static final String DISPLAY_VERTICES_AS_ICONS = "displayVerticesAsIcons";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* values are the strings N,NE,E,SE,S,SW,W,NW,AUTO,CNTR
|
* values are the strings N,NE,E,SE,S,SW,W,NW,AUTO,CNTR
|
||||||
* may have no meaning for a different graph visualization library
|
* may have no meaning for a different graph visualization library
|
||||||
*/
|
*/
|
||||||
String VERTEX_LABEL_POSITION = "vertexLabelPosition";
|
public static final String VERTEX_LABEL_POSITION = "vertexLabelPosition";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* true or false, whether edge selection via a mouse click is enabled.
|
* true or false, whether edge selection via a mouse click is enabled.
|
||||||
* May not be supported by another graph visualization library
|
* May not be supported by another graph visualization library
|
||||||
*/
|
*/
|
||||||
String ENABLE_EDGE_SELECTION = "enableEdgeSelection";
|
public static final String ENABLE_EDGE_SELECTION = "enableEdgeSelection";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* a comma-separated list of edge type names in priority order
|
* a comma-separated list of edge type names in priority order
|
||||||
*/
|
*/
|
||||||
String EDGE_TYPE_PRIORITY_LIST = "edgeTypePriorityList";
|
public static final String EDGE_TYPE_PRIORITY_LIST = "edgeTypePriorityList";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* a comma-separated list of edge type names.
|
* a comma-separated list of edge type names.
|
||||||
* any will be considered a favored edge for the min-cross layout
|
* any will be considered a favored edge for the min-cross layout
|
||||||
* algorithms.
|
* algorithms.
|
||||||
* May have no meaning with a different graph visualization library
|
* May have no meaning with a different graph visualization library
|
||||||
*/
|
*/
|
||||||
String FAVORED_EDGES = "favoredEdges";
|
public static final String FAVORED_EDGES = "favoredEdges";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets a {@link GraphDisplayListener} to be notified when the user changes the vertex focus
|
* Sets a {@link GraphDisplayListener} to be notified when the user changes the vertex focus
|
||||||
|
@ -153,6 +160,7 @@ public interface GraphDisplay {
|
||||||
TaskMonitor monitor) throws CancelledException {
|
TaskMonitor monitor) throws CancelledException {
|
||||||
setGraph(graph, new GraphDisplayOptions(graph.getGraphType()), title, append, monitor);
|
setGraph(graph, new GraphDisplayOptions(graph.getGraphType()), title, append, monitor);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the graph to be displayed or consumed by this graph display
|
* Sets the graph to be displayed or consumed by this graph display
|
||||||
*
|
*
|
||||||
|
|
|
@ -15,6 +15,8 @@
|
||||||
*/
|
*/
|
||||||
package ghidra.service.graph;
|
package ghidra.service.graph;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
import ghidra.framework.options.Options;
|
import ghidra.framework.options.Options;
|
||||||
import ghidra.framework.plugintool.PluginTool;
|
import ghidra.framework.plugintool.PluginTool;
|
||||||
import ghidra.util.HelpLocation;
|
import ghidra.util.HelpLocation;
|
||||||
|
@ -38,11 +40,28 @@ public interface GraphDisplayProvider extends ExtensionPoint {
|
||||||
*
|
*
|
||||||
* @param reuseGraph if true, this provider will attempt to re-use an existing GraphDisplay
|
* @param reuseGraph if true, this provider will attempt to re-use an existing GraphDisplay
|
||||||
* @param monitor the {@link TaskMonitor} that can be used to monitor and cancel the operation
|
* @param monitor the {@link TaskMonitor} that can be used to monitor and cancel the operation
|
||||||
* @return A GraphDisplay that can be used to display (or otherwise consume - e.g. export) the graph
|
* @return an object that can be used to display or otherwise consume (e.g., export) the graph
|
||||||
* @throws GraphException thrown if there is a problem creating a GraphDisplay
|
* @throws GraphException thrown if there is a problem creating a GraphDisplay
|
||||||
*/
|
*/
|
||||||
public GraphDisplay getGraphDisplay(boolean reuseGraph, TaskMonitor monitor) throws GraphException;
|
public GraphDisplay getGraphDisplay(boolean reuseGraph, TaskMonitor monitor)
|
||||||
|
throws GraphException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the active graph display or null if there is no active graph display. If only one
|
||||||
|
* graph is displayed, then that graph will be returned. If multiple graphs are being
|
||||||
|
* displayed, then the most recently shown graph will be displayed, regardless of whether that
|
||||||
|
* is the active graph in terms of user interaction.
|
||||||
|
*
|
||||||
|
* @return the active graph display or null if there is no active graph display.
|
||||||
|
*/
|
||||||
|
public GraphDisplay getActiveGraphDisplay();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns all known graph displays. Typically they will be ordered by use, most recently
|
||||||
|
* first.
|
||||||
|
* @return the displays
|
||||||
|
*/
|
||||||
|
public List<GraphDisplay> getAllGraphDisplays();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Provides an opportunity for this provider to register and read tool options
|
* Provides an opportunity for this provider to register and read tool options
|
||||||
|
|
|
@ -91,6 +91,11 @@ public class GraphActionsTest extends AbstractGhidraHeadedIntegrationTest {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void close(GraphDisplay gd) {
|
||||||
|
runSwing(() -> gd.close());
|
||||||
|
waitForSwing();
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testDeSelectVertexAction() {
|
public void testDeSelectVertexAction() {
|
||||||
select(a, b, c, d);
|
select(a, b, c, d);
|
||||||
|
@ -409,8 +414,35 @@ public class GraphActionsTest extends AbstractGhidraHeadedIntegrationTest {
|
||||||
assertTrue(graphSpy.isSelected(a, b, c, d));
|
assertTrue(graphSpy.isSelected(a, b, c, d));
|
||||||
}
|
}
|
||||||
|
|
||||||
private void clearSelection() {
|
@Test
|
||||||
select();
|
public void testGetActiveGraph() throws Exception {
|
||||||
|
|
||||||
|
GraphDisplayBroker broker = tool.getService(GraphDisplayBroker.class);
|
||||||
|
GraphDisplayProvider service = broker.getGraphDisplayProvider("Default Graph Display");
|
||||||
|
GraphDisplay firstDisplay = service.getActiveGraphDisplay();
|
||||||
|
assertNotNull(firstDisplay);
|
||||||
|
|
||||||
|
showGraph();
|
||||||
|
GraphDisplay secondDisplay = service.getActiveGraphDisplay();
|
||||||
|
assertNotNull(secondDisplay);
|
||||||
|
assertNotSame(firstDisplay, secondDisplay);
|
||||||
|
|
||||||
|
showGraph();
|
||||||
|
GraphDisplay thirdDisplay = service.getActiveGraphDisplay();
|
||||||
|
assertNotNull(thirdDisplay);
|
||||||
|
assertNotSame(firstDisplay, thirdDisplay);
|
||||||
|
assertNotSame(secondDisplay, thirdDisplay);
|
||||||
|
|
||||||
|
close(thirdDisplay);
|
||||||
|
close(firstDisplay);
|
||||||
|
|
||||||
|
GraphDisplay activeDisplay = service.getActiveGraphDisplay();
|
||||||
|
assertNotNull(activeDisplay);
|
||||||
|
assertSame(secondDisplay, activeDisplay);
|
||||||
|
|
||||||
|
close(secondDisplay);
|
||||||
|
activeDisplay = service.getActiveGraphDisplay();
|
||||||
|
assertNull(activeDisplay);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void collapse() {
|
private void collapse() {
|
||||||
|
@ -422,6 +454,10 @@ public class GraphActionsTest extends AbstractGhidraHeadedIntegrationTest {
|
||||||
pressButtonByText(dialog, "OK", true);
|
pressButtonByText(dialog, "OK", true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void clearSelection() {
|
||||||
|
select();
|
||||||
|
}
|
||||||
|
|
||||||
private void expand() {
|
private void expand() {
|
||||||
DockingActionIf action = getAction(tool, "Expand Selected");
|
DockingActionIf action = getAction(tool, "Expand Selected");
|
||||||
GraphActionContext context =
|
GraphActionContext context =
|
||||||
|
@ -453,12 +489,13 @@ public class GraphActionsTest extends AbstractGhidraHeadedIntegrationTest {
|
||||||
try {
|
try {
|
||||||
display.setGraph(graph, options, "test graph", false, TaskMonitor.DUMMY);
|
display.setGraph(graph, options, "test graph", false, TaskMonitor.DUMMY);
|
||||||
}
|
}
|
||||||
catch (CancelledException e) {
|
catch (CancelledException ce) {
|
||||||
// can't happen with a dummy monitor
|
// can't happen with a dummy monitor
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
display.setGraphDisplayListener(new TestGraphDisplayListener("test"));
|
display.setGraphDisplayListener(new TestGraphDisplayListener());
|
||||||
|
waitForSwing();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void select(AttributedVertex... vertices) {
|
private void select(AttributedVertex... vertices) {
|
||||||
|
@ -484,13 +521,7 @@ public class GraphActionsTest extends AbstractGhidraHeadedIntegrationTest {
|
||||||
runSwing(() -> display.setFocusedVertex(vertex, trigger));
|
runSwing(() -> display.setFocusedVertex(vertex, trigger));
|
||||||
}
|
}
|
||||||
|
|
||||||
class TestGraphDisplayListener implements GraphDisplayListener {
|
private class TestGraphDisplayListener implements GraphDisplayListener {
|
||||||
|
|
||||||
private String name;
|
|
||||||
|
|
||||||
TestGraphDisplayListener(String name) {
|
|
||||||
this.name = name;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void graphClosed() {
|
public void graphClosed() {
|
||||||
|
@ -509,7 +540,7 @@ public class GraphActionsTest extends AbstractGhidraHeadedIntegrationTest {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public GraphDisplayListener cloneWith(GraphDisplay graphDisplay) {
|
public GraphDisplayListener cloneWith(GraphDisplay graphDisplay) {
|
||||||
return new TestGraphDisplayListener("clone");
|
return new TestGraphDisplayListener();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -519,7 +550,7 @@ public class GraphActionsTest extends AbstractGhidraHeadedIntegrationTest {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
class GraphSpy {
|
private class GraphSpy {
|
||||||
AttributedVertex focusedVertex;
|
AttributedVertex focusedVertex;
|
||||||
Set<AttributedVertex> selectedVertices;
|
Set<AttributedVertex> selectedVertices;
|
||||||
|
|
||||||
|
@ -532,8 +563,8 @@ public class GraphActionsTest extends AbstractGhidraHeadedIntegrationTest {
|
||||||
return expected.equals(selectedVertices);
|
return expected.equals(selectedVertices);
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isFocused(AttributedVertex a) {
|
public boolean isFocused(AttributedVertex v) {
|
||||||
return a == focusedVertex;
|
return v == focusedVertex;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void clear() {
|
public void clear() {
|
||||||
|
|
|
@ -15,6 +15,9 @@
|
||||||
*/
|
*/
|
||||||
package ghidra.graph;
|
package ghidra.graph;
|
||||||
|
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
import ghidra.framework.options.Options;
|
import ghidra.framework.options.Options;
|
||||||
import ghidra.framework.plugintool.PluginTool;
|
import ghidra.framework.plugintool.PluginTool;
|
||||||
import ghidra.service.graph.GraphDisplay;
|
import ghidra.service.graph.GraphDisplay;
|
||||||
|
@ -38,25 +41,32 @@ public class TestGraphService implements GraphDisplayProvider {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void initialize(PluginTool tool, Options options) {
|
public GraphDisplay getActiveGraphDisplay() {
|
||||||
// nothing
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<GraphDisplay> getAllGraphDisplays() {
|
||||||
|
return Collections.emptyList();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void initialize(PluginTool tool, Options options) {
|
||||||
|
// stub
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void optionsChanged(Options options) {
|
public void optionsChanged(Options options) {
|
||||||
// nothing
|
// stub
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void dispose() {
|
public void dispose() {
|
||||||
// nothing
|
// stub
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public HelpLocation getHelpLocation() {
|
public HelpLocation getHelpLocation() {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue