mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2024-11-22 12:11:55 +00:00
Merge remote-tracking branch 'origin/patch'
This commit is contained in:
commit
3c11555a76
@ -42,7 +42,7 @@ public interface GraphDisplayBroker {
|
||||
|
||||
/**
|
||||
* Adds a listener for notification when the set of graph display providers change or the currently
|
||||
* active graph display provider changes
|
||||
* active graph display provider changes
|
||||
* @param listener the listener to be notified
|
||||
*/
|
||||
public void addGraphDisplayBrokerListener(GraphDisplayBrokerListener listener);
|
||||
@ -54,7 +54,9 @@ public interface GraphDisplayBroker {
|
||||
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 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.
|
||||
|
@ -15,6 +15,9 @@
|
||||
*/
|
||||
package ghidra.graph.export;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import ghidra.framework.options.Options;
|
||||
import ghidra.framework.plugintool.PluginTool;
|
||||
import ghidra.service.graph.GraphDisplay;
|
||||
@ -28,7 +31,7 @@ import ghidra.util.task.TaskMonitor;
|
||||
* {@link GraphDisplay} is mostly just a placeholder for executing the export function. By
|
||||
* hijacking the {@link GraphDisplayProvider} and {@link GraphDisplay} interfaces for exporting,
|
||||
* all graph generating operations can be exported instead of being displayed without changing
|
||||
* the graph generation code.
|
||||
* the graph generation code.
|
||||
*/
|
||||
public class ExportAttributedGraphDisplayProvider implements GraphDisplayProvider {
|
||||
|
||||
@ -51,10 +54,19 @@ public class ExportAttributedGraphDisplayProvider implements GraphDisplayProvide
|
||||
@Override
|
||||
public GraphDisplay getGraphDisplay(boolean reuseGraph,
|
||||
TaskMonitor monitor) {
|
||||
|
||||
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
|
||||
public void initialize(PluginTool tool, Options graphOptions) {
|
||||
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.model.LayoutModel;
|
||||
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.transform.*;
|
||||
import org.jungrapht.visualization.transform.shape.MagnifyImageLensSupport;
|
||||
@ -71,24 +70,6 @@ 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 {
|
||||
|
||||
@ -125,9 +106,8 @@ public class DefaultGraphDisplay implements GraphDisplay {
|
||||
private final DefaultGraphDisplayComponentProvider componentProvider;
|
||||
|
||||
/**
|
||||
* Whether to ensure the focused vertex is visible, scrolling if necessary
|
||||
* the visualization in order to center the selected vertex
|
||||
* or the center of the set of selected vertices
|
||||
* Whether to ensure the focused vertex is visible, scrolling if necessary the visualization in
|
||||
* order to center the selected vertex or the center of the set of selected vertices
|
||||
*/
|
||||
private boolean ensureVertexIsVisible = false;
|
||||
|
||||
@ -150,9 +130,6 @@ public class DefaultGraphDisplay implements GraphDisplay {
|
||||
*/
|
||||
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 FilterDialog filterDialog;
|
||||
@ -299,9 +276,6 @@ public class DefaultGraphDisplay implements GraphDisplay {
|
||||
.build();
|
||||
}
|
||||
|
||||
/**
|
||||
* create the highlighters ({@code Paintable}s to show which vertices have been selected or focused)
|
||||
*/
|
||||
private void buildHighlighers() {
|
||||
|
||||
viewer.removePostRenderPaintable(multiSelectedVertexPaintable);
|
||||
@ -358,10 +332,10 @@ public class DefaultGraphDisplay implements GraphDisplay {
|
||||
((AbstractButton) context.getSourceObject()).isSelected())
|
||||
.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
|
||||
// inside of a traced shape instead of a rectangle
|
||||
// create a toggle for enabling 'free-form' selection: selection is inside of a traced
|
||||
// shape instead of a rectangle
|
||||
new ToggleActionBuilder("Free-Form Selection", ACTION_OWNER)
|
||||
.toolBarIcon(DefaultDisplayGraphIcons.LASSO_ICON)
|
||||
.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() {
|
||||
AttributedVertex vertex = graphCollapser.groupSelectedVertices();
|
||||
if (vertex != null) {
|
||||
@ -615,9 +586,8 @@ public class DefaultGraphDisplay implements GraphDisplay {
|
||||
}
|
||||
|
||||
/**
|
||||
* Ungroup the selected vertices. If the focusedVertex is no longer
|
||||
* in the graph, null it. This will happen if the focusedVertex was
|
||||
* the GroupVertex
|
||||
* Ungroup the selected vertices. If the focusedVertex is no longer in the graph, null it. This
|
||||
* will happen if the focusedVertex was the GroupVertex
|
||||
*/
|
||||
private void ungroupSelectedVertices() {
|
||||
graphCollapser.ungroupSelectedVertices();
|
||||
@ -678,18 +648,16 @@ public class DefaultGraphDisplay implements GraphDisplay {
|
||||
|
||||
// select all the edges that connect the supplied vertices
|
||||
private void selectEdgesConnecting(Collection<AttributedVertex> vertices) {
|
||||
viewer.getSelectedEdgeState()
|
||||
.select(
|
||||
graph.edgeSet()
|
||||
.stream()
|
||||
.filter(
|
||||
e -> {
|
||||
AttributedVertex source = graph.getEdgeSource(e);
|
||||
AttributedVertex target = graph.getEdgeTarget(e);
|
||||
return vertices.contains(source) && vertices.contains(target);
|
||||
})
|
||||
.collect(Collectors.toSet()));
|
||||
|
||||
Set<AttributedEdge> edges = graph.edgeSet()
|
||||
.stream()
|
||||
.filter(
|
||||
e -> {
|
||||
AttributedVertex source = graph.getEdgeSource(e);
|
||||
AttributedVertex target = graph.getEdgeTarget(e);
|
||||
return vertices.contains(source) && vertices.contains(target);
|
||||
})
|
||||
.collect(Collectors.toSet());
|
||||
viewer.getSelectedEdgeState().select(edges);
|
||||
}
|
||||
|
||||
private boolean isAllSelected(Set<AttributedVertex> vertices) {
|
||||
@ -919,9 +887,6 @@ public class DefaultGraphDisplay implements GraphDisplay {
|
||||
viewer.getSelectedVertexState().select(Set.of(source, target));
|
||||
}
|
||||
|
||||
/**
|
||||
* connect the selection state to to the visualization
|
||||
*/
|
||||
private void connectSelectionStateListeners() {
|
||||
switchableSelectionListener = new SwitchableSelectionItemListener();
|
||||
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() {
|
||||
viewer.scaleToLayout();
|
||||
@ -1309,7 +1274,7 @@ public class DefaultGraphDisplay implements GraphDisplay {
|
||||
}
|
||||
});
|
||||
|
||||
// We control tooltips with the PopupRegulator. Use null values to disable the default
|
||||
// We control tooltips with the PopupRegulator. Use null values to disable the default
|
||||
// tool tip mechanism
|
||||
vv.setVertexToolTipFunction(v -> null);
|
||||
vv.setEdgeToolTipFunction(e -> null);
|
||||
@ -1460,9 +1425,14 @@ public class DefaultGraphDisplay implements GraphDisplay {
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return getClass().getSimpleName() + " " + displayId;
|
||||
}
|
||||
|
||||
//==================================================================================================
|
||||
// Inner Classes
|
||||
//==================================================================================================
|
||||
//==================================================================================================
|
||||
|
||||
// class passed to the PopupRegulator to help construct info popups for the graph
|
||||
private class GraphDisplayPopupSource implements PopupSource<AttributedVertex, AttributedEdge> {
|
||||
@ -1476,8 +1446,8 @@ public class DefaultGraphDisplay implements GraphDisplay {
|
||||
@Override
|
||||
public ToolTipInfo<?> getToolTipInfo(MouseEvent event) {
|
||||
|
||||
// check for a vertex hit first, otherwise, we get edge hits when we are hovering
|
||||
// over a vertex, due to how edges are interpreted as existing all the way to the
|
||||
// check for a vertex hit first, otherwise, we get edge hits when we are hovering
|
||||
// over a vertex, due to how edges are interpreted as existing all the way to the
|
||||
// center point of a vertex
|
||||
AttributedVertex vertex = getVertex(event);
|
||||
if (vertex != null) {
|
||||
@ -1531,8 +1501,8 @@ 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.
|
||||
* 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;
|
||||
@ -1545,9 +1515,8 @@ public class DefaultGraphDisplay implements GraphDisplay {
|
||||
}
|
||||
|
||||
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
|
||||
// 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<>(selectedVertices));
|
||||
|
@ -15,8 +15,8 @@
|
||||
*/
|
||||
package ghidra.graph.visualization;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
import java.util.*;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import ghidra.framework.options.Options;
|
||||
import ghidra.framework.options.PreferenceState;
|
||||
@ -55,7 +55,7 @@ public class DefaultGraphDisplayProvider implements GraphDisplayProvider {
|
||||
public GraphDisplay getGraphDisplay(boolean reuseGraph, TaskMonitor monitor) {
|
||||
|
||||
if (reuseGraph && !displays.isEmpty()) {
|
||||
DefaultGraphDisplay visibleGraph = getVisibleGraph();
|
||||
DefaultGraphDisplay visibleGraph = (DefaultGraphDisplay) getActiveGraphDisplay();
|
||||
visibleGraph.restoreToDefaultSetOfActions();
|
||||
return visibleGraph;
|
||||
}
|
||||
@ -66,6 +66,22 @@ public class DefaultGraphDisplayProvider implements GraphDisplayProvider {
|
||||
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
|
||||
public void initialize(PluginTool tool, Options graphOptions) {
|
||||
this.pluginTool = tool;
|
||||
@ -78,20 +94,6 @@ public class DefaultGraphDisplayProvider implements GraphDisplayProvider {
|
||||
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
|
||||
public void optionsChanged(Options graphOptions) {
|
||||
// no supported options
|
||||
|
@ -26,7 +26,7 @@ import ghidra.util.task.TaskMonitor;
|
||||
* Interface for objects that display (or consume) graphs. Normally, a graph display represents
|
||||
* a visual component for displaying and interacting with a graph. Some implementation may not
|
||||
* be a visual component, but instead consumes/processes the graph (i.e. graph exporter). In this
|
||||
* case, there is no interactive element and once the graph has been set on the display, it is
|
||||
* case, there is no interactive element and once the graph has been set on the display, it is
|
||||
* closed.
|
||||
*/
|
||||
public interface GraphDisplay {
|
||||
@ -37,11 +37,13 @@ public interface GraphDisplay {
|
||||
/**
|
||||
* 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
|
||||
*/
|
||||
String SELECTED_EDGE_COLOR = "selectedEdgeColor";
|
||||
public static final String SELECTED_EDGE_COLOR = "selectedEdgeColor";
|
||||
|
||||
/**
|
||||
* 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
|
||||
*/
|
||||
String INITIAL_LAYOUT_ALGORITHM = "initialLayoutAlgorithm";
|
||||
public static final String INITIAL_LAYOUT_ALGORITHM = "initialLayoutAlgorithm";
|
||||
|
||||
/**
|
||||
* true or false
|
||||
* 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
|
||||
* 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.
|
||||
* 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
|
||||
*/
|
||||
String EDGE_TYPE_PRIORITY_LIST = "edgeTypePriorityList";
|
||||
public static final String EDGE_TYPE_PRIORITY_LIST = "edgeTypePriorityList";
|
||||
|
||||
/**
|
||||
* a comma-separated list of edge type names.
|
||||
* any will be considered a favored edge for the min-cross layout
|
||||
* algorithms.
|
||||
* 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
|
||||
@ -121,7 +128,7 @@ public interface GraphDisplay {
|
||||
* @param eventTrigger Provides a hint to the GraphDisplay as to why we are updating the
|
||||
* graph location so that the GraphDisplay can decide if it should send out a notification via
|
||||
* the {@link GraphDisplayListener#selectionChanged(Set)}. For example, if we are updating
|
||||
* the the location due to an event from the main application, we don't want to notify the
|
||||
* the the location due to an event from the main application, we don't want to notify the
|
||||
* application the graph changed to avoid event cycles. See {@link EventTrigger} for more
|
||||
* information.
|
||||
*/
|
||||
@ -153,6 +160,7 @@ public interface GraphDisplay {
|
||||
TaskMonitor monitor) throws CancelledException {
|
||||
setGraph(graph, new GraphDisplayOptions(graph.getGraphType()), title, append, monitor);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the graph to be displayed or consumed by this graph display
|
||||
*
|
||||
|
@ -15,6 +15,8 @@
|
||||
*/
|
||||
package ghidra.service.graph;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import ghidra.framework.options.Options;
|
||||
import ghidra.framework.plugintool.PluginTool;
|
||||
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 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
|
||||
*/
|
||||
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
|
||||
|
@ -91,6 +91,11 @@ public class GraphActionsTest extends AbstractGhidraHeadedIntegrationTest {
|
||||
|
||||
}
|
||||
|
||||
private void close(GraphDisplay gd) {
|
||||
runSwing(() -> gd.close());
|
||||
waitForSwing();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDeSelectVertexAction() {
|
||||
select(a, b, c, d);
|
||||
@ -409,8 +414,35 @@ public class GraphActionsTest extends AbstractGhidraHeadedIntegrationTest {
|
||||
assertTrue(graphSpy.isSelected(a, b, c, d));
|
||||
}
|
||||
|
||||
private void clearSelection() {
|
||||
select();
|
||||
@Test
|
||||
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() {
|
||||
@ -422,6 +454,10 @@ public class GraphActionsTest extends AbstractGhidraHeadedIntegrationTest {
|
||||
pressButtonByText(dialog, "OK", true);
|
||||
}
|
||||
|
||||
private void clearSelection() {
|
||||
select();
|
||||
}
|
||||
|
||||
private void expand() {
|
||||
DockingActionIf action = getAction(tool, "Expand Selected");
|
||||
GraphActionContext context =
|
||||
@ -453,12 +489,13 @@ public class GraphActionsTest extends AbstractGhidraHeadedIntegrationTest {
|
||||
try {
|
||||
display.setGraph(graph, options, "test graph", false, TaskMonitor.DUMMY);
|
||||
}
|
||||
catch (CancelledException e) {
|
||||
catch (CancelledException ce) {
|
||||
// can't happen with a dummy monitor
|
||||
}
|
||||
});
|
||||
|
||||
display.setGraphDisplayListener(new TestGraphDisplayListener("test"));
|
||||
display.setGraphDisplayListener(new TestGraphDisplayListener());
|
||||
waitForSwing();
|
||||
}
|
||||
|
||||
private void select(AttributedVertex... vertices) {
|
||||
@ -484,13 +521,7 @@ public class GraphActionsTest extends AbstractGhidraHeadedIntegrationTest {
|
||||
runSwing(() -> display.setFocusedVertex(vertex, trigger));
|
||||
}
|
||||
|
||||
class TestGraphDisplayListener implements GraphDisplayListener {
|
||||
|
||||
private String name;
|
||||
|
||||
TestGraphDisplayListener(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
private class TestGraphDisplayListener implements GraphDisplayListener {
|
||||
|
||||
@Override
|
||||
public void graphClosed() {
|
||||
@ -509,7 +540,7 @@ public class GraphActionsTest extends AbstractGhidraHeadedIntegrationTest {
|
||||
|
||||
@Override
|
||||
public GraphDisplayListener cloneWith(GraphDisplay graphDisplay) {
|
||||
return new TestGraphDisplayListener("clone");
|
||||
return new TestGraphDisplayListener();
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -519,7 +550,7 @@ public class GraphActionsTest extends AbstractGhidraHeadedIntegrationTest {
|
||||
|
||||
}
|
||||
|
||||
class GraphSpy {
|
||||
private class GraphSpy {
|
||||
AttributedVertex focusedVertex;
|
||||
Set<AttributedVertex> selectedVertices;
|
||||
|
||||
@ -532,8 +563,8 @@ public class GraphActionsTest extends AbstractGhidraHeadedIntegrationTest {
|
||||
return expected.equals(selectedVertices);
|
||||
}
|
||||
|
||||
public boolean isFocused(AttributedVertex a) {
|
||||
return a == focusedVertex;
|
||||
public boolean isFocused(AttributedVertex v) {
|
||||
return v == focusedVertex;
|
||||
}
|
||||
|
||||
public void clear() {
|
||||
|
@ -15,6 +15,9 @@
|
||||
*/
|
||||
package ghidra.graph;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import ghidra.framework.options.Options;
|
||||
import ghidra.framework.plugintool.PluginTool;
|
||||
import ghidra.service.graph.GraphDisplay;
|
||||
@ -38,25 +41,32 @@ public class TestGraphService implements GraphDisplayProvider {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void initialize(PluginTool tool, Options options) {
|
||||
// nothing
|
||||
public GraphDisplay getActiveGraphDisplay() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<GraphDisplay> getAllGraphDisplays() {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void initialize(PluginTool tool, Options options) {
|
||||
// stub
|
||||
}
|
||||
|
||||
@Override
|
||||
public void optionsChanged(Options options) {
|
||||
// nothing
|
||||
|
||||
// stub
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dispose() {
|
||||
// nothing
|
||||
// stub
|
||||
}
|
||||
|
||||
@Override
|
||||
public HelpLocation getHelpLocation() {
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user