mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2025-10-03 17:59:46 +02:00
GP-1014 - Function Call Graph - add option to change background color;
consolidated graph options.
This commit is contained in:
parent
6962885c3e
commit
9112a84f63
22 changed files with 301 additions and 247 deletions
|
@ -35,8 +35,6 @@ public interface GhidraOptions {
|
||||||
* Category name for the Browser options that affect the display.
|
* Category name for the Browser options that affect the display.
|
||||||
*/
|
*/
|
||||||
final String CATEGORY_BROWSER_DISPLAY = "Listing Display";
|
final String CATEGORY_BROWSER_DISPLAY = "Listing Display";
|
||||||
@Deprecated //remove a few versions after 8.0
|
|
||||||
final String OLD_CATEGORY_BROWSER_DISPLAY = "Browser Display";
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Category name for the Browser Navigation Marker options.
|
* Category name for the Browser Navigation Marker options.
|
||||||
|
@ -101,8 +99,6 @@ public interface GhidraOptions {
|
||||||
* Options name for Browser fields
|
* Options name for Browser fields
|
||||||
*/
|
*/
|
||||||
final String CATEGORY_BROWSER_FIELDS = "Listing Fields";
|
final String CATEGORY_BROWSER_FIELDS = "Listing Fields";
|
||||||
@Deprecated //remove a few versions after 8.0
|
|
||||||
final String OLD_CATEGORY_BROWSER_FIELDS = "Browser Fields";
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Options title for Mnemonic group.
|
* Options title for Mnemonic group.
|
||||||
|
@ -125,8 +121,6 @@ public interface GhidraOptions {
|
||||||
* Category name for Browser Popup options
|
* Category name for Browser Popup options
|
||||||
*/
|
*/
|
||||||
final String CATEGORY_BROWSER_POPUPS = "Listing Popups";
|
final String CATEGORY_BROWSER_POPUPS = "Listing Popups";
|
||||||
@Deprecated //remove a few versions after 8.0
|
|
||||||
final String OLD_CATEGORY_BROWSER_POPUPS = "Browser Popups";
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Category name for Decompiler Popup options
|
* Category name for Decompiler Popup options
|
||||||
|
|
|
@ -131,12 +131,7 @@ public class CodeBrowserPlugin extends Plugin
|
||||||
|
|
||||||
public CodeBrowserPlugin(PluginTool tool) {
|
public CodeBrowserPlugin(PluginTool tool) {
|
||||||
super(tool);
|
super(tool);
|
||||||
tool.registerOptionsNameChange(GhidraOptions.OLD_CATEGORY_BROWSER_FIELDS,
|
|
||||||
GhidraOptions.CATEGORY_BROWSER_FIELDS);
|
|
||||||
tool.registerOptionsNameChange(GhidraOptions.OLD_CATEGORY_BROWSER_DISPLAY,
|
|
||||||
GhidraOptions.CATEGORY_BROWSER_DISPLAY);
|
|
||||||
tool.registerOptionsNameChange(GhidraOptions.OLD_CATEGORY_BROWSER_POPUPS,
|
|
||||||
GhidraOptions.CATEGORY_BROWSER_POPUPS);
|
|
||||||
ToolOptions displayOptions = tool.getOptions(GhidraOptions.CATEGORY_BROWSER_DISPLAY);
|
ToolOptions displayOptions = tool.getOptions(GhidraOptions.CATEGORY_BROWSER_DISPLAY);
|
||||||
ToolOptions fieldOptions = tool.getOptions(GhidraOptions.CATEGORY_BROWSER_FIELDS);
|
ToolOptions fieldOptions = tool.getOptions(GhidraOptions.CATEGORY_BROWSER_FIELDS);
|
||||||
displayOptions.registerOptionsEditor(new ListingDisplayOptionsEditor(displayOptions));
|
displayOptions.registerOptionsEditor(new ListingDisplayOptionsEditor(displayOptions));
|
||||||
|
|
|
@ -20,6 +20,7 @@ import java.util.*;
|
||||||
import docking.ActionContext;
|
import docking.ActionContext;
|
||||||
import docking.action.MenuData;
|
import docking.action.MenuData;
|
||||||
import docking.action.ToggleDockingAction;
|
import docking.action.ToggleDockingAction;
|
||||||
|
import docking.tool.ToolConstants;
|
||||||
import ghidra.app.CorePluginPackage;
|
import ghidra.app.CorePluginPackage;
|
||||||
import ghidra.app.plugin.PluginCategoryNames;
|
import ghidra.app.plugin.PluginCategoryNames;
|
||||||
import ghidra.app.services.GraphDisplayBroker;
|
import ghidra.app.services.GraphDisplayBroker;
|
||||||
|
@ -39,7 +40,7 @@ import ghidra.util.task.TaskMonitor;
|
||||||
shortDescription = "Manages the active Graph Display Service",
|
shortDescription = "Manages the active Graph Display Service",
|
||||||
description = "This plugin searches for available graph display providers and if it finds more" +
|
description = "This plugin searches for available graph display providers and if it finds more" +
|
||||||
"than one, it provides menu options for the user to choose the active provider.",
|
"than one, it provides menu options for the user to choose the active provider.",
|
||||||
servicesProvided = { GraphDisplayBroker.class }
|
servicesProvided = { GraphDisplayBroker.class }
|
||||||
)
|
)
|
||||||
//@formatter:on
|
//@formatter:on
|
||||||
public class GraphDisplayBrokerPlugin extends Plugin
|
public class GraphDisplayBrokerPlugin extends Plugin
|
||||||
|
@ -90,7 +91,7 @@ public class GraphDisplayBrokerPlugin extends Plugin
|
||||||
|
|
||||||
private void initializeServices() {
|
private void initializeServices() {
|
||||||
for (GraphDisplayProvider service : graphDisplayProviders) {
|
for (GraphDisplayProvider service : graphDisplayProviders) {
|
||||||
ToolOptions options = tool.getOptions("Graph");
|
ToolOptions options = tool.getOptions(ToolConstants.GRAPH_OPTIONS);
|
||||||
options.addOptionsChangeListener(this);
|
options.addOptionsChangeListener(this);
|
||||||
service.initialize(tool, options);
|
service.initialize(tool, options);
|
||||||
}
|
}
|
||||||
|
@ -148,7 +149,7 @@ public class GraphDisplayBrokerPlugin extends Plugin
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public GraphDisplay getDefaultGraphDisplay(boolean reuseGraph, Map<String, String> properties,
|
public GraphDisplay getDefaultGraphDisplay(boolean reuseGraph, Map<String, String> properties,
|
||||||
TaskMonitor monitor) throws GraphException {
|
TaskMonitor monitor) throws GraphException {
|
||||||
if (defaultGraphDisplayProvider != null) {
|
if (defaultGraphDisplayProvider != null) {
|
||||||
return defaultGraphDisplayProvider.getGraphDisplay(reuseGraph, properties, monitor);
|
return defaultGraphDisplayProvider.getGraphDisplay(reuseGraph, properties, monitor);
|
||||||
}
|
}
|
||||||
|
|
|
@ -665,7 +665,7 @@ class FGActionManager {
|
||||||
@Override
|
@Override
|
||||||
public void actionPerformed(ActionContext context) {
|
public void actionPerformed(ActionContext context) {
|
||||||
OptionsService service = tool.getService(OptionsService.class);
|
OptionsService service = tool.getService(OptionsService.class);
|
||||||
service.showOptionsDialog(FunctionGraphPlugin.PLUGIN_OPTIONS_NAME,
|
service.showOptionsDialog(FunctionGraphPlugin.OPTIONS_NAME_PATH,
|
||||||
"Function Graph");
|
"Function Graph");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -21,6 +21,7 @@ import javax.swing.ImageIcon;
|
||||||
|
|
||||||
import org.jdom.Element;
|
import org.jdom.Element;
|
||||||
|
|
||||||
|
import docking.tool.ToolConstants;
|
||||||
import ghidra.GhidraOptions;
|
import ghidra.GhidraOptions;
|
||||||
import ghidra.app.CorePluginPackage;
|
import ghidra.app.CorePluginPackage;
|
||||||
import ghidra.app.events.*;
|
import ghidra.app.events.*;
|
||||||
|
@ -57,7 +58,8 @@ import resources.ResourceManager;
|
||||||
//@formatter:on
|
//@formatter:on
|
||||||
public class FunctionGraphPlugin extends ProgramPlugin implements OptionsChangeListener {
|
public class FunctionGraphPlugin extends ProgramPlugin implements OptionsChangeListener {
|
||||||
static final String FUNCTION_GRAPH_NAME = "Function Graph";
|
static final String FUNCTION_GRAPH_NAME = "Function Graph";
|
||||||
static final String PLUGIN_OPTIONS_NAME = FUNCTION_GRAPH_NAME;
|
static final String OPTIONS_NAME_PATH =
|
||||||
|
ToolConstants.GRAPH_OPTIONS + Options.DELIMITER + FUNCTION_GRAPH_NAME;
|
||||||
|
|
||||||
static final ImageIcon ICON = ResourceManager.loadImage("images/function_graph.png");
|
static final ImageIcon ICON = ResourceManager.loadImage("images/function_graph.png");
|
||||||
|
|
||||||
|
@ -147,14 +149,20 @@ public class FunctionGraphPlugin extends ProgramPlugin implements OptionsChangeL
|
||||||
}
|
}
|
||||||
|
|
||||||
private void initializeOptions() {
|
private void initializeOptions() {
|
||||||
ToolOptions options = tool.getOptions(PLUGIN_OPTIONS_NAME);
|
ToolOptions options = tool.getOptions(ToolConstants.GRAPH_OPTIONS);
|
||||||
options.addOptionsChangeListener(this);
|
options.addOptionsChangeListener(this);
|
||||||
functionGraphOptions.registerOptions(options);
|
|
||||||
functionGraphOptions.loadOptions(options);
|
// Graph -> Function Graph
|
||||||
|
Options fgOptions = options.getOptions(FUNCTION_GRAPH_NAME);
|
||||||
|
|
||||||
|
functionGraphOptions.registerOptions(fgOptions);
|
||||||
|
functionGraphOptions.loadOptions(fgOptions);
|
||||||
|
|
||||||
for (FGLayoutProvider layoutProvider : layoutProviders) {
|
for (FGLayoutProvider layoutProvider : layoutProviders) {
|
||||||
|
|
||||||
|
// Graph -> Function Graph -> Layout Name
|
||||||
String layoutName = layoutProvider.getLayoutName();
|
String layoutName = layoutProvider.getLayoutName();
|
||||||
Options layoutToolOptions = options.getOptions(layoutName);
|
Options layoutToolOptions = fgOptions.getOptions(layoutName);
|
||||||
FGLayoutOptions layoutOptions = layoutProvider.createLayoutOptions(layoutToolOptions);
|
FGLayoutOptions layoutOptions = layoutProvider.createLayoutOptions(layoutToolOptions);
|
||||||
if (layoutOptions == null) {
|
if (layoutOptions == null) {
|
||||||
continue; // many layouts do not have options
|
continue; // many layouts do not have options
|
||||||
|
@ -170,7 +178,9 @@ public class FunctionGraphPlugin extends ProgramPlugin implements OptionsChangeL
|
||||||
public void optionsChanged(ToolOptions options, String optionName, Object oldValue,
|
public void optionsChanged(ToolOptions options, String optionName, Object oldValue,
|
||||||
Object newValue) {
|
Object newValue) {
|
||||||
|
|
||||||
functionGraphOptions.loadOptions(options);
|
// Graph -> Function Graph
|
||||||
|
Options fgOptions = options.getOptions(FUNCTION_GRAPH_NAME);
|
||||||
|
functionGraphOptions.loadOptions(fgOptions);
|
||||||
|
|
||||||
connectedProvider.optionsChanged();
|
connectedProvider.optionsChanged();
|
||||||
|
|
||||||
|
|
|
@ -220,8 +220,8 @@ public class FGComponent extends GraphComponent<FGVertex, FGEdge, FunctionGraph>
|
||||||
edgeLabelRenderer.setRotateEdgeLabels(false);
|
edgeLabelRenderer.setRotateEdgeLabels(false);
|
||||||
renderContext.setEdgeLabelRenderer(edgeLabelRenderer);
|
renderContext.setEdgeLabelRenderer(edgeLabelRenderer);
|
||||||
|
|
||||||
viewer.setGraphOptions(options);
|
viewer.setGraphOptions(vgOptions);
|
||||||
Color bgColor = options.getGraphBackgroundColor();
|
Color bgColor = vgOptions.getGraphBackgroundColor();
|
||||||
if (bgColor.equals(VisualGraphOptions.DEFAULT_GRAPH_BACKGROUND_COLOR)) {
|
if (bgColor.equals(VisualGraphOptions.DEFAULT_GRAPH_BACKGROUND_COLOR)) {
|
||||||
|
|
||||||
// Give user notice when seeing the graph for a non-function (such as an undefined
|
// Give user notice when seeing the graph for a non-function (such as an undefined
|
||||||
|
@ -259,7 +259,7 @@ public class FGComponent extends GraphComponent<FGVertex, FGEdge, FunctionGraph>
|
||||||
renderContext.setVertexFillPaintTransformer(new FGVertexPickableBackgroundPaintTransformer(
|
renderContext.setVertexFillPaintTransformer(new FGVertexPickableBackgroundPaintTransformer(
|
||||||
pickedVertexState, Color.YELLOW, START_COLOR, END_COLOR));
|
pickedVertexState, Color.YELLOW, START_COLOR, END_COLOR));
|
||||||
|
|
||||||
viewer.setGraphOptions(options);
|
viewer.setGraphOptions(vgOptions);
|
||||||
|
|
||||||
return viewer;
|
return viewer;
|
||||||
}
|
}
|
||||||
|
@ -287,7 +287,7 @@ public class FGComponent extends GraphComponent<FGVertex, FGEdge, FunctionGraph>
|
||||||
//==================================================================================================
|
//==================================================================================================
|
||||||
|
|
||||||
public FunctionGraphOptions getFucntionGraphOptions() {
|
public FunctionGraphOptions getFucntionGraphOptions() {
|
||||||
return (FunctionGraphOptions) options;
|
return (FunctionGraphOptions) vgOptions;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void ensureCursorVisible(FGVertex vertex) {
|
public void ensureCursorVisible(FGVertex vertex) {
|
||||||
|
|
|
@ -22,7 +22,8 @@ import java.util.Map.Entry;
|
||||||
import ghidra.app.plugin.core.functiongraph.FunctionGraphPlugin;
|
import ghidra.app.plugin.core.functiongraph.FunctionGraphPlugin;
|
||||||
import ghidra.app.plugin.core.functiongraph.graph.layout.FGLayoutOptions;
|
import ghidra.app.plugin.core.functiongraph.graph.layout.FGLayoutOptions;
|
||||||
import ghidra.framework.options.Options;
|
import ghidra.framework.options.Options;
|
||||||
import ghidra.graph.viewer.options.*;
|
import ghidra.graph.viewer.options.RelayoutOption;
|
||||||
|
import ghidra.graph.viewer.options.VisualGraphOptions;
|
||||||
import ghidra.program.model.symbol.FlowType;
|
import ghidra.program.model.symbol.FlowType;
|
||||||
import ghidra.util.HelpLocation;
|
import ghidra.util.HelpLocation;
|
||||||
|
|
||||||
|
@ -162,7 +163,7 @@ public class FunctionGraphOptions extends VisualGraphOptions {
|
||||||
public void registerOptions(Options options) {
|
public void registerOptions(Options options) {
|
||||||
|
|
||||||
HelpLocation help = new HelpLocation(OWNER, "Options");
|
HelpLocation help = new HelpLocation(OWNER, "Options");
|
||||||
options.setOptionsHelpLocation(help);
|
super.registerOptions(options, help);
|
||||||
|
|
||||||
options.registerOption(RELAYOUT_OPTIONS_KEY, relayoutOption, help,
|
options.registerOption(RELAYOUT_OPTIONS_KEY, relayoutOption, help,
|
||||||
RELAYOUT_OPTIONS_DESCRIPTION);
|
RELAYOUT_OPTIONS_DESCRIPTION);
|
||||||
|
@ -170,24 +171,9 @@ public class FunctionGraphOptions extends VisualGraphOptions {
|
||||||
options.registerOption(NAVIGATION_HISTORY_KEY, navigationHistoryChoice, help,
|
options.registerOption(NAVIGATION_HISTORY_KEY, navigationHistoryChoice, help,
|
||||||
NAVIGATION_HISTORY_DESCRIPTION);
|
NAVIGATION_HISTORY_DESCRIPTION);
|
||||||
|
|
||||||
options.registerOption(SHOW_ANIMATION_OPTIONS_KEY, useAnimation(), help,
|
|
||||||
SHOW_ANIMATION_DESCRIPTION);
|
|
||||||
|
|
||||||
options.registerOption(USE_MOUSE_RELATIVE_ZOOM_KEY, useMouseRelativeZoom(), help,
|
|
||||||
USE_MOUSE_RELATIVE_ZOOM_DESCRIPTION);
|
|
||||||
|
|
||||||
options.registerOption(USE_CONDENSED_LAYOUT_KEY, useCondensedLayout(),
|
options.registerOption(USE_CONDENSED_LAYOUT_KEY, useCondensedLayout(),
|
||||||
new HelpLocation(OWNER, "Layout_Compressing"), USE_CONDENSED_LAYOUT_DESCRIPTION);
|
new HelpLocation(OWNER, "Layout_Compressing"), USE_CONDENSED_LAYOUT_DESCRIPTION);
|
||||||
|
|
||||||
options.registerOption(VIEW_RESTORE_OPTIONS_KEY, ViewRestoreOption.START_FULLY_ZOOMED_OUT,
|
|
||||||
help, VIEW_RESTORE_OPTIONS_DESCRIPTION);
|
|
||||||
|
|
||||||
options.registerOption(SCROLL_WHEEL_PANS_KEY, getScrollWheelPans(), help,
|
|
||||||
SCROLL_WHEEL_PANS_DESCRIPTION);
|
|
||||||
|
|
||||||
options.registerOption(GRAPH_BACKGROUND_COLOR_KEY, DEFAULT_GRAPH_BACKGROUND_COLOR, help,
|
|
||||||
GRAPH_BACKGROUND_COLOR_DESCRPTION);
|
|
||||||
|
|
||||||
options.registerOption(DEFAULT_VERTEX_BACKGROUND_COLOR_KEY, DEFAULT_VERTEX_BACKGROUND_COLOR,
|
options.registerOption(DEFAULT_VERTEX_BACKGROUND_COLOR_KEY, DEFAULT_VERTEX_BACKGROUND_COLOR,
|
||||||
help, DEFAULT_VERTEX_BACKGROUND_COLOR_DESCRPTION);
|
help, DEFAULT_VERTEX_BACKGROUND_COLOR_DESCRPTION);
|
||||||
|
|
||||||
|
@ -222,7 +208,11 @@ public class FunctionGraphOptions extends VisualGraphOptions {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public void loadOptions(Options options) {
|
public void loadOptions(Options options) {
|
||||||
|
|
||||||
|
super.loadOptions(options);
|
||||||
|
|
||||||
conditionalJumpEdgeColor =
|
conditionalJumpEdgeColor =
|
||||||
options.getColor(EDGE_COLOR_CONDITIONAL_JUMP_KEY, conditionalJumpEdgeColor);
|
options.getColor(EDGE_COLOR_CONDITIONAL_JUMP_KEY, conditionalJumpEdgeColor);
|
||||||
|
|
||||||
|
@ -245,23 +235,8 @@ public class FunctionGraphOptions extends VisualGraphOptions {
|
||||||
navigationHistoryChoice =
|
navigationHistoryChoice =
|
||||||
options.getEnum(NAVIGATION_HISTORY_KEY, NavigationHistoryChoices.VERTEX_CHANGES);
|
options.getEnum(NAVIGATION_HISTORY_KEY, NavigationHistoryChoices.VERTEX_CHANGES);
|
||||||
|
|
||||||
useAnimation = options.getBoolean(SHOW_ANIMATION_OPTIONS_KEY, useAnimation);
|
|
||||||
|
|
||||||
useMouseRelativeZoom =
|
|
||||||
options.getBoolean(USE_MOUSE_RELATIVE_ZOOM_KEY, useMouseRelativeZoom);
|
|
||||||
|
|
||||||
useCondensedLayout = options.getBoolean(USE_CONDENSED_LAYOUT_KEY, useCondensedLayout);
|
|
||||||
|
|
||||||
useFullSizeTooltip = options.getBoolean(USE_FULL_SIZE_TOOLTIP_KEY, useFullSizeTooltip);
|
useFullSizeTooltip = options.getBoolean(USE_FULL_SIZE_TOOLTIP_KEY, useFullSizeTooltip);
|
||||||
|
|
||||||
viewRestoreOption =
|
|
||||||
options.getEnum(VIEW_RESTORE_OPTIONS_KEY, ViewRestoreOption.START_FULLY_ZOOMED_OUT);
|
|
||||||
|
|
||||||
scrollWheelPans = options.getBoolean(SCROLL_WHEEL_PANS_KEY, scrollWheelPans);
|
|
||||||
|
|
||||||
graphBackgroundColor =
|
|
||||||
options.getColor(GRAPH_BACKGROUND_COLOR_KEY, DEFAULT_GRAPH_BACKGROUND_COLOR);
|
|
||||||
|
|
||||||
defaultVertexBackgroundColor =
|
defaultVertexBackgroundColor =
|
||||||
options.getColor(DEFAULT_VERTEX_BACKGROUND_COLOR_KEY, DEFAULT_VERTEX_BACKGROUND_COLOR);
|
options.getColor(DEFAULT_VERTEX_BACKGROUND_COLOR_KEY, DEFAULT_VERTEX_BACKGROUND_COLOR);
|
||||||
|
|
||||||
|
|
|
@ -232,6 +232,15 @@
|
||||||
</P>
|
</P>
|
||||||
</BLOCKQUOTE>
|
</BLOCKQUOTE>
|
||||||
|
|
||||||
|
<H2><A name="Options"></A>Options</H2>
|
||||||
|
|
||||||
|
<BLOCKQUOTE>
|
||||||
|
<P>The Function Call Graph options are currently a subset of the
|
||||||
|
<A href="help/topics/FunctionGraphPlugin/Function_Graph.html#Options">
|
||||||
|
Function Graph's Options</A>.
|
||||||
|
</P>
|
||||||
|
</BLOCKQUOTE>
|
||||||
|
|
||||||
|
|
||||||
</BLOCKQUOTE>
|
</BLOCKQUOTE>
|
||||||
|
|
||||||
|
@ -240,8 +249,7 @@
|
||||||
<P class="relatedtopic">Related Topics:</P>
|
<P class="relatedtopic">Related Topics:</P>
|
||||||
|
|
||||||
<UL>
|
<UL>
|
||||||
<!-- TODO update this when we introduce the generic graphing help -->
|
<LI><A href="help/topics/Graph/GraphIntro.html">Graphs</A></LI>
|
||||||
<LI>Graphs</LI>
|
|
||||||
</UL><BR>
|
</UL><BR>
|
||||||
<BR>
|
<BR>
|
||||||
</BODY>
|
</BODY>
|
||||||
|
|
|
@ -25,11 +25,17 @@ import ghidra.graph.viewer.options.VisualGraphOptions;
|
||||||
*/
|
*/
|
||||||
public class FcgView extends VisualGraphView<FcgVertex, FcgEdge, FunctionCallGraph> {
|
public class FcgView extends VisualGraphView<FcgVertex, FcgEdge, FunctionCallGraph> {
|
||||||
|
|
||||||
|
private VisualGraphOptions options;
|
||||||
|
|
||||||
|
public FcgView(VisualGraphOptions options) {
|
||||||
|
this.options = options;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void installGraphViewer() {
|
protected void installGraphViewer() {
|
||||||
|
|
||||||
FcgComponent component = createGraphComponent();
|
FcgComponent component = createGraphComponent();
|
||||||
component.setGraphOptions(new VisualGraphOptions());
|
component.setGraphOptions(options);
|
||||||
setGraphComponent(component);
|
setGraphComponent(component);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -15,8 +15,7 @@
|
||||||
*/
|
*/
|
||||||
package functioncalls.plugin;
|
package functioncalls.plugin;
|
||||||
|
|
||||||
import static functioncalls.graph.FcgDirection.IN;
|
import static functioncalls.graph.FcgDirection.*;
|
||||||
import static functioncalls.graph.FcgDirection.OUT;
|
|
||||||
|
|
||||||
import java.awt.*;
|
import java.awt.*;
|
||||||
import java.awt.event.MouseEvent;
|
import java.awt.event.MouseEvent;
|
||||||
|
@ -60,7 +59,7 @@ import resources.Icons;
|
||||||
import util.CollectionUtils;
|
import util.CollectionUtils;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The primary component provider for the {@link FunctionCallGraphPlugin}
|
* The primary component provider for the {@link FunctionCallGraphPlugin}
|
||||||
*/
|
*/
|
||||||
public class FcgProvider
|
public class FcgProvider
|
||||||
extends VisualGraphComponentProvider<FcgVertex, FcgEdge, FunctionCallGraph> {
|
extends VisualGraphComponentProvider<FcgVertex, FcgEdge, FunctionCallGraph> {
|
||||||
|
@ -133,6 +132,10 @@ public class FcgProvider
|
||||||
installGraph();
|
installGraph();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void optionsChanged() {
|
||||||
|
view.optionsChanged();
|
||||||
|
}
|
||||||
|
|
||||||
void locationChanged(ProgramLocation loc) {
|
void locationChanged(ProgramLocation loc) {
|
||||||
if (!navigateIncomingToggleAction.isSelected()) {
|
if (!navigateIncomingToggleAction.isSelected()) {
|
||||||
return;
|
return;
|
||||||
|
@ -277,7 +280,7 @@ public class FcgProvider
|
||||||
|
|
||||||
private void buildComponent() {
|
private void buildComponent() {
|
||||||
|
|
||||||
view = new FcgView();
|
view = new FcgView(plugin.getOptions());
|
||||||
|
|
||||||
view.setVertexClickListener((v, info) -> {
|
view.setVertexClickListener((v, info) -> {
|
||||||
|
|
||||||
|
@ -519,7 +522,7 @@ public class FcgProvider
|
||||||
addLocalAction(resetGraphAction);
|
addLocalAction(resetGraphAction);
|
||||||
|
|
||||||
MultiStateDockingAction<LayoutProvider<FcgVertex, FcgEdge, FunctionCallGraph>> layoutAction =
|
MultiStateDockingAction<LayoutProvider<FcgVertex, FcgEdge, FunctionCallGraph>> layoutAction =
|
||||||
new MultiStateDockingAction<LayoutProvider<FcgVertex, FcgEdge, FunctionCallGraph>>(
|
new MultiStateDockingAction<>(
|
||||||
RELAYOUT_GRAPH_ACTION_NAME, plugin.getName()) {
|
RELAYOUT_GRAPH_ACTION_NAME, plugin.getName()) {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -627,7 +630,7 @@ public class FcgProvider
|
||||||
|
|
||||||
//==================================================================================================
|
//==================================================================================================
|
||||||
// Expand/Collapse Methods
|
// Expand/Collapse Methods
|
||||||
//==================================================================================================
|
//==================================================================================================
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Notes
|
* Notes
|
||||||
|
@ -660,8 +663,8 @@ public class FcgProvider
|
||||||
|
|
||||||
Set<FcgEdge> newEdges = getModelEdges(sources, expandingLevel, edgeNotInGraphFilter);
|
Set<FcgEdge> newEdges = getModelEdges(sources, expandingLevel, edgeNotInGraphFilter);
|
||||||
|
|
||||||
// Need all vertices from the source level, as well as their edges.
|
// Need all vertices from the source level, as well as their edges.
|
||||||
// This is used to correctly layout the vertices we are adding. This way, if we
|
// This is used to correctly layout the vertices we are adding. This way, if we
|
||||||
// later add the sibling vertices, they will be in the correct spot, without clipping.
|
// later add the sibling vertices, they will be in the correct spot, without clipping.
|
||||||
Iterable<FcgVertex> sourceSiblings = getVerticesByLevel(sourceLevel);
|
Iterable<FcgVertex> sourceSiblings = getVerticesByLevel(sourceLevel);
|
||||||
Set<FcgEdge> parentLevelEdges = getModelEdges(sourceSiblings, expandingLevel, unfiltered);
|
Set<FcgEdge> parentLevelEdges = getModelEdges(sourceSiblings, expandingLevel, unfiltered);
|
||||||
|
@ -756,7 +759,7 @@ public class FcgProvider
|
||||||
FcgLevel parentLevel = parent.getLevel();
|
FcgLevel parentLevel = parent.getLevel();
|
||||||
FcgLevel otherLevel = other.getLevel();
|
FcgLevel otherLevel = other.getLevel();
|
||||||
if (!parentLevel.isParentOf(otherLevel)) {
|
if (!parentLevel.isParentOf(otherLevel)) {
|
||||||
// the other vertex must be in the child level to be a dependent
|
// the other vertex must be in the child level to be a dependent
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -864,7 +867,7 @@ public class FcgProvider
|
||||||
}
|
}
|
||||||
|
|
||||||
private Set<FcgVertex> toStartVertices(Iterable<FcgEdge> edges, Predicate<FcgVertex> filter) {
|
private Set<FcgVertex> toStartVertices(Iterable<FcgEdge> edges, Predicate<FcgVertex> filter) {
|
||||||
//@formatter:off
|
//@formatter:off
|
||||||
return CollectionUtils
|
return CollectionUtils
|
||||||
.asStream(edges)
|
.asStream(edges)
|
||||||
.map(e -> e.getStart())
|
.map(e -> e.getStart())
|
||||||
|
@ -921,7 +924,7 @@ public class FcgProvider
|
||||||
currentLevel = currentLevel.child();
|
currentLevel = currentLevel.child();
|
||||||
}
|
}
|
||||||
|
|
||||||
// hand out from greatest to least so that we can close the extremities first
|
// hand out from greatest to least so that we can close the extremities first
|
||||||
Collections.reverse(result);
|
Collections.reverse(result);
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
|
@ -931,8 +934,8 @@ public class FcgProvider
|
||||||
|
|
||||||
private void doExpand(FcgExpandingVertexCollection collection) {
|
private void doExpand(FcgExpandingVertexCollection collection) {
|
||||||
|
|
||||||
// note: we must do this before adding edges, as that will also add vertices and
|
// note: we must do this before adding edges, as that will also add vertices and
|
||||||
// we will filter vertices later by those that are not already in the graph
|
// we will filter vertices later by those that are not already in the graph
|
||||||
|
|
||||||
Set<FcgVertex> newVertices = collection.getNewVertices();
|
Set<FcgVertex> newVertices = collection.getNewVertices();
|
||||||
FunctionCallGraph graph = graphData.getGraph();
|
FunctionCallGraph graph = graphData.getGraph();
|
||||||
|
@ -979,13 +982,13 @@ public class FcgProvider
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Called when new vertices are added to the graph to ensure that known edges between any
|
* Called when new vertices are added to the graph to ensure that known edges between any
|
||||||
* level of the graph get added as the associated vertices are added to the graph. This
|
* level of the graph get added as the associated vertices are added to the graph. This
|
||||||
* is needed because we don't add all known edges for a single vertex when it is added, as
|
* is needed because we don't add all known edges for a single vertex when it is added, as
|
||||||
* its associated vertex may not yet be in the graph. Calling this method ensures that as
|
* its associated vertex may not yet be in the graph. Calling this method ensures that as
|
||||||
* vertices appear, the edges are added.
|
* vertices appear, the edges are added.
|
||||||
*
|
*
|
||||||
* @param newVertices the vertices being added to the graph
|
* @param newVertices the vertices being added to the graph
|
||||||
* @param newEdges the set to which should be added any new edges being added to the graph
|
* @param newEdges the set to which should be added any new edges being added to the graph
|
||||||
*/
|
*/
|
||||||
private void addEdgesToExistingVertices(Iterable<FcgVertex> newVertices,
|
private void addEdgesToExistingVertices(Iterable<FcgVertex> newVertices,
|
||||||
Set<FcgEdge> newEdges) {
|
Set<FcgEdge> newEdges) {
|
||||||
|
@ -1018,7 +1021,7 @@ public class FcgProvider
|
||||||
|
|
||||||
//
|
//
|
||||||
// Unusual Code Alert
|
// Unusual Code Alert
|
||||||
// We wish to always use the same vertex *instance* across edges that we are
|
// We wish to always use the same vertex *instance* across edges that we are
|
||||||
// creating. If the vertex is already in the graph, then that will happen as we get it
|
// creating. If the vertex is already in the graph, then that will happen as we get it
|
||||||
// from the graph. However, if the function does not have a vertex in the graph, then
|
// from the graph. However, if the function does not have a vertex in the graph, then
|
||||||
// it must be created. Cache the vertices we retrieve here, whether exiting or created,
|
// it must be created. Cache the vertices we retrieve here, whether exiting or created,
|
||||||
|
@ -1026,7 +1029,7 @@ public class FcgProvider
|
||||||
//
|
//
|
||||||
|
|
||||||
//@formatter:off
|
//@formatter:off
|
||||||
return CollectionUtils.asStream(callees)
|
return CollectionUtils.asStream(callees)
|
||||||
.map(f -> {
|
.map(f -> {
|
||||||
|
|
||||||
if (newVertexCache.containsKey(f)) {
|
if (newVertexCache.containsKey(f)) {
|
||||||
|
|
|
@ -17,18 +17,21 @@ package functioncalls.plugin;
|
||||||
|
|
||||||
import docking.ActionContext;
|
import docking.ActionContext;
|
||||||
import docking.action.DockingAction;
|
import docking.action.DockingAction;
|
||||||
|
import docking.tool.ToolConstants;
|
||||||
import ghidra.app.CorePluginPackage;
|
import ghidra.app.CorePluginPackage;
|
||||||
import ghidra.app.plugin.PluginCategoryNames;
|
import ghidra.app.plugin.PluginCategoryNames;
|
||||||
import ghidra.app.plugin.ProgramPlugin;
|
import ghidra.app.plugin.ProgramPlugin;
|
||||||
import ghidra.app.services.GoToService;
|
import ghidra.app.services.GoToService;
|
||||||
import ghidra.framework.options.SaveState;
|
import ghidra.framework.options.*;
|
||||||
import ghidra.framework.plugintool.PluginInfo;
|
import ghidra.framework.plugintool.PluginInfo;
|
||||||
import ghidra.framework.plugintool.PluginTool;
|
import ghidra.framework.plugintool.PluginTool;
|
||||||
import ghidra.framework.plugintool.util.PluginStatus;
|
import ghidra.framework.plugintool.util.PluginStatus;
|
||||||
|
import ghidra.graph.viewer.options.VisualGraphOptions;
|
||||||
import ghidra.program.model.address.Address;
|
import ghidra.program.model.address.Address;
|
||||||
import ghidra.program.util.ProgramLocation;
|
import ghidra.program.util.ProgramLocation;
|
||||||
import ghidra.util.HelpLocation;
|
import ghidra.util.HelpLocation;
|
||||||
import ghidra.util.SystemUtilities;
|
import ghidra.util.SystemUtilities;
|
||||||
|
import ghidra.util.bean.opteditor.OptionsVetoException;
|
||||||
import ghidra.util.task.SwingUpdateManager;
|
import ghidra.util.task.SwingUpdateManager;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -43,7 +46,7 @@ import ghidra.util.task.SwingUpdateManager;
|
||||||
description = "Displays a graph of incoming and outgoing calls for a given function."
|
description = "Displays a graph of incoming and outgoing calls for a given function."
|
||||||
)
|
)
|
||||||
//@formatter:on
|
//@formatter:on
|
||||||
public class FunctionCallGraphPlugin extends ProgramPlugin {
|
public class FunctionCallGraphPlugin extends ProgramPlugin implements OptionsChangeListener {
|
||||||
|
|
||||||
/*package*/ static final String NAME = "Function Call Graph";
|
/*package*/ static final String NAME = "Function Call Graph";
|
||||||
/*package*/ static final String SHOW_PROVIDER_ACTION_NAME = "Display Function Call Graph";
|
/*package*/ static final String SHOW_PROVIDER_ACTION_NAME = "Display Function Call Graph";
|
||||||
|
@ -52,6 +55,7 @@ public class FunctionCallGraphPlugin extends ProgramPlugin {
|
||||||
FunctionCallGraphPlugin.class.getSimpleName());
|
FunctionCallGraphPlugin.class.getSimpleName());
|
||||||
|
|
||||||
private FcgProvider provider;
|
private FcgProvider provider;
|
||||||
|
private VisualGraphOptions vgOptions = new VisualGraphOptions();
|
||||||
|
|
||||||
// enough time for users to click around without the graph starting its work
|
// enough time for users to click around without the graph starting its work
|
||||||
private static final int MIN_UPDATE_DELAY = 750;
|
private static final int MIN_UPDATE_DELAY = 750;
|
||||||
|
@ -65,8 +69,32 @@ public class FunctionCallGraphPlugin extends ProgramPlugin {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void init() {
|
protected void init() {
|
||||||
|
|
||||||
provider = new FcgProvider(tool, this);
|
provider = new FcgProvider(tool, this);
|
||||||
createActions();
|
createActions();
|
||||||
|
|
||||||
|
initializeOptions();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void initializeOptions() {
|
||||||
|
ToolOptions options = tool.getOptions(ToolConstants.GRAPH_OPTIONS);
|
||||||
|
options.addOptionsChangeListener(this);
|
||||||
|
|
||||||
|
HelpLocation help = new HelpLocation(getName(), "Options");
|
||||||
|
|
||||||
|
Options callGraphOptions = options.getOptions(NAME);
|
||||||
|
vgOptions.registerOptions(callGraphOptions, help);
|
||||||
|
vgOptions.loadOptions(callGraphOptions);
|
||||||
|
provider.optionsChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void optionsChanged(ToolOptions options, String optionName, Object oldValue,
|
||||||
|
Object newValue) throws OptionsVetoException {
|
||||||
|
|
||||||
|
Options callGraphOptions = options.getOptions(NAME);
|
||||||
|
vgOptions.loadOptions(callGraphOptions);
|
||||||
|
provider.optionsChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -118,7 +146,7 @@ public class FunctionCallGraphPlugin extends ProgramPlugin {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// TODO create icon from scratch: bow-tie
|
// TODO create icon from scratch: bow-tie
|
||||||
// ImageIcon icon = ResourceManager.loadImage("images/applications-development.png");
|
// ImageIcon icon = ResourceManager.loadImage("images/applications-development.png");
|
||||||
// showProviderAction.setToolBarData(new ToolBarData(icon, "View"));
|
// showProviderAction.setToolBarData(new ToolBarData(icon, "View"));
|
||||||
tool.addAction(showProviderAction);
|
tool.addAction(showProviderAction);
|
||||||
|
@ -142,4 +170,8 @@ public class FunctionCallGraphPlugin extends ProgramPlugin {
|
||||||
ProgramLocation getCurrentLocation() {
|
ProgramLocation getCurrentLocation() {
|
||||||
return currentLocation;
|
return currentLocation;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
VisualGraphOptions getOptions() {
|
||||||
|
return vgOptions;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,9 +4,9 @@
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
* You may obtain a copy of the License at
|
* You may obtain a copy of the License at
|
||||||
*
|
*
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
*
|
*
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
@ -23,6 +23,7 @@ import docking.action.DockingAction;
|
||||||
import docking.action.ToggleDockingAction;
|
import docking.action.ToggleDockingAction;
|
||||||
import docking.action.builder.ActionBuilder;
|
import docking.action.builder.ActionBuilder;
|
||||||
import docking.action.builder.ToggleActionBuilder;
|
import docking.action.builder.ToggleActionBuilder;
|
||||||
|
import docking.tool.ToolConstants;
|
||||||
import ghidra.app.CorePluginPackage;
|
import ghidra.app.CorePluginPackage;
|
||||||
import ghidra.app.events.ProgramLocationPluginEvent;
|
import ghidra.app.events.ProgramLocationPluginEvent;
|
||||||
import ghidra.app.events.ProgramSelectionPluginEvent;
|
import ghidra.app.events.ProgramSelectionPluginEvent;
|
||||||
|
@ -69,11 +70,18 @@ import ghidra.util.task.TaskLauncher;
|
||||||
//@formatter:on
|
//@formatter:on
|
||||||
public class ProgramGraphPlugin extends ProgramPlugin
|
public class ProgramGraphPlugin extends ProgramPlugin
|
||||||
implements OptionsChangeListener, BlockModelServiceListener, GraphDisplayBrokerListener {
|
implements OptionsChangeListener, BlockModelServiceListener, GraphDisplayBrokerListener {
|
||||||
private static final String MAX_CODE_LINES_DISPLAYED = "Max Code Lines Displayed";
|
|
||||||
private static final String REUSE_GRAPH = "Reuse Graph";
|
private static final String PLUGIN_NAME = "Program Graph";
|
||||||
private static final String GRAPH_ENTRY_POINT_NEXUS = "Graph Entry Point Nexus";
|
|
||||||
private static final String FORCE_LOCATION_DISPLAY_OPTION = "Force Location Visible on Graph";
|
private static final String OPTIONS_PREFIX = PLUGIN_NAME + Options.DELIMITER;
|
||||||
private static final String MAX_DEPTH_OPTION = "Max Reference Depth";
|
private static final String MAX_CODE_LINES_DISPLAYED =
|
||||||
|
OPTIONS_PREFIX + "Max Code Lines Displayed";
|
||||||
|
private static final String REUSE_GRAPH = OPTIONS_PREFIX + "Reuse Graph";
|
||||||
|
private static final String GRAPH_ENTRY_POINT_NEXUS =
|
||||||
|
OPTIONS_PREFIX + "Graph Entry Point Nexus";
|
||||||
|
private static final String FORCE_LOCATION_DISPLAY_OPTION =
|
||||||
|
OPTIONS_PREFIX + "Force Location Visible on Graph";
|
||||||
|
private static final String MAX_DEPTH_OPTION = OPTIONS_PREFIX + "Max Reference Depth";
|
||||||
public static final String MENU_GRAPH = "&Graph";
|
public static final String MENU_GRAPH = "&Graph";
|
||||||
|
|
||||||
private BlockModelService blockModelService;
|
private BlockModelService blockModelService;
|
||||||
|
@ -102,23 +110,23 @@ public class ProgramGraphPlugin extends ProgramPlugin
|
||||||
|
|
||||||
private void intializeOptions() {
|
private void intializeOptions() {
|
||||||
HelpLocation help = new HelpLocation(getName(), "Graph_Option");
|
HelpLocation help = new HelpLocation(getName(), "Graph_Option");
|
||||||
ToolOptions options = tool.getOptions("Graph");
|
ToolOptions options = tool.getOptions(ToolConstants.GRAPH_OPTIONS);
|
||||||
|
|
||||||
options.registerOption(MAX_CODE_LINES_DISPLAYED, codeLimitPerBlock, help,
|
options.registerOption(MAX_CODE_LINES_DISPLAYED, codeLimitPerBlock, help,
|
||||||
"Specifies the maximum number of instructions to display in each graph " +
|
"Specifies the maximum number of instructions to display in each graph " +
|
||||||
"node in a Code Flow Graph.");
|
"node in a Code Flow Graph.");
|
||||||
|
|
||||||
options.registerOption(REUSE_GRAPH, false, help,
|
options.registerOption(REUSE_GRAPH, false, help,
|
||||||
"Determines whether the graph will reuse the active graph window when displaying graphs.");
|
"Determines whether the graph will reuse the active graph window when displaying " +
|
||||||
|
"graphs.");
|
||||||
|
|
||||||
options.registerOption(GRAPH_ENTRY_POINT_NEXUS, false, help,
|
options.registerOption(GRAPH_ENTRY_POINT_NEXUS, false, help,
|
||||||
"Add a dummy node at the root of the graph and adds dummy edges to each node that has " +
|
"Add a dummy node at the root of the graph and adds dummy edges to each node that " +
|
||||||
"no incoming edges.");
|
"has no incoming edges.");
|
||||||
|
|
||||||
options.registerOption(FORCE_LOCATION_DISPLAY_OPTION, false, help,
|
options.registerOption(FORCE_LOCATION_DISPLAY_OPTION, false, help,
|
||||||
"Specifies whether or not " +
|
"Specifies whether or not graph displays should force the visible graph to pan " +
|
||||||
"graph displays should force the visible graph to pan and/or scale to ensure that focused " +
|
"and/or scale to ensure that focused locations are visible.");
|
||||||
"locations are visible.");
|
|
||||||
options.registerOption(MAX_DEPTH_OPTION, 1, help,
|
options.registerOption(MAX_DEPTH_OPTION, 1, help,
|
||||||
"Specifies max depth of data references to graph (0 for no limit)");
|
"Specifies max depth of data references to graph (0 for no limit)");
|
||||||
|
|
||||||
|
|
|
@ -27,7 +27,7 @@ import ghidra.framework.options.ToolOptions;
|
||||||
import ghidra.framework.plugintool.ServiceProvider;
|
import ghidra.framework.plugintool.ServiceProvider;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Generic tool interface for managing {@link ComponentProvider}s and
|
* Generic tool interface for managing {@link ComponentProvider}s and
|
||||||
* {@link DockingActionIf actions}
|
* {@link DockingActionIf actions}
|
||||||
*/
|
*/
|
||||||
public interface Tool extends ServiceProvider {
|
public interface Tool extends ServiceProvider {
|
||||||
|
@ -74,7 +74,7 @@ public interface Tool extends ServiceProvider {
|
||||||
public void addComponentProvider(ComponentProvider componentProvider, boolean show);
|
public void addComponentProvider(ComponentProvider componentProvider, boolean show);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Removes the given ComponentProvider from the tool. When a provider has been removed
|
* Removes the given ComponentProvider from the tool. When a provider has been removed
|
||||||
* from the tool it is considered disposed and should not be reused.
|
* from the tool it is considered disposed and should not be reused.
|
||||||
*
|
*
|
||||||
* @param componentProvider the provider to remove from the tool
|
* @param componentProvider the provider to remove from the tool
|
||||||
|
@ -165,7 +165,7 @@ public interface Tool extends ServiceProvider {
|
||||||
* Return a set of all actions in the tool.
|
* Return a set of all actions in the tool.
|
||||||
*
|
*
|
||||||
* <p>Note: the result may contain conceptually duplicate actions, which is when multiple
|
* <p>Note: the result may contain conceptually duplicate actions, which is when multiple
|
||||||
* actions exist that share the same full name (the full name is the action name with the
|
* actions exist that share the same full name (the full name is the action name with the
|
||||||
* owner name, such as "My Action (MyPlugin)".
|
* owner name, such as "My Action (MyPlugin)".
|
||||||
*
|
*
|
||||||
* @return set of all actions
|
* @return set of all actions
|
||||||
|
@ -176,7 +176,7 @@ public interface Tool extends ServiceProvider {
|
||||||
* Returns all actions for the given owner
|
* Returns all actions for the given owner
|
||||||
*
|
*
|
||||||
* <p>Note: the result may contain conceptually duplicate actions, which is when multiple
|
* <p>Note: the result may contain conceptually duplicate actions, which is when multiple
|
||||||
* actions exist that share the same full name (the full name is the action name with the
|
* actions exist that share the same full name (the full name is the action name with the
|
||||||
* owner name, such as "My Action (MyPlugin)".
|
* owner name, such as "My Action (MyPlugin)".
|
||||||
*
|
*
|
||||||
* @param owner the action owner's name
|
* @param owner the action owner's name
|
||||||
|
@ -239,8 +239,8 @@ public interface Tool extends ServiceProvider {
|
||||||
public void updateTitle(ComponentProvider componentProvider);
|
public void updateTitle(ComponentProvider componentProvider);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Signals to the tool that the provider's context has changed. This lets toolbar and
|
* Signals to the tool that the provider's context has changed. This lets toolbar and
|
||||||
* menu actions update enablement based on current context.
|
* menu actions update enablement based on current context.
|
||||||
*
|
*
|
||||||
* <p>Pass <code>null</code> to signal that the entire tool's context has changed
|
* <p>Pass <code>null</code> to signal that the entire tool's context has changed
|
||||||
*
|
*
|
||||||
|
@ -290,7 +290,7 @@ public interface Tool extends ServiceProvider {
|
||||||
* Returns the class that manages actions for the tool.
|
* Returns the class that manages actions for the tool.
|
||||||
*
|
*
|
||||||
* <p>Most clients will not need to use this methods. Instead, actions should be added to
|
* <p>Most clients will not need to use this methods. Instead, actions should be added to
|
||||||
* the tool via {@link #addAction(DockingActionIf)} and
|
* the tool via {@link #addAction(DockingActionIf)} and
|
||||||
* {@link #addLocalAction(ComponentProvider, DockingActionIf)}.
|
* {@link #addLocalAction(ComponentProvider, DockingActionIf)}.
|
||||||
*
|
*
|
||||||
* @return the action manager
|
* @return the action manager
|
||||||
|
|
|
@ -92,17 +92,22 @@ public interface ToolConstants extends DockingToolConstants {
|
||||||
public static final String TOOL_OWNER = "Tool";
|
public static final String TOOL_OWNER = "Tool";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This is used when many actions wish to share a key binding.
|
* This is used when many actions wish to share a key binding.
|
||||||
*
|
*
|
||||||
* @see KeyBindingType#SHARED
|
* @see KeyBindingType#SHARED
|
||||||
*/
|
*/
|
||||||
public static final String SHARED_OWNER = "Shared";
|
public static final String SHARED_OWNER = "Shared";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Name of options for a tool
|
* Tool options name
|
||||||
*/
|
*/
|
||||||
public static final String TOOL_OPTIONS = "Tool";
|
public static final String TOOL_OPTIONS = "Tool";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Graph options name
|
||||||
|
*/
|
||||||
|
public static final String GRAPH_OPTIONS = "Graph";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Name of the help topic for "About" domain objects and Ghidra
|
* Name of the help topic for "About" domain objects and Ghidra
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -40,7 +40,7 @@ public interface Options {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns a unique id for option in this options with the given name. This will be the full
|
* Returns a unique id for option in this options with the given name. This will be the full
|
||||||
* path name to the root options object.
|
* path name to the root options object.
|
||||||
* @param optionName the name of the option for which to get an ID;
|
* @param optionName the name of the option for which to get an ID;
|
||||||
* @return the unique ID for the given option.
|
* @return the unique ID for the given option.
|
||||||
*/
|
*/
|
||||||
|
@ -56,6 +56,7 @@ public interface Options {
|
||||||
/**
|
/**
|
||||||
* Get the property editor for the option with the given name. Note: This method must be called
|
* Get the property editor for the option with the given name. Note: This method must be called
|
||||||
* from the swing thread.
|
* from the swing thread.
|
||||||
|
* @param optionName the option name
|
||||||
* @return either the PropertyEditor that was registered for this option or a default editor
|
* @return either the PropertyEditor that was registered for this option or a default editor
|
||||||
* for the property type if one can be found; otherwise null.
|
* for the property type if one can be found; otherwise null.
|
||||||
* @throws IllegalStateException if not called from the swing thread.
|
* @throws IllegalStateException if not called from the swing thread.
|
||||||
|
@ -65,6 +66,7 @@ public interface Options {
|
||||||
/**
|
/**
|
||||||
* Get the property editor that was registered for the specific option with the given name. Unlike
|
* Get the property editor that was registered for the specific option with the given name. Unlike
|
||||||
* the getPropertyEditor() method, this method does not have to be called from the swing thread
|
* the getPropertyEditor() method, this method does not have to be called from the swing thread
|
||||||
|
* @param optionName the option name
|
||||||
* @return the PropertyEditor that was registered for this option.
|
* @return the PropertyEditor that was registered for this option.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
@ -79,7 +81,7 @@ public interface Options {
|
||||||
/**
|
/**
|
||||||
* Returns a list of option names that immediately fall under this options. For example, if this options
|
* Returns a list of option names that immediately fall under this options. For example, if this options
|
||||||
* object had the following options named ("a", "b", "c.d"), only "a" and "b" would be returned. The
|
* object had the following options named ("a", "b", "c.d"), only "a" and "b" would be returned. The
|
||||||
* "c.d" leaf option name could be returned by getOptions("c").getLeafOptionNames()
|
* "c.d" leaf option name could be returned by getOptions("c").getLeafOptionNames()
|
||||||
* @return the list of the names of the options that are immediate children of this options object.
|
* @return the list of the names of the options that are immediate children of this options object.
|
||||||
*/
|
*/
|
||||||
public List<String> getLeafOptionNames();
|
public List<String> getLeafOptionNames();
|
||||||
|
@ -163,6 +165,8 @@ public interface Options {
|
||||||
/**
|
/**
|
||||||
* Put the object value. If the option exists, the type must match the type of the existing
|
* Put the object value. If the option exists, the type must match the type of the existing
|
||||||
* object.
|
* object.
|
||||||
|
* @param optionName the option name
|
||||||
|
* @param obj the option value
|
||||||
* @throws IllegalStateException if the object does not match the existing type of the option.
|
* @throws IllegalStateException if the object does not match the existing type of the option.
|
||||||
* @throws IllegalArgumentException if the object is null or not a supported type.
|
* @throws IllegalArgumentException if the object is null or not a supported type.
|
||||||
*/
|
*/
|
||||||
|
@ -268,7 +272,7 @@ public interface Options {
|
||||||
* @param pName the property name
|
* @param pName the property name
|
||||||
* @param date the default date that is stored and returned if there is no
|
* @param date the default date that is stored and returned if there is no
|
||||||
* option with the given name
|
* option with the given name
|
||||||
* @return the Date for the option
|
* @return the Date for the option
|
||||||
* @throws IllegalArgumentException is a option exists with the given
|
* @throws IllegalArgumentException is a option exists with the given
|
||||||
* name but it is not a Date options
|
* name but it is not a Date options
|
||||||
*/
|
*/
|
||||||
|
@ -352,21 +356,21 @@ public interface Options {
|
||||||
/**
|
/**
|
||||||
* Sets the Custom option value for the option.
|
* Sets the Custom option value for the option.
|
||||||
* @param optionName name of the option
|
* @param optionName name of the option
|
||||||
* @param value
|
* @param value the value
|
||||||
*/
|
*/
|
||||||
public abstract void setCustomOption(String optionName, CustomOption value);
|
public abstract void setCustomOption(String optionName, CustomOption value);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the byte[] value for the given option name.
|
* Sets the byte[] value for the given option name.
|
||||||
* @param optionName the name of the option on which to save bytes.
|
* @param optionName the name of the option on which to save bytes.
|
||||||
* @param value
|
* @param value the value
|
||||||
*/
|
*/
|
||||||
public abstract void setByteArray(String optionName, byte[] value);
|
public abstract void setByteArray(String optionName, byte[] value);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the File value for the option.
|
* Sets the File value for the option.
|
||||||
* @param optionName name of the option
|
* @param optionName name of the option
|
||||||
* @param value
|
* @param value the value
|
||||||
*/
|
*/
|
||||||
public abstract void setFile(String optionName, File value);
|
public abstract void setFile(String optionName, File value);
|
||||||
|
|
||||||
|
@ -426,7 +430,7 @@ public interface Options {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the list of option names. This method will return the names (paths) of all options contained
|
* Get the list of option names. This method will return the names (paths) of all options contained
|
||||||
* in this options object or below. For example, if the options has ("aaa", "bbb", "ccc.ddd"),
|
* in this options object or below. For example, if the options has ("aaa", "bbb", "ccc.ddd"),
|
||||||
* all three will be returned. the {@link Options#getLeafOptionNames()} method will return only
|
* all three will be returned. the {@link Options#getLeafOptionNames()} method will return only
|
||||||
* the "aaa" and "bbb" names.
|
* the "aaa" and "bbb" names.
|
||||||
* @return the list of all option names(paths) under this options.
|
* @return the list of all option names(paths) under this options.
|
||||||
|
@ -436,6 +440,7 @@ public interface Options {
|
||||||
/**
|
/**
|
||||||
* Return true if a option exists with the given name.
|
* Return true if a option exists with the given name.
|
||||||
* @param optionName option name
|
* @param optionName option name
|
||||||
|
* @return true if there exists an option with the given name
|
||||||
*/
|
*/
|
||||||
public abstract boolean contains(String optionName);
|
public abstract boolean contains(String optionName);
|
||||||
|
|
||||||
|
@ -449,6 +454,8 @@ public interface Options {
|
||||||
/**
|
/**
|
||||||
* Returns true if the specified option has been registered. Only registered names
|
* Returns true if the specified option has been registered. Only registered names
|
||||||
* are saved.
|
* are saved.
|
||||||
|
* @param optionName the option name
|
||||||
|
* @return true if registered
|
||||||
*/
|
*/
|
||||||
public abstract boolean isRegistered(String optionName);
|
public abstract boolean isRegistered(String optionName);
|
||||||
|
|
||||||
|
@ -476,14 +483,20 @@ public interface Options {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns a Options object that is a sub-options of this options.
|
* Returns a Options object that is a sub-options of this options.
|
||||||
* @param path the path for the sub-options object.
|
*
|
||||||
* @return a Options object that is a sub-options of this options.
|
* <p>Note: the option path can have {@link Options#DELIMITER} characters which will be
|
||||||
|
* used to create a hierarchy with each element in the path resulting in sub-option of the
|
||||||
|
* previous path element.
|
||||||
|
*
|
||||||
|
* @param path the path for the sub-options object
|
||||||
|
* @return an Options object that is a sub-options of this options
|
||||||
*/
|
*/
|
||||||
public Options getOptions(String path);
|
public Options getOptions(String path);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create an alias in this options for an existing option in some other options object.
|
* Create an alias in this options for an existing option in some other options object.
|
||||||
* @param aliasName the name within this options object that will acutally refer to some other options object.
|
* @param aliasName the name within this options object that will actually refer to some other
|
||||||
|
* options object.
|
||||||
* @param options the options object that has the actual option.
|
* @param options the options object that has the actual option.
|
||||||
* @param optionsName the name within the given options object of the actual option.
|
* @param optionsName the name within the given options object of the actual option.
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -32,13 +32,17 @@ import ghidra.util.exception.AssertException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Class to manage a set of option name/value pairs for a category.
|
* Class to manage a set of option name/value pairs for a category.
|
||||||
* The values may be primitives or
|
*
|
||||||
* WrappedObjects that are containers for its primitive components.
|
* <p>The values may be primitives or {@link WrappedOption}s that are containers for primitive
|
||||||
* The option may be associated with a particular group.
|
* components.
|
||||||
* <p> The name/value pair has a owner so that the option name
|
*
|
||||||
* can be removed from the Options object when it is no longer being used.
|
* <p>The name/value pair has an owner so that the option name can be removed from the Options
|
||||||
* <p>NOTE: Property Names can have DELIMITER characters to create a hierarchy.
|
* object when it is no longer being used.
|
||||||
* The Options Dialog shows the hierarchy in tree format.
|
*
|
||||||
|
* <p>Note: Property Names can have {@link Options#DELIMITER} characters to create a hierarchy.
|
||||||
|
* So too can sub-options accessed via {@link #getOptions(String)}.
|
||||||
|
*
|
||||||
|
* <p>The Options Dialog shows the delimited hierarchy in tree format.
|
||||||
*/
|
*/
|
||||||
public class ToolOptions extends AbstractOptions {
|
public class ToolOptions extends AbstractOptions {
|
||||||
private static final String CLASS_ATTRIBUTE = "CLASS";
|
private static final String CLASS_ATTRIBUTE = "CLASS";
|
||||||
|
@ -145,7 +149,7 @@ public class ToolOptions extends AbstractOptions {
|
||||||
* Note: only those options which have been explicitly set
|
* Note: only those options which have been explicitly set
|
||||||
* will be included.
|
* will be included.
|
||||||
*
|
*
|
||||||
* @param includeDefaultBindings true to include default key binding values in the xml
|
* @param includeDefaultBindings true to include default key binding values in the xml
|
||||||
* @return the xml root element
|
* @return the xml root element
|
||||||
*/
|
*/
|
||||||
public Element getXmlRoot(boolean includeDefaultBindings) {
|
public Element getXmlRoot(boolean includeDefaultBindings) {
|
||||||
|
@ -194,7 +198,7 @@ public class ToolOptions extends AbstractOptions {
|
||||||
SaveState ss = new SaveState(WRAPPED_OPTION_NAME);
|
SaveState ss = new SaveState(WRAPPED_OPTION_NAME);
|
||||||
Element elem = null;
|
Element elem = null;
|
||||||
if (value == null) {
|
if (value == null) {
|
||||||
// Handle the null case ourselves, not using the wrapped option (and when
|
// Handle the null case ourselves, not using the wrapped option (and when
|
||||||
// reading from xml) so that the logic does not need to in each wrapped option
|
// reading from xml) so that the logic does not need to in each wrapped option
|
||||||
elem = ss.saveToXml();
|
elem = ss.saveToXml();
|
||||||
elem.addContent(new Element(CLEARED_VALUE_ELEMENT_NAME));
|
elem.addContent(new Element(CLEARED_VALUE_ELEMENT_NAME));
|
||||||
|
|
|
@ -63,13 +63,13 @@ import resources.ResourceManager;
|
||||||
import util.CollectionUtils;
|
import util.CollectionUtils;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A component that contains primary and satellite graph views. This viewer provides
|
* A component that contains primary and satellite graph views. This viewer provides
|
||||||
* methods for manipulating the graph using the mouse.
|
* methods for manipulating the graph using the mouse.
|
||||||
*
|
*
|
||||||
* <p>To gain the full functionality offered by this class, clients will need to subclass
|
* <p>To gain the full functionality offered by this class, clients will need to subclass
|
||||||
* this class and override {@link #createPrimaryGraphViewer(VisualGraphLayout, Dimension)}
|
* this class and override {@link #createPrimaryGraphViewer(VisualGraphLayout, Dimension)}
|
||||||
* and {@link #createSatelliteGraphViewer(GraphViewer, Dimension)} as needed. This allows
|
* and {@link #createSatelliteGraphViewer(GraphViewer, Dimension)} as needed. This allows
|
||||||
* them to customize renderers and other viewer attributes. To use the subclass, see the
|
* them to customize renderers and other viewer attributes. To use the subclass, see the
|
||||||
* {@link VisualGraphView} and its <code>installGraphViewer()</code> method.
|
* {@link VisualGraphView} and its <code>installGraphViewer()</code> method.
|
||||||
*
|
*
|
||||||
* @param <V> the vertex type
|
* @param <V> the vertex type
|
||||||
|
@ -83,7 +83,7 @@ public class GraphComponent<V extends VisualVertex, E extends VisualEdge<V>, G e
|
||||||
private static final double PARENT_TO_SATELLITE_RATIO = 4;// 2.5 smaller view seems better
|
private static final double PARENT_TO_SATELLITE_RATIO = 4;// 2.5 smaller view seems better
|
||||||
private static final int MINIMUM_SATELLITE_WIDTH = 150;
|
private static final int MINIMUM_SATELLITE_WIDTH = 150;
|
||||||
|
|
||||||
// TODO this is arbitrary right now; perform testing for a generic number value;
|
// TODO this is arbitrary right now; perform testing for a generic number value;
|
||||||
// subclasses can override
|
// subclasses can override
|
||||||
private static final int REALLY_BIG_GRAPH_VERTEX_COUNT = 500;
|
private static final int REALLY_BIG_GRAPH_VERTEX_COUNT = 500;
|
||||||
|
|
||||||
|
@ -124,7 +124,7 @@ public class GraphComponent<V extends VisualVertex, E extends VisualEdge<V>, G e
|
||||||
// a cache to prevent unnecessary layout calculations
|
// a cache to prevent unnecessary layout calculations
|
||||||
private Dimension lastSize;
|
private Dimension lastSize;
|
||||||
|
|
||||||
protected VisualGraphOptions options = new VisualGraphOptions();
|
protected VisualGraphOptions vgOptions = new VisualGraphOptions();
|
||||||
|
|
||||||
public GraphComponent(G graph) {
|
public GraphComponent(G graph) {
|
||||||
|
|
||||||
|
@ -187,7 +187,7 @@ public class GraphComponent<V extends VisualVertex, E extends VisualEdge<V>, G e
|
||||||
//
|
//
|
||||||
// This method can be overridden by subclasses to perform custom creation and setup.
|
// This method can be overridden by subclasses to perform custom creation and setup.
|
||||||
// Any setup, like renderers, that this class should not override must be put in this
|
// Any setup, like renderers, that this class should not override must be put in this
|
||||||
// method so that subclasses can override. Common setup items should be in the
|
// method so that subclasses can override. Common setup items should be in the
|
||||||
// method that calls this one.
|
// method that calls this one.
|
||||||
//
|
//
|
||||||
|
|
||||||
|
@ -208,7 +208,7 @@ public class GraphComponent<V extends VisualVertex, E extends VisualEdge<V>, G e
|
||||||
renderContext.setVertexFillPaintTransformer(
|
renderContext.setVertexFillPaintTransformer(
|
||||||
new PickableVertexPaintTransformer<>(pickedVertexState, Color.WHITE, Color.YELLOW));
|
new PickableVertexPaintTransformer<>(pickedVertexState, Color.WHITE, Color.YELLOW));
|
||||||
|
|
||||||
viewer.setGraphOptions(options);
|
viewer.setGraphOptions(vgOptions);
|
||||||
|
|
||||||
return viewer;
|
return viewer;
|
||||||
}
|
}
|
||||||
|
@ -295,7 +295,7 @@ public class GraphComponent<V extends VisualVertex, E extends VisualEdge<V>, G e
|
||||||
|
|
||||||
SatelliteGraphViewer<V, E> viewer = createSatelliteGraphViewer(masterViewer, viewerSize);
|
SatelliteGraphViewer<V, E> viewer = createSatelliteGraphViewer(masterViewer, viewerSize);
|
||||||
|
|
||||||
viewer.setGraphOptions(options);
|
viewer.setGraphOptions(vgOptions);
|
||||||
|
|
||||||
viewer.setMinimumSize(viewerSize);
|
viewer.setMinimumSize(viewerSize);
|
||||||
viewer.setMaximumSize(viewerSize);
|
viewer.setMaximumSize(viewerSize);
|
||||||
|
@ -434,7 +434,7 @@ public class GraphComponent<V extends VisualVertex, E extends VisualEdge<V>, G e
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
||||||
TODO fix when the help module is created
|
TODO fix when the Generic Visual Graph help module is created
|
||||||
|
|
||||||
HelpService helpService = DockingWindowManager.getHelpService();
|
HelpService helpService = DockingWindowManager.getHelpService();
|
||||||
helpService.registerHelp(button,
|
helpService.registerHelp(button,
|
||||||
|
@ -506,7 +506,7 @@ public class GraphComponent<V extends VisualVertex, E extends VisualEdge<V>, G e
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This method is used to determine caching strategy. For example, large graph will
|
* This method is used to determine caching strategy. For example, large graph will
|
||||||
* trigger the us of a cached satellite view, for performance reasons.
|
* trigger the us of a cached satellite view, for performance reasons.
|
||||||
*
|
*
|
||||||
* @return true if the data is considered 'really big'
|
* @return true if the data is considered 'really big'
|
||||||
|
@ -524,7 +524,7 @@ public class GraphComponent<V extends VisualVertex, E extends VisualEdge<V>, G e
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setGraphOptions(VisualGraphOptions options) {
|
public void setGraphOptions(VisualGraphOptions options) {
|
||||||
this.options = options;
|
this.vgOptions = options;
|
||||||
|
|
||||||
// the viewers may be null if called during initialization
|
// the viewers may be null if called during initialization
|
||||||
if (primaryViewer != null) {
|
if (primaryViewer != null) {
|
||||||
|
@ -536,6 +536,10 @@ public class GraphComponent<V extends VisualVertex, E extends VisualEdge<V>, G e
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public VisualGraphOptions getGraphOptions() {
|
||||||
|
return vgOptions;
|
||||||
|
}
|
||||||
|
|
||||||
public boolean isUninitialized() {
|
public boolean isUninitialized() {
|
||||||
return isUninitialized;
|
return isUninitialized;
|
||||||
}
|
}
|
||||||
|
@ -592,7 +596,7 @@ public class GraphComponent<V extends VisualVertex, E extends VisualEdge<V>, G e
|
||||||
return primaryViewer.getViewUpdater();
|
return primaryViewer.getViewUpdater();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns an empty rectangle if the satellite is not visible
|
* Returns an empty rectangle if the satellite is not visible
|
||||||
* @return the bounds
|
* @return the bounds
|
||||||
*/
|
*/
|
||||||
|
@ -611,10 +615,10 @@ public class GraphComponent<V extends VisualVertex, E extends VisualEdge<V>, G e
|
||||||
applyGraphPerspective(graphPerspectiveInfo);
|
applyGraphPerspective(graphPerspectiveInfo);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
//
|
//
|
||||||
// Default Zoom - Zoomed-out or Zoomed-in?
|
// Default Zoom - Zoomed-out or Zoomed-in?
|
||||||
//
|
//
|
||||||
ViewRestoreOption viewOption = options.getViewRestoreOption();
|
ViewRestoreOption viewOption = vgOptions.getViewRestoreOption();
|
||||||
if (viewOption == ViewRestoreOption.START_FULLY_ZOOMED_IN) {
|
if (viewOption == ViewRestoreOption.START_FULLY_ZOOMED_IN) {
|
||||||
zoomInCompletely(getInitialVertex());
|
zoomInCompletely(getInitialVertex());
|
||||||
}
|
}
|
||||||
|
@ -883,7 +887,7 @@ public class GraphComponent<V extends VisualVertex, E extends VisualEdge<V>, G e
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
// Let's go a bit overboard and help the garbage collector cleanup by nulling out
|
// Let's go a bit overboard and help the garbage collector cleanup by nulling out
|
||||||
// references and removing the data from Jung's graph
|
// references and removing the data from Jung's graph
|
||||||
//
|
//
|
||||||
|
|
||||||
|
@ -1204,7 +1208,7 @@ public class GraphComponent<V extends VisualVertex, E extends VisualEdge<V>, G e
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void mouseClicked(MouseEvent e) {
|
public void mouseClicked(MouseEvent e) {
|
||||||
// stub
|
// stub
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -1214,7 +1218,7 @@ public class GraphComponent<V extends VisualVertex, E extends VisualEdge<V>, G e
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void mouseEntered(MouseEvent e) {
|
public void mouseEntered(MouseEvent e) {
|
||||||
// stub
|
// stub
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -66,7 +66,7 @@ public class GraphViewer<V extends VisualVertex, E extends VisualEdge<V>>
|
||||||
private PopupRegulator<V, E> popupRegulator;
|
private PopupRegulator<V, E> popupRegulator;
|
||||||
private VertexTooltipProvider<V, E> vertexTooltipProvider = new DummyTooltipProvider();
|
private VertexTooltipProvider<V, E> vertexTooltipProvider = new DummyTooltipProvider();
|
||||||
|
|
||||||
protected VisualGraphOptions options;
|
protected VisualGraphOptions vgOptions;
|
||||||
|
|
||||||
private VisualGraphViewUpdater<V, E> viewUpdater;
|
private VisualGraphViewUpdater<V, E> viewUpdater;
|
||||||
private VisualGraphPathHighlighter<V, E> pathHighlighter;
|
private VisualGraphPathHighlighter<V, E> pathHighlighter;
|
||||||
|
@ -157,16 +157,16 @@ public class GraphViewer<V extends VisualVertex, E extends VisualEdge<V>>
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setGraphOptions(VisualGraphOptions options) {
|
public void setGraphOptions(VisualGraphOptions options) {
|
||||||
this.options = options;
|
this.vgOptions = options;
|
||||||
optionsChanged();
|
optionsChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void optionsChanged() {
|
public void optionsChanged() {
|
||||||
setBackground(options.getGraphBackgroundColor());
|
setBackground(vgOptions.getGraphBackgroundColor());
|
||||||
}
|
}
|
||||||
|
|
||||||
public VisualGraphOptions getOptions() {
|
public VisualGraphOptions getOptions() {
|
||||||
return options;
|
return vgOptions;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setVertexHoverPathHighlightMode(PathHighlightMode hoverMode) {
|
public void setVertexHoverPathHighlightMode(PathHighlightMode hoverMode) {
|
||||||
|
@ -221,7 +221,7 @@ public class GraphViewer<V extends VisualVertex, E extends VisualEdge<V>>
|
||||||
* @return true if using mouse-relative zoom
|
* @return true if using mouse-relative zoom
|
||||||
*/
|
*/
|
||||||
public boolean useMouseRelativeZoom() {
|
public boolean useMouseRelativeZoom() {
|
||||||
return options.useMouseRelativeZoom();
|
return vgOptions.useMouseRelativeZoom();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -18,6 +18,8 @@ package ghidra.graph.viewer.options;
|
||||||
import java.awt.Color;
|
import java.awt.Color;
|
||||||
|
|
||||||
import docking.DockingUtils;
|
import docking.DockingUtils;
|
||||||
|
import ghidra.framework.options.Options;
|
||||||
|
import ghidra.util.HelpLocation;
|
||||||
|
|
||||||
public class VisualGraphOptions {
|
public class VisualGraphOptions {
|
||||||
|
|
||||||
|
@ -96,4 +98,41 @@ public class VisualGraphOptions {
|
||||||
return useCondensedLayout;
|
return useCondensedLayout;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void registerOptions(Options options, HelpLocation help) {
|
||||||
|
|
||||||
|
options.setOptionsHelpLocation(help);
|
||||||
|
|
||||||
|
options.registerOption(SHOW_ANIMATION_OPTIONS_KEY, useAnimation(), help,
|
||||||
|
SHOW_ANIMATION_DESCRIPTION);
|
||||||
|
|
||||||
|
options.registerOption(USE_MOUSE_RELATIVE_ZOOM_KEY, useMouseRelativeZoom(), help,
|
||||||
|
USE_MOUSE_RELATIVE_ZOOM_DESCRIPTION);
|
||||||
|
|
||||||
|
options.registerOption(VIEW_RESTORE_OPTIONS_KEY, ViewRestoreOption.START_FULLY_ZOOMED_OUT,
|
||||||
|
help, VIEW_RESTORE_OPTIONS_DESCRIPTION);
|
||||||
|
|
||||||
|
options.registerOption(SCROLL_WHEEL_PANS_KEY, getScrollWheelPans(), help,
|
||||||
|
SCROLL_WHEEL_PANS_DESCRIPTION);
|
||||||
|
|
||||||
|
options.registerOption(GRAPH_BACKGROUND_COLOR_KEY, DEFAULT_GRAPH_BACKGROUND_COLOR, help,
|
||||||
|
GRAPH_BACKGROUND_COLOR_DESCRPTION);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void loadOptions(Options options) {
|
||||||
|
|
||||||
|
useAnimation = options.getBoolean(SHOW_ANIMATION_OPTIONS_KEY, useAnimation);
|
||||||
|
|
||||||
|
useMouseRelativeZoom =
|
||||||
|
options.getBoolean(USE_MOUSE_RELATIVE_ZOOM_KEY, useMouseRelativeZoom);
|
||||||
|
|
||||||
|
useCondensedLayout = options.getBoolean(USE_CONDENSED_LAYOUT_KEY, useCondensedLayout);
|
||||||
|
|
||||||
|
viewRestoreOption =
|
||||||
|
options.getEnum(VIEW_RESTORE_OPTIONS_KEY, ViewRestoreOption.START_FULLY_ZOOMED_OUT);
|
||||||
|
|
||||||
|
scrollWheelPans = options.getBoolean(SCROLL_WHEEL_PANS_KEY, scrollWheelPans);
|
||||||
|
|
||||||
|
graphBackgroundColor =
|
||||||
|
options.getColor(GRAPH_BACKGROUND_COLOR_KEY, DEFAULT_GRAPH_BACKGROUND_COLOR);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -60,12 +60,12 @@ import ghidra.util.*;
|
||||||
import ghidra.util.task.*;
|
import ghidra.util.task.*;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Base class that is a container to manage plugins and their actions, and to coordinate the
|
* Base class that is a container to manage plugins and their actions, and to coordinate the
|
||||||
* firing of plugin events and tool events. A PluginTool may have visible components supplied by
|
* firing of plugin events and tool events. A PluginTool may have visible components supplied by
|
||||||
* <pre>ComponentProviders </pre>. These components may be docked within the tool, or moved
|
* <pre>ComponentProviders </pre>. These components may be docked within the tool, or moved
|
||||||
* out into their own windows.
|
* out into their own windows.
|
||||||
*
|
*
|
||||||
* <p>Plugins normally add actions via {@link #addAction(DockingActionIf)}. There is also
|
* <p>Plugins normally add actions via {@link #addAction(DockingActionIf)}. There is also
|
||||||
* an alternate method for getting actions to appear in the popup context menu (see
|
* an alternate method for getting actions to appear in the popup context menu (see
|
||||||
* {@link #addPopupActionProvider(PopupActionProvider)}). The popup listener mechanism is generally not
|
* {@link #addPopupActionProvider(PopupActionProvider)}). The popup listener mechanism is generally not
|
||||||
* needed and should only be used in special circumstances (see {@link PopupActionProvider}).
|
* needed and should only be used in special circumstances (see {@link PopupActionProvider}).
|
||||||
|
@ -710,11 +710,6 @@ public abstract class PluginTool extends AbstractDockingTool {
|
||||||
new TaskLauncher(task, winMgr.getActiveWindow());
|
new TaskLauncher(task, winMgr.getActiveWindow());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the options for the given category name; if no options exist with
|
|
||||||
* the given name, then one is created.
|
|
||||||
*/
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ToolOptions getOptions(String categoryName) {
|
public ToolOptions getOptions(String categoryName) {
|
||||||
return optionsMgr.getOptions(categoryName);
|
return optionsMgr.getOptions(categoryName);
|
||||||
|
@ -1103,7 +1098,7 @@ public abstract class PluginTool extends AbstractDockingTool {
|
||||||
return configChangedFlag; // ignore the window layout changes
|
return configChangedFlag; // ignore the window layout changes
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Called when it is time to save the tool. Handles auto-saving logic.
|
* Called when it is time to save the tool. Handles auto-saving logic.
|
||||||
* @return true if a save happened
|
* @return true if a save happened
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -58,12 +58,9 @@ public class OptionsManager implements OptionsService, OptionsChangeListener {
|
||||||
optionsMap.values().forEach(options -> options.dispose());
|
optionsMap.values().forEach(options -> options.dispose());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the options for the given category name.
|
|
||||||
* @param category name of category
|
|
||||||
*/
|
|
||||||
@Override
|
@Override
|
||||||
public ToolOptions getOptions(String category) {
|
public ToolOptions getOptions(String category) {
|
||||||
|
|
||||||
ToolOptions opt = optionsMap.get(category);
|
ToolOptions opt = optionsMap.get(category);
|
||||||
if (opt == null) {
|
if (opt == null) {
|
||||||
opt = new ToolOptions(category);
|
opt = new ToolOptions(category);
|
||||||
|
@ -87,20 +84,11 @@ public class OptionsManager implements OptionsService, OptionsChangeListener {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Return whether an Options object exists for the given category.
|
|
||||||
* @param category name of the category
|
|
||||||
* @return true if an Options object exists
|
|
||||||
*/
|
|
||||||
@Override
|
@Override
|
||||||
public boolean hasOptions(String category) {
|
public boolean hasOptions(String category) {
|
||||||
return optionsMap.containsKey(category);
|
return optionsMap.containsKey(category);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Shows Options Dialog with the section called 'category' being displayed
|
|
||||||
* @param category The category of options to have displayed
|
|
||||||
*/
|
|
||||||
@Override
|
@Override
|
||||||
public void showOptionsDialog(String category, String filterText) {
|
public void showOptionsDialog(String category, String filterText) {
|
||||||
if (optionsDialog != null && optionsDialog.isVisible()) {
|
if (optionsDialog != null && optionsDialog.isVisible()) {
|
||||||
|
@ -112,9 +100,6 @@ public class OptionsManager implements OptionsService, OptionsChangeListener {
|
||||||
tool.showDialog(optionsDialog);
|
tool.showDialog(optionsDialog);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the list of options for all categories.
|
|
||||||
*/
|
|
||||||
@Override
|
@Override
|
||||||
public ToolOptions[] getOptions() {
|
public ToolOptions[] getOptions() {
|
||||||
ToolOptions[] opt = new ToolOptions[optionsMap.size()];
|
ToolOptions[] opt = new ToolOptions[optionsMap.size()];
|
||||||
|
@ -134,7 +119,6 @@ public class OptionsManager implements OptionsService, OptionsChangeListener {
|
||||||
* remove the options from the map.
|
* remove the options from the map.
|
||||||
* @param ownerPlugin the owner plugin
|
* @param ownerPlugin the owner plugin
|
||||||
*/
|
*/
|
||||||
//TODO anyone using this Or should they be?
|
|
||||||
public void deregisterOwner(Plugin ownerPlugin) {
|
public void deregisterOwner(Plugin ownerPlugin) {
|
||||||
List<String> deleteList = new ArrayList<>();
|
List<String> deleteList = new ArrayList<>();
|
||||||
Iterator<String> iter = optionsMap.keySet().iterator();
|
Iterator<String> iter = optionsMap.keySet().iterator();
|
||||||
|
@ -211,9 +195,6 @@ public class OptionsManager implements OptionsService, OptionsChangeListener {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Show the dialog to edit options.
|
|
||||||
*/
|
|
||||||
public void editOptions() {
|
public void editOptions() {
|
||||||
if (optionsMap.isEmpty()) {
|
if (optionsMap.isEmpty()) {
|
||||||
Msg.showInfo(getClass(), tool.getToolFrame(), "No Options",
|
Msg.showInfo(getClass(), tool.getToolFrame(), "No Options",
|
||||||
|
@ -234,9 +215,6 @@ public class OptionsManager implements OptionsService, OptionsChangeListener {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Create the options dialog.
|
|
||||||
*/
|
|
||||||
private OptionsDialog createOptionsDialog() {
|
private OptionsDialog createOptionsDialog() {
|
||||||
OptionsDialog dialog = null;
|
OptionsDialog dialog = null;
|
||||||
if (optionsMap.size() == 0) {
|
if (optionsMap.size() == 0) {
|
||||||
|
@ -275,37 +253,20 @@ public class OptionsManager implements OptionsService, OptionsChangeListener {
|
||||||
}
|
}
|
||||||
|
|
||||||
private class OptionsComparator implements Comparator<ToolOptions> {
|
private class OptionsComparator implements Comparator<ToolOptions> {
|
||||||
/**
|
|
||||||
* Compares its two arguments for order. Returns a negative integer,
|
|
||||||
* zero, or a positive integer as the first argument is less than, equal
|
|
||||||
* to, or greater than the second.<p>
|
|
||||||
*
|
|
||||||
* @param o1 the first object to be compared.
|
|
||||||
* @param o2 the second object to be compared.
|
|
||||||
* @return a negative integer, zero, or a positive integer as the
|
|
||||||
* first argument is less than, equal to, or greater than the
|
|
||||||
* second.
|
|
||||||
* @throws ClassCastException if the arguments' types prevent them from
|
|
||||||
* being compared by this Comparator.
|
|
||||||
*/
|
|
||||||
@Override
|
@Override
|
||||||
public int compare(ToolOptions o1, ToolOptions o2) {
|
public int compare(ToolOptions o1, ToolOptions o2) {
|
||||||
return o1.getName().compareTo(o2.getName());
|
return o1.getName().compareTo(o2.getName());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/////////////////////////////////////////////////////////////////////
|
|
||||||
private class KeyBindingOptionsEditor implements OptionsEditor {
|
private class KeyBindingOptionsEditor implements OptionsEditor {
|
||||||
|
|
||||||
private KeyBindingsPanel panel;
|
private KeyBindingsPanel panel;
|
||||||
|
|
||||||
KeyBindingOptionsEditor() {
|
KeyBindingOptionsEditor() {
|
||||||
panel = new KeyBindingsPanel(tool, getOptions(ToolConstants.KEY_BINDINGS));
|
panel = new KeyBindingsPanel(tool, getOptions(DockingToolConstants.KEY_BINDINGS));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Apply the changes.
|
|
||||||
*/
|
|
||||||
@Override
|
@Override
|
||||||
public void apply() {
|
public void apply() {
|
||||||
panel.apply();
|
panel.apply();
|
||||||
|
@ -326,9 +287,6 @@ public class OptionsManager implements OptionsService, OptionsChangeListener {
|
||||||
panel.dispose();
|
panel.dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the editor component.
|
|
||||||
*/
|
|
||||||
@Override
|
@Override
|
||||||
public JComponent getEditorComponent(Options options,
|
public JComponent getEditorComponent(Options options,
|
||||||
EditorStateFactory editorStateFactory) {
|
EditorStateFactory editorStateFactory) {
|
||||||
|
@ -339,12 +297,10 @@ public class OptionsManager implements OptionsService, OptionsChangeListener {
|
||||||
public void setOptionsPropertyChangeListener(PropertyChangeListener listener) {
|
public void setOptionsPropertyChangeListener(PropertyChangeListener listener) {
|
||||||
panel.setOptionsPropertyChangeListener(listener);
|
panel.setOptionsPropertyChangeListener(listener);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void optionsChanged(ToolOptions options, String name, Object oldValue, Object newValue) {
|
public void optionsChanged(ToolOptions options, String name, Object oldValue, Object newValue) {
|
||||||
tool.setConfigChanged(true);
|
tool.setConfigChanged(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,53 +19,59 @@ import ghidra.framework.options.Options;
|
||||||
import ghidra.framework.options.ToolOptions;
|
import ghidra.framework.options.ToolOptions;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Provides a service interface that allows the user to get Options and to check for the
|
* Provides a service interface that allows the user to get Options and to check for the
|
||||||
* existence of options.
|
* existence of options.
|
||||||
*/
|
*/
|
||||||
public interface OptionsService {
|
public interface OptionsService {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the list of options for all categories.
|
* Get the list of options for all categories.
|
||||||
* @return the list of options for all categories.
|
* @return the list of options for all categories.
|
||||||
*/
|
*/
|
||||||
public Options[] getOptions();
|
public Options[] getOptions();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the options for the given category name.
|
* Get the options for the given category name. If no options exist with the given name,
|
||||||
* @param category name of category
|
* then a new options object is created.
|
||||||
* @return the options for the given category name.
|
*
|
||||||
*/
|
* <p>Note: the given name should not contains options path separator characters. Any
|
||||||
public ToolOptions getOptions(String category);
|
* sub-options needed must be retrieved from the ToolOptions object returned from this
|
||||||
|
* method.
|
||||||
/**
|
*
|
||||||
* Return whether an Options object exists for the given category.
|
* @param category name of category
|
||||||
* @param category name of the category
|
* @return the options for the given category name.
|
||||||
* @return true if an Options object exists
|
*/
|
||||||
*/
|
public ToolOptions getOptions(String category);
|
||||||
public boolean hasOptions(String category);
|
|
||||||
|
/**
|
||||||
/**
|
* Return whether an Options object exists for the given category.
|
||||||
* Shows Options Dialog with the node denoted by "category" being displayed. The value is
|
* @param category name of the category
|
||||||
* expected to be the name of a node in the options tree, residing under the root node. You
|
* @return true if an Options object exists
|
||||||
* may also provide the name of such a node, followed by the options delimiter, followed by
|
*/
|
||||||
* the name of a child node under that node. For example, suppose in the options tree exists
|
public boolean hasOptions(String category);
|
||||||
* a node {@literal Root->Foo} You may pass the value "Foo" to get that node. Or, suppose
|
|
||||||
* in the options tree exists a node {@literal Root->Foo->childNode1} In this case, you may
|
/**
|
||||||
* pass the value "Foo.childNode1", where the '.' character is the delimiter of the
|
* Shows Options Dialog with the node denoted by "category" being displayed. The value is
|
||||||
* {@link ToolOptions} class (this is the value at the time of writing this documentation).
|
* expected to be the name of a node in the options tree, residing under the root node. You
|
||||||
*
|
* may also provide the name of such a node, followed by the options delimiter, followed by
|
||||||
* <p>
|
* the name of a child node under that node. For example, suppose in the options tree exists
|
||||||
* The filter text parameter is used to set the contents filter text of the options. You may
|
* a node {@literal Root->Foo} You may pass the value "Foo" to get that node. Or, suppose
|
||||||
* use this parameter to filter the tree; for example, to show only the node in the tree that
|
* in the options tree exists a node {@literal Root->Foo->childNode1} In this case, you may
|
||||||
* you want the user to see.
|
* pass the value "Foo.childNode1", where the '.' character is the delimiter of the
|
||||||
*
|
* {@link ToolOptions} class (this is the value at the time of writing this documentation).
|
||||||
* @param category The category of options to have displayed
|
*
|
||||||
* @param filterText An optional value used to filter the nodes visible in the options tree.
|
* <p>
|
||||||
* You may pass <code>null</code> or the empty string <code>""</code> here if you
|
* The filter text parameter is used to set the contents filter text of the options. You may
|
||||||
* do not desire filtering.
|
* use this parameter to filter the tree; for example, to show only the node in the tree that
|
||||||
* @throws IllegalArgumentException if the given <code>category</code> value does not exist in
|
* you want the user to see.
|
||||||
* the tree of options.
|
*
|
||||||
*/
|
* @param category The category of options to have displayed
|
||||||
public void showOptionsDialog(String category, String filterText);
|
* @param filterText An optional value used to filter the nodes visible in the options tree.
|
||||||
|
* You may pass <code>null</code> or the empty string <code>""</code> here if you
|
||||||
|
* do not desire filtering.
|
||||||
|
* @throws IllegalArgumentException if the given <code>category</code> value does not exist in
|
||||||
|
* the tree of options.
|
||||||
|
*/
|
||||||
|
public void showOptionsDialog(String category, String filterText);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue