mirror of
https://github.com/NationalSecurityAgency/ghidra
synced 2024-09-13 21:56:19 +00:00
GT-2869 - Key Bindings - refactor of methods to provide all actions
This commit is contained in:
parent
c1de98304a
commit
43fa7e3f92
|
@ -20,6 +20,7 @@ import java.io.*;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
|
||||||
import docking.action.DockingActionIf;
|
import docking.action.DockingActionIf;
|
||||||
|
import docking.actions.KeyBindingUtils;
|
||||||
import ghidra.app.script.GhidraScript;
|
import ghidra.app.script.GhidraScript;
|
||||||
import ghidra.framework.plugintool.Plugin;
|
import ghidra.framework.plugintool.Plugin;
|
||||||
import ghidra.framework.plugintool.PluginTool;
|
import ghidra.framework.plugintool.PluginTool;
|
||||||
|
@ -30,9 +31,9 @@ public class CreateHelpTemplateScript extends GhidraScript {
|
||||||
@Override
|
@Override
|
||||||
protected void run() throws Exception {
|
protected void run() throws Exception {
|
||||||
PluginTool tool = state.getTool();
|
PluginTool tool = state.getTool();
|
||||||
Plugin[] plugins = getSortedPlugins(tool);
|
List<Plugin> plugins = getSortedPlugins(tool);
|
||||||
Plugin selectedPlugin =
|
Plugin selectedPlugin =
|
||||||
askChoice("Select Plugin To Use To Generate Help", "Plugin", plugins, plugins[0]);
|
askChoice("Select Plugin To Use To Generate Help", "Plugin", plugins, plugins.get(0));
|
||||||
if (selectedPlugin == null) {
|
if (selectedPlugin == null) {
|
||||||
printerr("no plugin selected, no help template created.");
|
printerr("no plugin selected, no help template created.");
|
||||||
return;
|
return;
|
||||||
|
@ -101,7 +102,8 @@ public class CreateHelpTemplateScript extends GhidraScript {
|
||||||
}
|
}
|
||||||
|
|
||||||
private List<DockingActionIf> getActions(PluginTool tool, Plugin plugin) {
|
private List<DockingActionIf> getActions(PluginTool tool, Plugin plugin) {
|
||||||
List<DockingActionIf> actions = tool.getDockingActionsByOwnerName(plugin.getName());
|
Set<DockingActionIf> actions = KeyBindingUtils.getKeyBindingActions(tool, plugin.getName());
|
||||||
|
List<DockingActionIf> list = new ArrayList<>(actions);
|
||||||
Comparator<DockingActionIf> comparator = (action1, action2) -> {
|
Comparator<DockingActionIf> comparator = (action1, action2) -> {
|
||||||
try {
|
try {
|
||||||
return action1.getName().compareTo(action2.getName());
|
return action1.getName().compareTo(action2.getName());
|
||||||
|
@ -110,14 +112,12 @@ public class CreateHelpTemplateScript extends GhidraScript {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
Collections.sort(actions, comparator);
|
Collections.sort(list, comparator);
|
||||||
return actions;
|
return list;
|
||||||
}
|
}
|
||||||
|
|
||||||
private Plugin[] getSortedPlugins(PluginTool tool) {
|
private List<Plugin> getSortedPlugins(PluginTool tool) {
|
||||||
List<Plugin> list = tool.getManagedPlugins();
|
List<Plugin> list = tool.getManagedPlugins();
|
||||||
Plugin[] plugins = new Plugin[list.size()];
|
|
||||||
list.toArray(plugins);
|
|
||||||
Comparator<Plugin> comparator = (plugin1, plugin2) -> {
|
Comparator<Plugin> comparator = (plugin1, plugin2) -> {
|
||||||
try {
|
try {
|
||||||
return plugin1.getName().compareTo(plugin2.getName());
|
return plugin1.getName().compareTo(plugin2.getName());
|
||||||
|
@ -126,8 +126,9 @@ public class CreateHelpTemplateScript extends GhidraScript {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
Arrays.sort(plugins, comparator);
|
|
||||||
return plugins;
|
Collections.sort(list, comparator);
|
||||||
|
return list;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,9 +21,7 @@ import java.awt.datatransfer.Transferable;
|
||||||
import java.awt.dnd.*;
|
import java.awt.dnd.*;
|
||||||
import java.awt.event.*;
|
import java.awt.event.*;
|
||||||
import java.math.BigInteger;
|
import java.math.BigInteger;
|
||||||
import java.util.Arrays;
|
import java.util.*;
|
||||||
import java.util.EventObject;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import javax.swing.*;
|
import javax.swing.*;
|
||||||
import javax.swing.border.Border;
|
import javax.swing.border.Border;
|
||||||
|
@ -33,10 +31,10 @@ import javax.swing.table.*;
|
||||||
import javax.swing.text.JTextComponent;
|
import javax.swing.text.JTextComponent;
|
||||||
|
|
||||||
import docking.action.DockingActionIf;
|
import docking.action.DockingActionIf;
|
||||||
|
import docking.actions.KeyBindingUtils;
|
||||||
import docking.dnd.*;
|
import docking.dnd.*;
|
||||||
import docking.help.Help;
|
import docking.help.Help;
|
||||||
import docking.help.HelpService;
|
import docking.help.HelpService;
|
||||||
import docking.util.KeyBindingUtils;
|
|
||||||
import docking.widgets.DropDownSelectionTextField;
|
import docking.widgets.DropDownSelectionTextField;
|
||||||
import docking.widgets.OptionDialog;
|
import docking.widgets.OptionDialog;
|
||||||
import docking.widgets.fieldpanel.support.FieldRange;
|
import docking.widgets.fieldpanel.support.FieldRange;
|
||||||
|
@ -1519,17 +1517,18 @@ public abstract class CompositeEditorPanel extends JPanel
|
||||||
@Override
|
@Override
|
||||||
public boolean isKeyConsumed(KeyStroke keyStroke) {
|
public boolean isKeyConsumed(KeyStroke keyStroke) {
|
||||||
if (isEditing()) {
|
if (isEditing()) {
|
||||||
|
// don't let actions through when editing our table
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// don't let actions through when editing our table
|
// TODO this should no longer be needed
|
||||||
return !hasLocalActionForKeyStroke(keyStroke);
|
return !hasLocalActionForKeyStroke(keyStroke);
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean hasLocalActionForKeyStroke(KeyStroke keyStroke) {
|
private boolean hasLocalActionForKeyStroke(KeyStroke keyStroke) {
|
||||||
Plugin plugin = provider.getPlugin();
|
Plugin plugin = provider.getPlugin();
|
||||||
PluginTool tool = plugin.getTool();
|
PluginTool tool = plugin.getTool();
|
||||||
List<DockingActionIf> actions = tool.getDockingActionsByOwnerName(plugin.getName());
|
Set<DockingActionIf> actions = tool.getDockingActionsByOwnerName(plugin.getName());
|
||||||
for (DockingActionIf action : actions) {
|
for (DockingActionIf action : actions) {
|
||||||
if (!(action instanceof CompositeEditorTableAction)) {
|
if (!(action instanceof CompositeEditorTableAction)) {
|
||||||
continue;
|
continue;
|
||||||
|
|
|
@ -32,8 +32,8 @@ import javax.swing.undo.UndoableEdit;
|
||||||
import docking.ActionContext;
|
import docking.ActionContext;
|
||||||
import docking.ComponentProvider;
|
import docking.ComponentProvider;
|
||||||
import docking.action.*;
|
import docking.action.*;
|
||||||
|
import docking.actions.KeyBindingUtils;
|
||||||
import docking.options.editor.FontPropertyEditor;
|
import docking.options.editor.FontPropertyEditor;
|
||||||
import docking.util.KeyBindingUtils;
|
|
||||||
import docking.widgets.OptionDialog;
|
import docking.widgets.OptionDialog;
|
||||||
import docking.widgets.filechooser.GhidraFileChooser;
|
import docking.widgets.filechooser.GhidraFileChooser;
|
||||||
import ghidra.framework.options.SaveState;
|
import ghidra.framework.options.SaveState;
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
/* ###
|
/* ###
|
||||||
* IP: GHIDRA
|
* IP: GHIDRA
|
||||||
* REVIEWED: YES
|
|
||||||
*
|
*
|
||||||
* 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.
|
||||||
|
@ -28,7 +27,7 @@ import javax.swing.*;
|
||||||
import javax.swing.event.*;
|
import javax.swing.event.*;
|
||||||
import javax.swing.text.*;
|
import javax.swing.text.*;
|
||||||
|
|
||||||
import docking.util.KeyBindingUtils;
|
import docking.actions.KeyBindingUtils;
|
||||||
|
|
||||||
class FunctionSignatureTextField extends JTextPane {
|
class FunctionSignatureTextField extends JTextPane {
|
||||||
private static final String ENTER_ACTION_NAME = "ENTER";
|
private static final String ENTER_ACTION_NAME = "ENTER";
|
||||||
|
|
|
@ -24,7 +24,7 @@ import java.util.Map.Entry;
|
||||||
import javax.swing.*;
|
import javax.swing.*;
|
||||||
import javax.swing.border.*;
|
import javax.swing.border.*;
|
||||||
|
|
||||||
import docking.util.KeyBindingUtils;
|
import docking.actions.KeyBindingUtils;
|
||||||
import docking.widgets.label.GDLabel;
|
import docking.widgets.label.GDLabel;
|
||||||
import docking.widgets.label.GIconLabel;
|
import docking.widgets.label.GIconLabel;
|
||||||
import generic.util.WindowUtilities;
|
import generic.util.WindowUtilities;
|
||||||
|
|
|
@ -26,8 +26,8 @@ import javax.swing.*;
|
||||||
import javax.swing.tree.*;
|
import javax.swing.tree.*;
|
||||||
|
|
||||||
import docking.DockingUtils;
|
import docking.DockingUtils;
|
||||||
|
import docking.actions.KeyBindingUtils;
|
||||||
import docking.dnd.*;
|
import docking.dnd.*;
|
||||||
import docking.util.KeyBindingUtils;
|
|
||||||
import docking.widgets.table.AutoscrollAdapter;
|
import docking.widgets.table.AutoscrollAdapter;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -30,8 +30,8 @@ import javax.swing.tree.*;
|
||||||
|
|
||||||
import docking.DockingUtils;
|
import docking.DockingUtils;
|
||||||
import docking.action.DockingAction;
|
import docking.action.DockingAction;
|
||||||
|
import docking.actions.KeyBindingUtils;
|
||||||
import docking.dnd.DropTgtAdapter;
|
import docking.dnd.DropTgtAdapter;
|
||||||
import docking.util.KeyBindingUtils;
|
|
||||||
import docking.widgets.JTreeMouseListenerDelegate;
|
import docking.widgets.JTreeMouseListenerDelegate;
|
||||||
import ghidra.app.util.SelectionTransferData;
|
import ghidra.app.util.SelectionTransferData;
|
||||||
import ghidra.app.util.SelectionTransferable;
|
import ghidra.app.util.SelectionTransferable;
|
||||||
|
|
|
@ -28,9 +28,9 @@ import javax.swing.event.ChangeEvent;
|
||||||
import javax.swing.event.ChangeListener;
|
import javax.swing.event.ChangeListener;
|
||||||
|
|
||||||
import docking.action.DockingAction;
|
import docking.action.DockingAction;
|
||||||
|
import docking.actions.KeyBindingUtils;
|
||||||
import docking.dnd.DropTgtAdapter;
|
import docking.dnd.DropTgtAdapter;
|
||||||
import docking.dnd.Droppable;
|
import docking.dnd.Droppable;
|
||||||
import docking.util.KeyBindingUtils;
|
|
||||||
import docking.widgets.label.GDLabel;
|
import docking.widgets.label.GDLabel;
|
||||||
import ghidra.app.util.*;
|
import ghidra.app.util.*;
|
||||||
import ghidra.app.util.viewer.field.BrowserCodeUnitFormat;
|
import ghidra.app.util.viewer.field.BrowserCodeUnitFormat;
|
||||||
|
|
|
@ -43,7 +43,6 @@ import utilities.util.FileUtilities;
|
||||||
|
|
||||||
class GhidraScriptActionManager {
|
class GhidraScriptActionManager {
|
||||||
public static final String RERUN_LAST_SHARED_ACTION_NAME = "Rerun Last Script";
|
public static final String RERUN_LAST_SHARED_ACTION_NAME = "Rerun Last Script";
|
||||||
public static final String GLOBAL_RERUN_LAST_SHARED_ACTION_NAME = "Global Rerun Last Script";
|
|
||||||
private static final KeyStroke RERUN_LAST_SCRIPT_KEYSTROKE = KeyStroke.getKeyStroke(
|
private static final KeyStroke RERUN_LAST_SCRIPT_KEYSTROKE = KeyStroke.getKeyStroke(
|
||||||
KeyEvent.VK_R, DockingUtils.CONTROL_KEY_MODIFIER_MASK | InputEvent.SHIFT_DOWN_MASK);
|
KeyEvent.VK_R, DockingUtils.CONTROL_KEY_MODIFIER_MASK | InputEvent.SHIFT_DOWN_MASK);
|
||||||
private static final String SCRIPT_ACTIONS_KEY = "Scripts_Actions_Key";
|
private static final String SCRIPT_ACTIONS_KEY = "Scripts_Actions_Key";
|
||||||
|
|
|
@ -29,8 +29,8 @@ import javax.swing.undo.UndoableEdit;
|
||||||
|
|
||||||
import docking.*;
|
import docking.*;
|
||||||
import docking.action.*;
|
import docking.action.*;
|
||||||
|
import docking.actions.KeyBindingUtils;
|
||||||
import docking.options.editor.FontPropertyEditor;
|
import docking.options.editor.FontPropertyEditor;
|
||||||
import docking.util.KeyBindingUtils;
|
|
||||||
import docking.widgets.OptionDialog;
|
import docking.widgets.OptionDialog;
|
||||||
import generic.jar.ResourceFile;
|
import generic.jar.ResourceFile;
|
||||||
import ghidra.app.script.GhidraScriptUtil;
|
import ghidra.app.script.GhidraScriptUtil;
|
||||||
|
|
|
@ -28,7 +28,7 @@ import docking.widgets.label.GDLabel;
|
||||||
* components (usually icon buttons)
|
* components (usually icon buttons)
|
||||||
*/
|
*/
|
||||||
public class TitledPanel extends JPanel {
|
public class TitledPanel extends JPanel {
|
||||||
private JLabel title;
|
private JLabel title; // GDLabel or GHtmlLabel
|
||||||
private JPanel titlePanel;
|
private JPanel titlePanel;
|
||||||
private JPanel iconPanel;
|
private JPanel iconPanel;
|
||||||
private JComponent bottomComp;
|
private JComponent bottomComp;
|
||||||
|
@ -37,16 +37,27 @@ public class TitledPanel extends JPanel {
|
||||||
/**
|
/**
|
||||||
* Creates a new TitlePanel
|
* Creates a new TitlePanel
|
||||||
* @param name the name of the panel
|
* @param name the name of the panel
|
||||||
* @param panel the component to wrap.
|
* @param panel the component to wrap
|
||||||
* @param margin the size of the margin to use.
|
* @param margin the size of the margin to use
|
||||||
*/
|
*/
|
||||||
public TitledPanel(String name, JComponent panel, int margin) {
|
public TitledPanel(String name, JComponent panel, int margin) {
|
||||||
|
this(new GDLabel(name), panel, margin);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new TitlePanel
|
||||||
|
*
|
||||||
|
* @param titleLabel the title label for the panel; this allow clients to provide HTML-based
|
||||||
|
* title text. Note: it is up to the client to escape this text as needed for safety
|
||||||
|
* @param panel the component to wrap
|
||||||
|
* @param margin the size of the margin to use
|
||||||
|
*/
|
||||||
|
public TitledPanel(JLabel titleLabel, JComponent panel, int margin) {
|
||||||
super(new BorderLayout());
|
super(new BorderLayout());
|
||||||
titlePanel = new JPanel(new BorderLayout());
|
titlePanel = new JPanel(new BorderLayout());
|
||||||
iconPanel = new JPanel(new FlowLayout(FlowLayout.CENTER, 4, 1));
|
iconPanel = new JPanel(new FlowLayout(FlowLayout.CENTER, 4, 1));
|
||||||
iconPanel.setBorder(BorderFactory.createEmptyBorder(0, 0, 0, 0));
|
iconPanel.setBorder(BorderFactory.createEmptyBorder(0, 0, 0, 0));
|
||||||
title = new GDLabel(name);
|
title = titleLabel;
|
||||||
title.setToolTipText(name);
|
|
||||||
JLabel filler = new GDLabel();
|
JLabel filler = new GDLabel();
|
||||||
filler.setPreferredSize(new Dimension(margin, filler.getPreferredSize().height));
|
filler.setPreferredSize(new Dimension(margin, filler.getPreferredSize().height));
|
||||||
titlePanel.add(filler, BorderLayout.WEST);
|
titlePanel.add(filler, BorderLayout.WEST);
|
||||||
|
|
|
@ -212,9 +212,8 @@ public abstract class AbstractScreenShotGenerator extends AbstractGhidraHeadedIn
|
||||||
|
|
||||||
public void performAction(String actionName, String owner, ComponentProvider contextProvider,
|
public void performAction(String actionName, String owner, ComponentProvider contextProvider,
|
||||||
boolean wait) {
|
boolean wait) {
|
||||||
String fullActionName = actionName + " (" + owner + ")";
|
DockingActionIf action = getAction(tool, owner, actionName);
|
||||||
List<DockingActionIf> action = tool.getDockingActionsByFullActionName(fullActionName);
|
performAction(action, contextProvider, wait);
|
||||||
performAction(action.get(0), contextProvider, wait);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void showOptions(final String optionsCategoryName) {
|
public void showOptions(final String optionsCategoryName) {
|
||||||
|
|
|
@ -359,12 +359,11 @@ public abstract class GhidraScreenShotGenerator extends AbstractScreenShotGenera
|
||||||
}
|
}
|
||||||
|
|
||||||
public void performFrontEndAction(String actionName, String owner, boolean wait) {
|
public void performFrontEndAction(String actionName, String owner, boolean wait) {
|
||||||
String fullActionName = actionName + " (" + owner + ")";
|
|
||||||
FrontEndTool frontEnd = getFrontEndTool();
|
FrontEndTool frontEnd = getFrontEndTool();
|
||||||
List<DockingActionIf> action = frontEnd.getDockingActionsByFullActionName(fullActionName);
|
|
||||||
|
DockingActionIf action = getAction(frontEnd, owner, actionName);
|
||||||
ComponentProvider compProvider =
|
ComponentProvider compProvider =
|
||||||
(ComponentProvider) getInstanceField("compProvider", frontEnd);
|
(ComponentProvider) getInstanceField("compProvider", frontEnd);
|
||||||
performAction(action.get(0), compProvider, wait);
|
performAction(action, compProvider, wait);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,7 +18,7 @@ package ghidra.app.plugin.core.algorithmtree;
|
||||||
import static org.junit.Assert.assertNotNull;
|
import static org.junit.Assert.assertNotNull;
|
||||||
import static org.junit.Assert.assertTrue;
|
import static org.junit.Assert.assertTrue;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.Set;
|
||||||
|
|
||||||
import org.junit.*;
|
import org.junit.*;
|
||||||
|
|
||||||
|
@ -33,6 +33,7 @@ import ghidra.program.model.listing.Program;
|
||||||
import ghidra.program.model.listing.ProgramModule;
|
import ghidra.program.model.listing.ProgramModule;
|
||||||
import ghidra.program.util.GroupPath;
|
import ghidra.program.util.GroupPath;
|
||||||
import ghidra.test.*;
|
import ghidra.test.*;
|
||||||
|
import util.CollectionUtils;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Test the module algorithm plugin gui elements.
|
* Test the module algorithm plugin gui elements.
|
||||||
|
@ -43,7 +44,7 @@ public class ModuleAlgorithmPluginTest extends AbstractGhidraHeadedIntegrationTe
|
||||||
private PluginTool tool;
|
private PluginTool tool;
|
||||||
private Program program;
|
private Program program;
|
||||||
private ModuleAlgorithmPlugin plugin;
|
private ModuleAlgorithmPlugin plugin;
|
||||||
private List<DockingActionIf> actions;
|
private Set<DockingActionIf> actions;
|
||||||
private ProgramTreeService service;
|
private ProgramTreeService service;
|
||||||
private Object context;
|
private Object context;
|
||||||
|
|
||||||
|
@ -58,7 +59,7 @@ public class ModuleAlgorithmPluginTest extends AbstractGhidraHeadedIntegrationTe
|
||||||
tool.addPlugin(ProgramTreePlugin.class.getName());
|
tool.addPlugin(ProgramTreePlugin.class.getName());
|
||||||
tool.addPlugin(ModuleAlgorithmPlugin.class.getName());
|
tool.addPlugin(ModuleAlgorithmPlugin.class.getName());
|
||||||
plugin = env.getPlugin(ModuleAlgorithmPlugin.class);
|
plugin = env.getPlugin(ModuleAlgorithmPlugin.class);
|
||||||
actions = tool.getDockingActionsByOwnerName(plugin.getName());
|
actions = getActionsByOwner(tool, plugin.getName());
|
||||||
service = tool.getService(ProgramTreeService.class);
|
service = tool.getService(ProgramTreeService.class);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -98,7 +99,7 @@ public class ModuleAlgorithmPluginTest extends AbstractGhidraHeadedIntegrationTe
|
||||||
|
|
||||||
getContextObject(vps);
|
getContextObject(vps);
|
||||||
|
|
||||||
performAction(actions.get(0), new ActionContext(null, context), true);
|
performAction(CollectionUtils.any(actions), new ActionContext(null, context), true);
|
||||||
|
|
||||||
waitForTasks();
|
waitForTasks();
|
||||||
program.flushEvents();
|
program.flushEvents();
|
||||||
|
|
|
@ -1090,10 +1090,9 @@ public class CallTreePluginTest extends AbstractGhidraHeadedIntegrationTest {
|
||||||
private DockingActionIf getAction(String actionName) {
|
private DockingActionIf getAction(String actionName) {
|
||||||
// make sure there is a provider from which to get actions
|
// make sure there is a provider from which to get actions
|
||||||
getProvider();
|
getProvider();
|
||||||
String fullActionName = actionName + " (CallTreePlugin)";
|
|
||||||
List<DockingActionIf> actions = tool.getDockingActionsByFullActionName(fullActionName);
|
DockingActionIf action = getAction(tool, "CallTreePlugin", actionName);
|
||||||
Assert.assertTrue("Could not find action: " + fullActionName, actions.size() > 0);
|
return action;
|
||||||
return actions.get(0);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void myWaitForTree(GTree gTree, CallTreeProvider treeProvider) {
|
private void myWaitForTree(GTree gTree, CallTreeProvider treeProvider) {
|
||||||
|
|
|
@ -165,7 +165,7 @@ public abstract class AbstractDataActionTest extends AbstractGhidraHeadedIntegra
|
||||||
builtInDataTypesManager.setFavorite(root.getDataType("word"), true);
|
builtInDataTypesManager.setFavorite(root.getDataType("word"), true);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void checkActions(List<DockingActionIf> actions, boolean enabled, String caseStr) {
|
protected void checkActions(Set<DockingActionIf> actions, boolean enabled, String caseStr) {
|
||||||
checkAction(actions, CREATE_STRUCTURE, enabled, caseStr);
|
checkAction(actions, CREATE_STRUCTURE, enabled, caseStr);
|
||||||
checkAction(actions, EDIT_DATA_TYPE, enabled, caseStr);
|
checkAction(actions, EDIT_DATA_TYPE, enabled, caseStr);
|
||||||
checkAction(actions, CREATE_ARRAY, enabled, caseStr);
|
checkAction(actions, CREATE_ARRAY, enabled, caseStr);
|
||||||
|
@ -1063,7 +1063,7 @@ public abstract class AbstractDataActionTest extends AbstractGhidraHeadedIntegra
|
||||||
ProgramSelection sel = getCurrentSelection();
|
ProgramSelection sel = getCurrentSelection();
|
||||||
boolean useSelection = (sel != null && !sel.isEmpty());
|
boolean useSelection = (sel != null && !sel.isEmpty());
|
||||||
|
|
||||||
List<DockingActionIf> actions = tool.getDockingActionsByOwnerName(plugin.getName());
|
Set<DockingActionIf> actions = getActionsByOwner(tool, plugin.getName());
|
||||||
|
|
||||||
for (DockingActionIf element : actions) {
|
for (DockingActionIf element : actions) {
|
||||||
MenuData menuBarData = element.getMenuBarData();
|
MenuData menuBarData = element.getMenuBarData();
|
||||||
|
@ -1113,31 +1113,6 @@ public abstract class AbstractDataActionTest extends AbstractGhidraHeadedIntegra
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// if (useSelection) {
|
|
||||||
//
|
|
||||||
// checkAction(actions, CREATE_STRUCTURE, true, caseName);
|
|
||||||
// checkAction(actions, EDIT_STRUCTURE, false, caseName);
|
|
||||||
// checkAction(actions, CREATE_ARRAY, true, caseName);
|
|
||||||
// checkAction(actions, DEFAULT_DATA_SETTINGS, false, caseName);
|
|
||||||
// checkAction(actions, DATA_SETTINGS, false, caseName);
|
|
||||||
// checkAction(actions, CYCLE_FLOAT_DOUBLE, true, caseName);
|
|
||||||
// checkAction(actions, CYCLE_BYTE_WORD_DWORD_QWORD, true, caseName);
|
|
||||||
// checkAction(actions, CYCLE_CHAR_STRING_UNICODE, true, caseName);
|
|
||||||
// checkAction(actions, DEFINE_BYTE, true, caseName);
|
|
||||||
// checkAction(actions, DEFINE_WORD, true, caseName);
|
|
||||||
// checkAction(actions, DEFINE_DWORD, true, caseName);
|
|
||||||
// checkAction(actions, DEFINE_QWORD, true, caseName);
|
|
||||||
// checkAction(actions, DEFINE_FLOAT, true, caseName);
|
|
||||||
// checkAction(actions, DEFINE_DOUBLE, true, caseName);
|
|
||||||
// checkAction(actions, DEFINE_TERM_CSTRING, true, caseName);
|
|
||||||
// checkAction(actions, DEFINE_POINTER, true, caseName);
|
|
||||||
//
|
|
||||||
// PluginAction recentlyUsedAction = getAction(RECENTLY_USED);
|
|
||||||
// if (recentlyUsedAction != null) {
|
|
||||||
// checkAction(recentlyUsedAction, false, caseName);
|
|
||||||
// }
|
|
||||||
// return;
|
|
||||||
// }
|
|
||||||
if (data != null) {
|
if (data != null) {
|
||||||
|
|
||||||
DataType dt = data.getDataType();
|
DataType dt = data.getDataType();
|
||||||
|
@ -1184,10 +1159,10 @@ public abstract class AbstractDataActionTest extends AbstractGhidraHeadedIntegra
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void checkOnUndefined(List<DockingActionIf> actions) {
|
protected void checkOnUndefined(Set<DockingActionIf> actions) {
|
||||||
|
|
||||||
if (actions == null) {
|
if (actions == null) {
|
||||||
actions = tool.getDockingActionsByOwnerName(plugin.getName());
|
actions = getActionsByOwner(tool, plugin.getName());
|
||||||
}
|
}
|
||||||
|
|
||||||
Data data = getContextData();
|
Data data = getContextData();
|
||||||
|
@ -1223,10 +1198,10 @@ public abstract class AbstractDataActionTest extends AbstractGhidraHeadedIntegra
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void checkOnDefined(List<DockingActionIf> actions, Class<?> expectedDataType) {
|
protected void checkOnDefined(Set<DockingActionIf> actions, Class<?> expectedDataType) {
|
||||||
|
|
||||||
if (actions == null) {
|
if (actions == null) {
|
||||||
actions = tool.getDockingActionsByOwnerName(plugin.getName());
|
actions = getActionsByOwner(tool, plugin.getName());
|
||||||
}
|
}
|
||||||
|
|
||||||
String dtName = expectedDataType.getName();
|
String dtName = expectedDataType.getName();
|
||||||
|
@ -1287,10 +1262,10 @@ public abstract class AbstractDataActionTest extends AbstractGhidraHeadedIntegra
|
||||||
checkAction(actions, DEFINE_POINTER, true, caseName);
|
checkAction(actions, DEFINE_POINTER, true, caseName);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void checkOnArray(List<DockingActionIf> actions, DataType interiorDt, int arraySize) {
|
protected void checkOnArray(Set<DockingActionIf> actions, DataType interiorDt, int arraySize) {
|
||||||
|
|
||||||
if (actions == null) {
|
if (actions == null) {
|
||||||
actions = tool.getDockingActionsByOwnerName(plugin.getName());
|
actions = getActionsByOwner(tool, plugin.getName());
|
||||||
}
|
}
|
||||||
|
|
||||||
Data d = getContextData();
|
Data d = getContextData();
|
||||||
|
@ -1356,10 +1331,10 @@ public abstract class AbstractDataActionTest extends AbstractGhidraHeadedIntegra
|
||||||
* @param actions
|
* @param actions
|
||||||
* @param structSize structure size or -1 to disable size check
|
* @param structSize structure size or -1 to disable size check
|
||||||
*/
|
*/
|
||||||
protected void checkOnStructure(List<DockingActionIf> actions, int structSize) {
|
protected void checkOnStructure(Set<DockingActionIf> actions, int structSize) {
|
||||||
|
|
||||||
if (actions == null) {
|
if (actions == null) {
|
||||||
actions = tool.getDockingActionsByOwnerName(plugin.getName());
|
actions = getActionsByOwner(tool, plugin.getName());
|
||||||
}
|
}
|
||||||
|
|
||||||
Data d = getContextData();
|
Data d = getContextData();
|
||||||
|
@ -1400,7 +1375,7 @@ public abstract class AbstractDataActionTest extends AbstractGhidraHeadedIntegra
|
||||||
}
|
}
|
||||||
|
|
||||||
protected DockingActionIf getAction(String name) {
|
protected DockingActionIf getAction(String name) {
|
||||||
List<DockingActionIf> actions = tool.getDockingActionsByOwnerName(plugin.getName());
|
Set<DockingActionIf> actions = getActionsByOwner(tool, plugin.getName());
|
||||||
for (DockingActionIf element : actions) {
|
for (DockingActionIf element : actions) {
|
||||||
String actionName = element.getName();
|
String actionName = element.getName();
|
||||||
int pos = actionName.indexOf(" (");
|
int pos = actionName.indexOf(" (");
|
||||||
|
@ -1439,7 +1414,7 @@ public abstract class AbstractDataActionTest extends AbstractGhidraHeadedIntegra
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void checkAction(List<DockingActionIf> actions, String name, boolean isEnabled,
|
protected void checkAction(Set<DockingActionIf> actions, String name, boolean isEnabled,
|
||||||
String caseName) {
|
String caseName) {
|
||||||
for (DockingActionIf element : actions) {
|
for (DockingActionIf element : actions) {
|
||||||
String actionName = element.getName();
|
String actionName = element.getName();
|
||||||
|
|
|
@ -17,7 +17,7 @@ package ghidra.app.plugin.core.data;
|
||||||
|
|
||||||
import static org.junit.Assert.*;
|
import static org.junit.Assert.*;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.Set;
|
||||||
|
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.junit.experimental.categories.Category;
|
import org.junit.experimental.categories.Category;
|
||||||
|
@ -39,13 +39,13 @@ public class DataAction4Test extends AbstractDataActionTest {
|
||||||
@Test
|
@Test
|
||||||
public void testNotepadLocations() {
|
public void testNotepadLocations() {
|
||||||
|
|
||||||
List<DockingActionIf> actions;
|
Set<DockingActionIf> actions;
|
||||||
|
|
||||||
program.addConsumer(this); // allow program to survive close
|
program.addConsumer(this); // allow program to survive close
|
||||||
try {
|
try {
|
||||||
closeProgram();
|
closeProgram();
|
||||||
|
|
||||||
actions = tool.getDockingActionsByOwnerName(plugin.getName());
|
actions = getActionsByOwner(tool, plugin.getName());
|
||||||
assertEquals(ACTION_COUNT, actions.size());
|
assertEquals(ACTION_COUNT, actions.size());
|
||||||
checkActions(actions, false, "Start");
|
checkActions(actions, false, "Start");
|
||||||
|
|
||||||
|
@ -60,7 +60,7 @@ public class DataAction4Test extends AbstractDataActionTest {
|
||||||
|
|
||||||
closeProgram();
|
closeProgram();
|
||||||
|
|
||||||
actions = tool.getDockingActionsByOwnerName(plugin.getName());
|
actions = getActionsByOwner(tool, plugin.getName());
|
||||||
assertEquals(ACTION_COUNT, actions.size());
|
assertEquals(ACTION_COUNT, actions.size());
|
||||||
checkActions(actions, false, "Start");
|
checkActions(actions, false, "Start");
|
||||||
}
|
}
|
||||||
|
@ -73,13 +73,13 @@ public class DataAction4Test extends AbstractDataActionTest {
|
||||||
|
|
||||||
doAction(DEFINE_BYTE, true);
|
doAction(DEFINE_BYTE, true);
|
||||||
|
|
||||||
List<DockingActionIf> actions = tool.getDockingActionsByOwnerName(plugin.getName());
|
Set<DockingActionIf> actions = getActionsByOwner(tool, plugin.getName());
|
||||||
assertEquals(ACTION_COUNT, actions.size());
|
assertEquals(ACTION_COUNT, actions.size());
|
||||||
checkOnDefined(actions, ByteDataType.class);
|
checkOnDefined(actions, ByteDataType.class);
|
||||||
|
|
||||||
undo(program);
|
undo(program);
|
||||||
|
|
||||||
actions = tool.getDockingActionsByOwnerName(plugin.getName());
|
actions = getActionsByOwner(tool, plugin.getName());
|
||||||
checkOnUndefined(actions);
|
checkOnUndefined(actions);
|
||||||
|
|
||||||
gotoLocation(0x010069f2);
|
gotoLocation(0x010069f2);
|
||||||
|
@ -107,7 +107,7 @@ public class DataAction4Test extends AbstractDataActionTest {
|
||||||
|
|
||||||
doAction(DEFINE_WORD, true);
|
doAction(DEFINE_WORD, true);
|
||||||
|
|
||||||
List<DockingActionIf> actions = tool.getDockingActionsByOwnerName(plugin.getName());
|
Set<DockingActionIf> actions = getActionsByOwner(tool, plugin.getName());
|
||||||
assertEquals(ACTION_COUNT, actions.size());
|
assertEquals(ACTION_COUNT, actions.size());
|
||||||
checkOnDefined(actions, WordDataType.class);
|
checkOnDefined(actions, WordDataType.class);
|
||||||
|
|
||||||
|
@ -138,7 +138,7 @@ public class DataAction4Test extends AbstractDataActionTest {
|
||||||
|
|
||||||
doAction(DEFINE_DWORD, true);
|
doAction(DEFINE_DWORD, true);
|
||||||
|
|
||||||
List<DockingActionIf> actions = tool.getDockingActionsByOwnerName(plugin.getName());
|
Set<DockingActionIf> actions = getActionsByOwner(tool, plugin.getName());
|
||||||
assertEquals(ACTION_COUNT, actions.size());
|
assertEquals(ACTION_COUNT, actions.size());
|
||||||
checkOnDefined(actions, DWordDataType.class);
|
checkOnDefined(actions, DWordDataType.class);
|
||||||
|
|
||||||
|
@ -169,7 +169,7 @@ public class DataAction4Test extends AbstractDataActionTest {
|
||||||
|
|
||||||
doAction(DEFINE_QWORD, true);
|
doAction(DEFINE_QWORD, true);
|
||||||
|
|
||||||
List<DockingActionIf> actions = tool.getDockingActionsByOwnerName(plugin.getName());
|
Set<DockingActionIf> actions = getActionsByOwner(tool, plugin.getName());
|
||||||
assertEquals(ACTION_COUNT, actions.size());
|
assertEquals(ACTION_COUNT, actions.size());
|
||||||
checkOnDefined(actions, QWordDataType.class);
|
checkOnDefined(actions, QWordDataType.class);
|
||||||
|
|
||||||
|
@ -200,7 +200,7 @@ public class DataAction4Test extends AbstractDataActionTest {
|
||||||
|
|
||||||
doAction(DEFINE_FLOAT, true);
|
doAction(DEFINE_FLOAT, true);
|
||||||
|
|
||||||
List<DockingActionIf> actions = tool.getDockingActionsByOwnerName(plugin.getName());
|
Set<DockingActionIf> actions = getActionsByOwner(tool, plugin.getName());
|
||||||
assertEquals(ACTION_COUNT, actions.size());
|
assertEquals(ACTION_COUNT, actions.size());
|
||||||
checkOnDefined(actions, FloatDataType.class);
|
checkOnDefined(actions, FloatDataType.class);
|
||||||
|
|
||||||
|
@ -231,7 +231,7 @@ public class DataAction4Test extends AbstractDataActionTest {
|
||||||
|
|
||||||
doAction(DEFINE_DOUBLE, true);
|
doAction(DEFINE_DOUBLE, true);
|
||||||
|
|
||||||
List<DockingActionIf> actions = tool.getDockingActionsByOwnerName(plugin.getName());
|
Set<DockingActionIf> actions = getActionsByOwner(tool, plugin.getName());
|
||||||
assertEquals(ACTION_COUNT, actions.size());
|
assertEquals(ACTION_COUNT, actions.size());
|
||||||
checkOnDefined(actions, DoubleDataType.class);
|
checkOnDefined(actions, DoubleDataType.class);
|
||||||
|
|
||||||
|
@ -264,7 +264,7 @@ public class DataAction4Test extends AbstractDataActionTest {
|
||||||
|
|
||||||
doAction(CYCLE_CHAR_STRING_UNICODE, true);
|
doAction(CYCLE_CHAR_STRING_UNICODE, true);
|
||||||
|
|
||||||
List<DockingActionIf> actions = tool.getDockingActionsByOwnerName(plugin.getName());
|
Set<DockingActionIf> actions = getActionsByOwner(tool, plugin.getName());
|
||||||
assertEquals(ACTION_COUNT, actions.size());
|
assertEquals(ACTION_COUNT, actions.size());
|
||||||
checkOnDefined(actions, CharDataType.class);
|
checkOnDefined(actions, CharDataType.class);
|
||||||
|
|
||||||
|
@ -283,15 +283,15 @@ public class DataAction4Test extends AbstractDataActionTest {
|
||||||
checkOnDefined(actions, CharDataType.class);
|
checkOnDefined(actions, CharDataType.class);
|
||||||
|
|
||||||
doAction(CYCLE_CHAR_STRING_UNICODE, true);
|
doAction(CYCLE_CHAR_STRING_UNICODE, true);
|
||||||
actions = tool.getDockingActionsByOwnerName(plugin.getName());
|
actions = getActionsByOwner(tool, plugin.getName());
|
||||||
checkOnDefined(actions, StringDataType.class);
|
checkOnDefined(actions, StringDataType.class);
|
||||||
|
|
||||||
doAction(CYCLE_CHAR_STRING_UNICODE, true);
|
doAction(CYCLE_CHAR_STRING_UNICODE, true);
|
||||||
actions = tool.getDockingActionsByOwnerName(plugin.getName());
|
actions = getActionsByOwner(tool, plugin.getName());
|
||||||
checkOnDefined(actions, UnicodeDataType.class);
|
checkOnDefined(actions, UnicodeDataType.class);
|
||||||
|
|
||||||
doAction(CYCLE_CHAR_STRING_UNICODE, true);
|
doAction(CYCLE_CHAR_STRING_UNICODE, true);
|
||||||
actions = tool.getDockingActionsByOwnerName(plugin.getName());
|
actions = getActionsByOwner(tool, plugin.getName());
|
||||||
checkOnDefined(actions, CharDataType.class);
|
checkOnDefined(actions, CharDataType.class);
|
||||||
|
|
||||||
clearLocation(0x01006a00);
|
clearLocation(0x01006a00);
|
||||||
|
@ -326,7 +326,7 @@ public class DataAction4Test extends AbstractDataActionTest {
|
||||||
|
|
||||||
doAction(CYCLE_BYTE_WORD_DWORD_QWORD, true);
|
doAction(CYCLE_BYTE_WORD_DWORD_QWORD, true);
|
||||||
|
|
||||||
List<DockingActionIf> actions = tool.getDockingActionsByOwnerName(plugin.getName());
|
Set<DockingActionIf> actions = getActionsByOwner(tool, plugin.getName());
|
||||||
assertEquals(ACTION_COUNT, actions.size());
|
assertEquals(ACTION_COUNT, actions.size());
|
||||||
checkOnDefined(actions, ByteDataType.class);
|
checkOnDefined(actions, ByteDataType.class);
|
||||||
|
|
||||||
|
@ -345,19 +345,19 @@ public class DataAction4Test extends AbstractDataActionTest {
|
||||||
checkOnDefined(actions, ByteDataType.class);
|
checkOnDefined(actions, ByteDataType.class);
|
||||||
|
|
||||||
doAction(CYCLE_BYTE_WORD_DWORD_QWORD, true);
|
doAction(CYCLE_BYTE_WORD_DWORD_QWORD, true);
|
||||||
actions = tool.getDockingActionsByOwnerName(plugin.getName());
|
actions = getActionsByOwner(tool, plugin.getName());
|
||||||
checkOnDefined(actions, WordDataType.class);
|
checkOnDefined(actions, WordDataType.class);
|
||||||
|
|
||||||
doAction(CYCLE_BYTE_WORD_DWORD_QWORD, true);
|
doAction(CYCLE_BYTE_WORD_DWORD_QWORD, true);
|
||||||
actions = tool.getDockingActionsByOwnerName(plugin.getName());
|
actions = getActionsByOwner(tool, plugin.getName());
|
||||||
checkOnDefined(actions, DWordDataType.class);
|
checkOnDefined(actions, DWordDataType.class);
|
||||||
|
|
||||||
doAction(CYCLE_BYTE_WORD_DWORD_QWORD, true);
|
doAction(CYCLE_BYTE_WORD_DWORD_QWORD, true);
|
||||||
actions = tool.getDockingActionsByOwnerName(plugin.getName());
|
actions = getActionsByOwner(tool, plugin.getName());
|
||||||
checkOnDefined(actions, QWordDataType.class);
|
checkOnDefined(actions, QWordDataType.class);
|
||||||
|
|
||||||
doAction(CYCLE_BYTE_WORD_DWORD_QWORD, true);
|
doAction(CYCLE_BYTE_WORD_DWORD_QWORD, true);
|
||||||
actions = tool.getDockingActionsByOwnerName(plugin.getName());
|
actions = getActionsByOwner(tool, plugin.getName());
|
||||||
checkOnDefined(actions, ByteDataType.class);
|
checkOnDefined(actions, ByteDataType.class);
|
||||||
|
|
||||||
clearLocation(0x01006a00);
|
clearLocation(0x01006a00);
|
||||||
|
@ -387,19 +387,19 @@ public class DataAction4Test extends AbstractDataActionTest {
|
||||||
// Test cycle when it does not fit
|
// Test cycle when it does not fit
|
||||||
|
|
||||||
gotoLocation(0x010069f0);
|
gotoLocation(0x010069f0);
|
||||||
actions = tool.getDockingActionsByOwnerName(plugin.getName());
|
actions = getActionsByOwner(tool, plugin.getName());
|
||||||
checkOnUndefined(actions);
|
checkOnUndefined(actions);
|
||||||
|
|
||||||
doAction(CYCLE_BYTE_WORD_DWORD_QWORD, true);
|
doAction(CYCLE_BYTE_WORD_DWORD_QWORD, true);
|
||||||
actions = tool.getDockingActionsByOwnerName(plugin.getName());
|
actions = getActionsByOwner(tool, plugin.getName());
|
||||||
checkOnDefined(actions, ByteDataType.class);
|
checkOnDefined(actions, ByteDataType.class);
|
||||||
|
|
||||||
doAction(CYCLE_BYTE_WORD_DWORD_QWORD, true);
|
doAction(CYCLE_BYTE_WORD_DWORD_QWORD, true);
|
||||||
actions = tool.getDockingActionsByOwnerName(plugin.getName());
|
actions = getActionsByOwner(tool, plugin.getName());
|
||||||
checkOnDefined(actions, WordDataType.class);
|
checkOnDefined(actions, WordDataType.class);
|
||||||
|
|
||||||
doAction(CYCLE_BYTE_WORD_DWORD_QWORD, true);
|
doAction(CYCLE_BYTE_WORD_DWORD_QWORD, true);
|
||||||
actions = tool.getDockingActionsByOwnerName(plugin.getName());
|
actions = getActionsByOwner(tool, plugin.getName());
|
||||||
checkOnUndefined(actions);
|
checkOnUndefined(actions);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -414,7 +414,7 @@ public class DataAction4Test extends AbstractDataActionTest {
|
||||||
|
|
||||||
doAction(CYCLE_FLOAT_DOUBLE, true);
|
doAction(CYCLE_FLOAT_DOUBLE, true);
|
||||||
|
|
||||||
List<DockingActionIf> actions = tool.getDockingActionsByOwnerName(plugin.getName());
|
Set<DockingActionIf> actions = getActionsByOwner(tool, plugin.getName());
|
||||||
assertEquals(ACTION_COUNT, actions.size());
|
assertEquals(ACTION_COUNT, actions.size());
|
||||||
checkOnDefined(actions, FloatDataType.class);
|
checkOnDefined(actions, FloatDataType.class);
|
||||||
|
|
||||||
|
@ -433,11 +433,11 @@ public class DataAction4Test extends AbstractDataActionTest {
|
||||||
checkOnDefined(actions, FloatDataType.class);
|
checkOnDefined(actions, FloatDataType.class);
|
||||||
|
|
||||||
doAction(CYCLE_FLOAT_DOUBLE, true);
|
doAction(CYCLE_FLOAT_DOUBLE, true);
|
||||||
actions = tool.getDockingActionsByOwnerName(plugin.getName());
|
actions = getActionsByOwner(tool, plugin.getName());
|
||||||
checkOnDefined(actions, DoubleDataType.class);
|
checkOnDefined(actions, DoubleDataType.class);
|
||||||
|
|
||||||
doAction(CYCLE_FLOAT_DOUBLE, true);
|
doAction(CYCLE_FLOAT_DOUBLE, true);
|
||||||
actions = tool.getDockingActionsByOwnerName(plugin.getName());
|
actions = getActionsByOwner(tool, plugin.getName());
|
||||||
checkOnDefined(actions, FloatDataType.class);
|
checkOnDefined(actions, FloatDataType.class);
|
||||||
|
|
||||||
clearLocation(0x01006a00);
|
clearLocation(0x01006a00);
|
||||||
|
@ -461,15 +461,15 @@ public class DataAction4Test extends AbstractDataActionTest {
|
||||||
// Test cycle when it does not fit
|
// Test cycle when it does not fit
|
||||||
|
|
||||||
gotoLocation(0x010069ee);
|
gotoLocation(0x010069ee);
|
||||||
actions = tool.getDockingActionsByOwnerName(plugin.getName());
|
actions = getActionsByOwner(tool, plugin.getName());
|
||||||
checkOnUndefined(actions);
|
checkOnUndefined(actions);
|
||||||
|
|
||||||
doAction(CYCLE_FLOAT_DOUBLE, true);
|
doAction(CYCLE_FLOAT_DOUBLE, true);
|
||||||
actions = tool.getDockingActionsByOwnerName(plugin.getName());
|
actions = getActionsByOwner(tool, plugin.getName());
|
||||||
checkOnDefined(actions, FloatDataType.class);
|
checkOnDefined(actions, FloatDataType.class);
|
||||||
|
|
||||||
doAction(CYCLE_FLOAT_DOUBLE, true);
|
doAction(CYCLE_FLOAT_DOUBLE, true);
|
||||||
actions = tool.getDockingActionsByOwnerName(plugin.getName());
|
actions = getActionsByOwner(tool, plugin.getName());
|
||||||
checkOnUndefined(actions);
|
checkOnUndefined(actions);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -495,7 +495,7 @@ public class DataAction4Test extends AbstractDataActionTest {
|
||||||
|
|
||||||
waitForPostedSwingRunnables();
|
waitForPostedSwingRunnables();
|
||||||
|
|
||||||
List<DockingActionIf> actions = tool.getDockingActionsByOwnerName(plugin.getName());
|
Set<DockingActionIf> actions = getActionsByOwner(tool, plugin.getName());
|
||||||
checkOnArray(actions, null, 0x20);
|
checkOnArray(actions, null, 0x20);
|
||||||
|
|
||||||
// Test action disablement on array element location
|
// Test action disablement on array element location
|
||||||
|
@ -524,7 +524,7 @@ public class DataAction4Test extends AbstractDataActionTest {
|
||||||
|
|
||||||
waitForPostedSwingRunnables();
|
waitForPostedSwingRunnables();
|
||||||
|
|
||||||
actions = tool.getDockingActionsByOwnerName(plugin.getName());
|
actions = getActionsByOwner(tool, plugin.getName());
|
||||||
checkOnArray(actions, new ByteDataType(), 0x10);
|
checkOnArray(actions, new ByteDataType(), 0x10);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -541,7 +541,7 @@ public class DataAction4Test extends AbstractDataActionTest {
|
||||||
|
|
||||||
clearSelection();// Remove selection to allow array check to work
|
clearSelection();// Remove selection to allow array check to work
|
||||||
|
|
||||||
List<DockingActionIf> actions = tool.getDockingActionsByOwnerName(plugin.getName());
|
Set<DockingActionIf> actions = getActionsByOwner(tool, plugin.getName());
|
||||||
checkOnArray(actions, null, 0x20);
|
checkOnArray(actions, null, 0x20);
|
||||||
|
|
||||||
// Create Byte[0x10] array
|
// Create Byte[0x10] array
|
||||||
|
@ -555,7 +555,7 @@ public class DataAction4Test extends AbstractDataActionTest {
|
||||||
|
|
||||||
clearSelection();// Remove selection to allow array check to work
|
clearSelection();// Remove selection to allow array check to work
|
||||||
|
|
||||||
actions = tool.getDockingActionsByOwnerName(plugin.getName());
|
actions = getActionsByOwner(tool, plugin.getName());
|
||||||
checkOnArray(actions, new ByteDataType(), 0x10);
|
checkOnArray(actions, new ByteDataType(), 0x10);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -565,10 +565,7 @@ public class DataAction4Test extends AbstractDataActionTest {
|
||||||
|
|
||||||
gotoLocation(0x01006c00);
|
gotoLocation(0x01006c00);
|
||||||
|
|
||||||
List<DockingActionIf> actions =
|
DockingActionIf recentlyUsedAction = getAction(tool, plugin.getName(), RECENTLY_USED);
|
||||||
tool.getDockingActionsByFullActionName(RECENTLY_USED + " (" + plugin.getName() + ")");
|
|
||||||
assertEquals(1, actions.size());
|
|
||||||
DockingActionIf recentlyUsedAction = actions.get(0);
|
|
||||||
String caseName = "On Structure at: " + getCurrentLocation();
|
String caseName = "On Structure at: " + getCurrentLocation();
|
||||||
checkAction(recentlyUsedAction, false, caseName);
|
checkAction(recentlyUsedAction, false, caseName);
|
||||||
|
|
||||||
|
@ -591,7 +588,7 @@ public class DataAction4Test extends AbstractDataActionTest {
|
||||||
|
|
||||||
clearSelection();
|
clearSelection();
|
||||||
|
|
||||||
List<DockingActionIf> actions = tool.getDockingActionsByOwnerName(plugin.getName());
|
Set<DockingActionIf> actions = getActionsByOwner(tool, plugin.getName());
|
||||||
checkOnStructure(actions, 0x20);
|
checkOnStructure(actions, 0x20);
|
||||||
|
|
||||||
gotoLocation(0x01006c00);
|
gotoLocation(0x01006c00);
|
||||||
|
@ -708,14 +705,14 @@ public class DataAction4Test extends AbstractDataActionTest {
|
||||||
|
|
||||||
doAction(DEFINE_BYTE, true);
|
doAction(DEFINE_BYTE, true);
|
||||||
|
|
||||||
List<DockingActionIf> actions = tool.getDockingActionsByOwnerName(plugin.getName());
|
Set<DockingActionIf> actions = getActionsByOwner(tool, plugin.getName());
|
||||||
checkOnDefined(actions, ByteDataType.class);
|
checkOnDefined(actions, ByteDataType.class);
|
||||||
|
|
||||||
gotoLocation(0x01006a01, new int[] { 1 });
|
gotoLocation(0x01006a01, new int[] { 1 });
|
||||||
|
|
||||||
doAction(DEFINE_FLOAT, true);
|
doAction(DEFINE_FLOAT, true);
|
||||||
|
|
||||||
actions = tool.getDockingActionsByOwnerName(plugin.getName());
|
actions = getActionsByOwner(tool, plugin.getName());
|
||||||
checkOnDefined(actions, FloatDataType.class);
|
checkOnDefined(actions, FloatDataType.class);
|
||||||
|
|
||||||
Data pdata = getContextData().getParent();
|
Data pdata = getContextData().getParent();
|
||||||
|
@ -757,7 +754,7 @@ public class DataAction4Test extends AbstractDataActionTest {
|
||||||
|
|
||||||
waitForPostedSwingRunnables();
|
waitForPostedSwingRunnables();
|
||||||
|
|
||||||
List<DockingActionIf> actions = tool.getDockingActionsByOwnerName(plugin.getName());
|
Set<DockingActionIf> actions = getActionsByOwner(tool, plugin.getName());
|
||||||
checkOnArray(actions, structDt, 5);
|
checkOnArray(actions, structDt, 5);
|
||||||
|
|
||||||
// Expand structure
|
// Expand structure
|
||||||
|
@ -772,14 +769,14 @@ public class DataAction4Test extends AbstractDataActionTest {
|
||||||
|
|
||||||
doAction(DEFINE_BYTE, true);
|
doAction(DEFINE_BYTE, true);
|
||||||
|
|
||||||
actions = tool.getDockingActionsByOwnerName(plugin.getName());
|
actions = getActionsByOwner(tool, plugin.getName());
|
||||||
checkOnDefined(actions, ByteDataType.class);
|
checkOnDefined(actions, ByteDataType.class);
|
||||||
|
|
||||||
gotoLocation(0x01006a01, new int[] { 0, 1 });
|
gotoLocation(0x01006a01, new int[] { 0, 1 });
|
||||||
|
|
||||||
doAction(DEFINE_FLOAT, true);
|
doAction(DEFINE_FLOAT, true);
|
||||||
|
|
||||||
actions = tool.getDockingActionsByOwnerName(plugin.getName());
|
actions = getActionsByOwner(tool, plugin.getName());
|
||||||
checkOnDefined(actions, FloatDataType.class);
|
checkOnDefined(actions, FloatDataType.class);
|
||||||
|
|
||||||
Data pdata = getContextData().getParent();
|
Data pdata = getContextData().getParent();
|
||||||
|
|
|
@ -37,7 +37,7 @@ import org.junit.*;
|
||||||
import docking.DockingUtils;
|
import docking.DockingUtils;
|
||||||
import docking.action.DockingActionIf;
|
import docking.action.DockingActionIf;
|
||||||
import docking.action.ToggleDockingActionIf;
|
import docking.action.ToggleDockingActionIf;
|
||||||
import docking.util.KeyBindingUtils;
|
import docking.actions.KeyBindingUtils;
|
||||||
import docking.widgets.OptionDialog;
|
import docking.widgets.OptionDialog;
|
||||||
import docking.widgets.combobox.GhidraComboBox;
|
import docking.widgets.combobox.GhidraComboBox;
|
||||||
import docking.widgets.dialogs.InputWithChoicesDialog;
|
import docking.widgets.dialogs.InputWithChoicesDialog;
|
||||||
|
|
|
@ -17,7 +17,7 @@ package ghidra.app.plugin.core.equate;
|
||||||
|
|
||||||
import static org.junit.Assert.*;
|
import static org.junit.Assert.*;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.Set;
|
||||||
|
|
||||||
import javax.swing.JTextField;
|
import javax.swing.JTextField;
|
||||||
|
|
||||||
|
@ -115,11 +115,10 @@ public abstract class AbstractEquatePluginTest extends AbstractProgramBasedTest
|
||||||
|
|
||||||
// for selection containing a function stack address
|
// for selection containing a function stack address
|
||||||
builder.setBytes("0x01004bbd", "c2 08 00"); // return of previous function
|
builder.setBytes("0x01004bbd", "c2 08 00"); // return of previous function
|
||||||
builder.setBytes("0x01004bc0",
|
builder.setBytes("0x01004bc0", "53 8b 5c 24 08 56 8b 35 b8 10 00 01 57 ff 35 78 80 00 01 " +
|
||||||
"53 8b 5c 24 08 56 8b 35 b8 10 00 01 57 ff 35 78 80 00 01 " +
|
"53 ff d6 8b 3d e0 10 00 01 53 ff d7 8d 5c 43 02 68 9c 13 00 01 53 ff d6 53 ff d7 " +
|
||||||
"53 ff d6 8b 3d e0 10 00 01 53 ff d7 8d 5c 43 02 68 9c 13 00 01 53 ff d6 53 ff d7 " +
|
"ff 35 7c 80 00 01 8d 5c 43 02 53 ff d6 53 ff d7 8d 5c 43 02 68 e0 17 00 01 53 ff " +
|
||||||
"ff 35 7c 80 00 01 8d 5c 43 02 53 ff d6 53 ff d7 8d 5c 43 02 68 e0 17 00 01 53 ff " +
|
"d6 53 ff d7 66 83 64 43 02 00 8d 44 43 02 5f 5e 5b c2 04 00");
|
||||||
"d6 53 ff d7 66 83 64 43 02 00 8d 44 43 02 5f 5e 5b c2 04 00");
|
|
||||||
builder.disassemble(new AddressSet(builder.getProgram(), builder.addr("0x01004bc0"),
|
builder.disassemble(new AddressSet(builder.getProgram(), builder.addr("0x01004bc0"),
|
||||||
builder.addr("0x01004c1a")), true);
|
builder.addr("0x01004c1a")), true);
|
||||||
builder.createFunction("0x01004bc0");
|
builder.createFunction("0x01004bc0");
|
||||||
|
@ -203,8 +202,6 @@ public abstract class AbstractEquatePluginTest extends AbstractProgramBasedTest
|
||||||
env.dispose();
|
env.dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
//=================================================================================================
|
//=================================================================================================
|
||||||
// Private Methods
|
// Private Methods
|
||||||
//=================================================================================================
|
//=================================================================================================
|
||||||
|
@ -218,8 +215,7 @@ public abstract class AbstractEquatePluginTest extends AbstractProgramBasedTest
|
||||||
ComponentProvider provider = tool.getComponentProvider(PluginConstants.CODE_BROWSER);
|
ComponentProvider provider = tool.getComponentProvider(PluginConstants.CODE_BROWSER);
|
||||||
DockingActionIf action = getAction(equatePlugin, "Apply Enum");
|
DockingActionIf action = getAction(equatePlugin, "Apply Enum");
|
||||||
performAction(action, provider, false);
|
performAction(action, provider, false);
|
||||||
ApplyEnumDialog d =
|
ApplyEnumDialog d = waitForDialogComponent(ApplyEnumDialog.class);
|
||||||
waitForDialogComponent(tool.getToolFrame(), ApplyEnumDialog.class, DEFAULT_WAIT_DELAY);
|
|
||||||
return d;
|
return d;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -231,7 +227,7 @@ public abstract class AbstractEquatePluginTest extends AbstractProgramBasedTest
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void assertConvertActionsInPopup(boolean inPopup) {
|
protected void assertConvertActionsInPopup(boolean inPopup) {
|
||||||
List<DockingActionIf> actions = tool.getDockingActionsByOwnerName("EquatePlugin");
|
Set<DockingActionIf> actions = getActionsByOwner(tool, "EquatePlugin");
|
||||||
for (DockingActionIf action : actions) {
|
for (DockingActionIf action : actions) {
|
||||||
String actionName = action.getName();
|
String actionName = action.getName();
|
||||||
if (actionName.startsWith("Convert")) {
|
if (actionName.startsWith("Convert")) {
|
||||||
|
@ -242,7 +238,7 @@ public abstract class AbstractEquatePluginTest extends AbstractProgramBasedTest
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void assertNonFloatConvertActionsInPopup() {
|
protected void assertNonFloatConvertActionsInPopup() {
|
||||||
List<DockingActionIf> actions = tool.getDockingActionsByOwnerName("EquatePlugin");
|
Set<DockingActionIf> actions = getActionsByOwner(tool, "EquatePlugin");
|
||||||
for (DockingActionIf action : actions) {
|
for (DockingActionIf action : actions) {
|
||||||
String actionName = action.getName();
|
String actionName = action.getName();
|
||||||
if (actionName.startsWith("Convert")) {
|
if (actionName.startsWith("Convert")) {
|
||||||
|
@ -255,7 +251,7 @@ public abstract class AbstractEquatePluginTest extends AbstractProgramBasedTest
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void assertConvertNonCharNonSignedActionsInPopup() {
|
protected void assertConvertNonCharNonSignedActionsInPopup() {
|
||||||
List<DockingActionIf> actions = tool.getDockingActionsByOwnerName("EquatePlugin");
|
Set<DockingActionIf> actions = getActionsByOwner(tool, "EquatePlugin");
|
||||||
for (DockingActionIf element : actions) {
|
for (DockingActionIf element : actions) {
|
||||||
String name = element.getName();
|
String name = element.getName();
|
||||||
if (name.startsWith("Convert") &&
|
if (name.startsWith("Convert") &&
|
||||||
|
@ -266,7 +262,7 @@ public abstract class AbstractEquatePluginTest extends AbstractProgramBasedTest
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void assertConvertNonSignedActionsInPopup() {
|
protected void assertConvertNonSignedActionsInPopup() {
|
||||||
List<DockingActionIf> actions = tool.getDockingActionsByOwnerName("EquatePlugin");
|
Set<DockingActionIf> actions = getActionsByOwner(tool, "EquatePlugin");
|
||||||
for (DockingActionIf action : actions) {
|
for (DockingActionIf action : actions) {
|
||||||
String name = action.getName();
|
String name = action.getName();
|
||||||
if (name.startsWith("Convert") && name.indexOf("Signed") < 0) {
|
if (name.startsWith("Convert") && name.indexOf("Signed") < 0) {
|
||||||
|
|
|
@ -19,6 +19,7 @@ import static org.junit.Assert.*;
|
||||||
|
|
||||||
import java.lang.reflect.InvocationTargetException;
|
import java.lang.reflect.InvocationTargetException;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
import javax.swing.*;
|
import javax.swing.*;
|
||||||
import javax.swing.table.TableModel;
|
import javax.swing.table.TableModel;
|
||||||
|
@ -841,7 +842,7 @@ public class EquatePlugin1Test extends AbstractEquatePluginTest {
|
||||||
|
|
||||||
putCursorOnOperand(0x010064ae, 1);
|
putCursorOnOperand(0x010064ae, 1);
|
||||||
|
|
||||||
List<DockingActionIf> actions = tool.getDockingActionsByOwnerName("EquatePlugin");
|
Set<DockingActionIf> actions = getActionsByOwner(tool, "EquatePlugin");
|
||||||
int found = 0;
|
int found = 0;
|
||||||
for (DockingActionIf action : actions) {
|
for (DockingActionIf action : actions) {
|
||||||
String name = action.getName();
|
String name = action.getName();
|
||||||
|
@ -892,7 +893,7 @@ public class EquatePlugin1Test extends AbstractEquatePluginTest {
|
||||||
putCursorOnOperand(0x010064a3, 0);
|
putCursorOnOperand(0x010064a3, 0);
|
||||||
|
|
||||||
int found = 0;
|
int found = 0;
|
||||||
List<DockingActionIf> actions = tool.getDockingActionsByOwnerName("EquatePlugin");
|
Set<DockingActionIf> actions = getActionsByOwner(tool, "EquatePlugin");
|
||||||
for (DockingActionIf action : actions) {
|
for (DockingActionIf action : actions) {
|
||||||
String name = action.getName();
|
String name = action.getName();
|
||||||
if (!name.startsWith("Convert") || !action.isAddToPopup(getListingContext())) {
|
if (!name.startsWith("Convert") || !action.isAddToPopup(getListingContext())) {
|
||||||
|
@ -944,7 +945,7 @@ public class EquatePlugin1Test extends AbstractEquatePluginTest {
|
||||||
putCursorOnOperand(0x01003a94, 0);
|
putCursorOnOperand(0x01003a94, 0);
|
||||||
|
|
||||||
int found = 0;
|
int found = 0;
|
||||||
List<DockingActionIf> actions = tool.getDockingActionsByOwnerName("EquatePlugin");
|
Set<DockingActionIf> actions = getActionsByOwner(tool, "EquatePlugin");
|
||||||
for (DockingActionIf action : actions) {
|
for (DockingActionIf action : actions) {
|
||||||
String name = action.getName();
|
String name = action.getName();
|
||||||
if (!name.startsWith("Convert") || !action.isAddToPopup(getListingContext())) {
|
if (!name.startsWith("Convert") || !action.isAddToPopup(getListingContext())) {
|
||||||
|
|
|
@ -17,7 +17,7 @@ package ghidra.app.plugin.core.fallthrough;
|
||||||
|
|
||||||
import static org.junit.Assert.assertEquals;
|
import static org.junit.Assert.assertEquals;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.Set;
|
||||||
|
|
||||||
import org.junit.*;
|
import org.junit.*;
|
||||||
|
|
||||||
|
@ -37,7 +37,8 @@ import ghidra.program.util.ProgramLocation;
|
||||||
import ghidra.program.util.ProgramSelection;
|
import ghidra.program.util.ProgramSelection;
|
||||||
import ghidra.test.*;
|
import ghidra.test.*;
|
||||||
|
|
||||||
public class FallThroughActionTest extends AbstractGhidraHeadedIntegrationTest implements LocationCallback {
|
public class FallThroughActionTest extends AbstractGhidraHeadedIntegrationTest
|
||||||
|
implements LocationCallback {
|
||||||
private Program program;
|
private Program program;
|
||||||
private TestEnv env;
|
private TestEnv env;
|
||||||
private PluginTool tool;
|
private PluginTool tool;
|
||||||
|
@ -70,7 +71,7 @@ public class FallThroughActionTest extends AbstractGhidraHeadedIntegrationTest i
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testNotepadLocations() {
|
public void testNotepadLocations() {
|
||||||
List<DockingActionIf> actions = tool.getDockingActionsByOwnerName(plugin.getName());
|
Set<DockingActionIf> actions = getActionsByOwner(tool, plugin.getName());
|
||||||
checkAction(actions, AUTO_OVERRIDE, false, "Start");
|
checkAction(actions, AUTO_OVERRIDE, false, "Start");
|
||||||
checkAction(actions, CLEAR_FALLTHROUGH, false, "Start");
|
checkAction(actions, CLEAR_FALLTHROUGH, false, "Start");
|
||||||
|
|
||||||
|
@ -96,7 +97,7 @@ public class FallThroughActionTest extends AbstractGhidraHeadedIntegrationTest i
|
||||||
new ProgramSelectionPluginEvent("Test", selection, program);
|
new ProgramSelectionPluginEvent("Test", selection, program);
|
||||||
tool.firePluginEvent(ev);
|
tool.firePluginEvent(ev);
|
||||||
|
|
||||||
List<DockingActionIf> actions = tool.getDockingActionsByOwnerName(plugin.getName());
|
Set<DockingActionIf> actions = getActionsByOwner(tool, plugin.getName());
|
||||||
checkAction(actions, AUTO_OVERRIDE, true, "selection");
|
checkAction(actions, AUTO_OVERRIDE, true, "selection");
|
||||||
checkAction(actions, CLEAR_FALLTHROUGH, true, "selection");
|
checkAction(actions, CLEAR_FALLTHROUGH, true, "selection");
|
||||||
|
|
||||||
|
@ -110,7 +111,7 @@ public class FallThroughActionTest extends AbstractGhidraHeadedIntegrationTest i
|
||||||
@Override
|
@Override
|
||||||
public void locationGenerated(ProgramLocation loc) {
|
public void locationGenerated(ProgramLocation loc) {
|
||||||
tool.firePluginEvent(new ProgramLocationPluginEvent("test", loc, program));
|
tool.firePluginEvent(new ProgramLocationPluginEvent("test", loc, program));
|
||||||
List<DockingActionIf> actions = tool.getDockingActionsByOwnerName(plugin.getName());
|
Set<DockingActionIf> actions = getActionsByOwner(tool, plugin.getName());
|
||||||
|
|
||||||
ListingActionContext actionContext =
|
ListingActionContext actionContext =
|
||||||
(ListingActionContext) cb.getProvider().getActionContext(null);
|
(ListingActionContext) cb.getProvider().getActionContext(null);
|
||||||
|
@ -126,7 +127,7 @@ public class FallThroughActionTest extends AbstractGhidraHeadedIntegrationTest i
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void checkAction(List<DockingActionIf> actions, String name, boolean isValidContext,
|
private void checkAction(Set<DockingActionIf> actions, String name, boolean isValidContext,
|
||||||
String caseName) {
|
String caseName) {
|
||||||
for (DockingActionIf action : actions) {
|
for (DockingActionIf action : actions) {
|
||||||
String actionName = action.getName();
|
String actionName = action.getName();
|
||||||
|
|
|
@ -19,7 +19,7 @@ import static org.junit.Assert.*;
|
||||||
|
|
||||||
import java.awt.*;
|
import java.awt.*;
|
||||||
import java.awt.event.MouseEvent;
|
import java.awt.event.MouseEvent;
|
||||||
import java.util.List;
|
import java.util.Set;
|
||||||
|
|
||||||
import javax.swing.JTable;
|
import javax.swing.JTable;
|
||||||
import javax.swing.JTextField;
|
import javax.swing.JTextField;
|
||||||
|
@ -96,7 +96,7 @@ public class MemoryMapPluginTest extends AbstractGhidraHeadedIntegrationTest {
|
||||||
env.close(program);
|
env.close(program);
|
||||||
program = buildProgram("sdk");
|
program = buildProgram("sdk");
|
||||||
env.open(program);
|
env.open(program);
|
||||||
List<DockingActionIf> actions = tool.getDockingActionsByOwnerName(plugin.getName());
|
Set<DockingActionIf> actions = getActionsByOwner(tool, plugin.getName());
|
||||||
for (DockingActionIf action : actions) {
|
for (DockingActionIf action : actions) {
|
||||||
if (action.getName().equals("Add Block") || action.getName().equals("Set Image Base") ||
|
if (action.getName().equals("Add Block") || action.getName().equals("Set Image Base") ||
|
||||||
action.getName().equals("View Memory Map")) {
|
action.getName().equals("View Memory Map")) {
|
||||||
|
@ -114,7 +114,7 @@ public class MemoryMapPluginTest extends AbstractGhidraHeadedIntegrationTest {
|
||||||
env.close(program);
|
env.close(program);
|
||||||
JTable table = provider.getTable();
|
JTable table = provider.getTable();
|
||||||
assertEquals(0, table.getModel().getRowCount());
|
assertEquals(0, table.getModel().getRowCount());
|
||||||
List<DockingActionIf> actions = tool.getDockingActionsByOwnerName(plugin.getName());
|
Set<DockingActionIf> actions = getActionsByOwner(tool, plugin.getName());
|
||||||
for (DockingActionIf action : actions) {
|
for (DockingActionIf action : actions) {
|
||||||
if (!action.getName().equals("View Memory Map")) {
|
if (!action.getName().equals("View Memory Map")) {
|
||||||
assertTrue(!action.isEnabledForContext(provider.getActionContext(null)));
|
assertTrue(!action.isEnabledForContext(provider.getActionContext(null)));
|
||||||
|
|
|
@ -19,7 +19,6 @@ import static org.junit.Assert.*;
|
||||||
|
|
||||||
import java.awt.*;
|
import java.awt.*;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import javax.swing.*;
|
import javax.swing.*;
|
||||||
import javax.swing.table.JTableHeader;
|
import javax.swing.table.JTableHeader;
|
||||||
|
@ -117,7 +116,7 @@ public class MemoryMapProvider1Test extends AbstractGhidraHeadedIntegrationTest
|
||||||
// select first row
|
// select first row
|
||||||
// all actions except "merge" should be enabled
|
// all actions except "merge" should be enabled
|
||||||
table.addRowSelectionInterval(0, 0);
|
table.addRowSelectionInterval(0, 0);
|
||||||
List<DockingActionIf> actions = tool.getDockingActionsByOwnerName(plugin.getName());
|
Set<DockingActionIf> actions = getActionsByOwner(tool, plugin.getName());
|
||||||
for (DockingActionIf action : actions) {
|
for (DockingActionIf action : actions) {
|
||||||
if (action.getName().equals("Merge Blocks")) {
|
if (action.getName().equals("Merge Blocks")) {
|
||||||
assertTrue(!action.isEnabled());
|
assertTrue(!action.isEnabled());
|
||||||
|
@ -133,7 +132,7 @@ public class MemoryMapProvider1Test extends AbstractGhidraHeadedIntegrationTest
|
||||||
|
|
||||||
table.addRowSelectionInterval(0, 1);
|
table.addRowSelectionInterval(0, 1);
|
||||||
assertEquals(2, table.getSelectedRowCount());
|
assertEquals(2, table.getSelectedRowCount());
|
||||||
List<DockingActionIf> actions = tool.getDockingActionsByOwnerName(plugin.getName());
|
Set<DockingActionIf> actions = getActionsByOwner(tool, plugin.getName());
|
||||||
for (DockingActionIf action : actions) {
|
for (DockingActionIf action : actions) {
|
||||||
String name = action.getName();
|
String name = action.getName();
|
||||||
if (name.equals("Add Block") || name.equals("Merge Blocks") ||
|
if (name.equals("Add Block") || name.equals("Merge Blocks") ||
|
||||||
|
|
|
@ -18,8 +18,7 @@ package ghidra.app.plugin.core.module;
|
||||||
import static org.junit.Assert.assertEquals;
|
import static org.junit.Assert.assertEquals;
|
||||||
import static org.junit.Assert.assertTrue;
|
import static org.junit.Assert.assertTrue;
|
||||||
|
|
||||||
import java.util.Arrays;
|
import java.util.*;
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import org.junit.*;
|
import org.junit.*;
|
||||||
|
|
||||||
|
@ -42,7 +41,7 @@ public class ModuleSortPluginTest extends AbstractGhidraHeadedIntegrationTest {
|
||||||
private PluginTool tool;
|
private PluginTool tool;
|
||||||
private Program program;
|
private Program program;
|
||||||
private ModuleSortPlugin plugin;
|
private ModuleSortPlugin plugin;
|
||||||
private List<DockingActionIf> actions;
|
private Set<DockingActionIf> actions;
|
||||||
private ProgramTreeService service;
|
private ProgramTreeService service;
|
||||||
|
|
||||||
public ModuleSortPluginTest() {
|
public ModuleSortPluginTest() {
|
||||||
|
@ -63,7 +62,7 @@ public class ModuleSortPluginTest extends AbstractGhidraHeadedIntegrationTest {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
actions = tool.getDockingActionsByOwnerName(plugin.getName());
|
actions = getActionsByOwner(tool, plugin.getName());
|
||||||
service = tool.getService(ProgramTreeService.class);
|
service = tool.getService(ProgramTreeService.class);
|
||||||
|
|
||||||
ProgramBuilder builder = new ProgramBuilder("notepad", ProgramBuilder._TOY);
|
ProgramBuilder builder = new ProgramBuilder("notepad", ProgramBuilder._TOY);
|
||||||
|
|
|
@ -17,8 +17,7 @@ package ghidra.app.plugin.core.navigation;
|
||||||
|
|
||||||
import static org.junit.Assert.*;
|
import static org.junit.Assert.*;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.*;
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import javax.swing.*;
|
import javax.swing.*;
|
||||||
|
|
||||||
|
@ -65,7 +64,7 @@ import ghidra.util.Msg;
|
||||||
import ghidra.util.table.GhidraProgramTableModel;
|
import ghidra.util.table.GhidraProgramTableModel;
|
||||||
import ghidra.util.table.field.LabelTableColumn;
|
import ghidra.util.table.field.LabelTableColumn;
|
||||||
import ghidra.util.task.TaskMonitor;
|
import ghidra.util.task.TaskMonitor;
|
||||||
import ghidra.util.task.TaskMonitorAdapter;
|
import util.CollectionUtils;
|
||||||
|
|
||||||
public class GoToPluginTest extends AbstractGhidraHeadedIntegrationTest {
|
public class GoToPluginTest extends AbstractGhidraHeadedIntegrationTest {
|
||||||
private TestEnv env;
|
private TestEnv env;
|
||||||
|
@ -104,20 +103,20 @@ public class GoToPluginTest extends AbstractGhidraHeadedIntegrationTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testActionEnablement() throws Exception {
|
public void testActionEnablement() throws Exception {
|
||||||
List<DockingActionIf> actions = tool.getDockingActionsByOwnerName(plugin.getName());
|
Set<DockingActionIf> actions = getActionsByOwner(tool, plugin.getName());
|
||||||
assertEquals(1, actions.size());
|
assertEquals(1, actions.size());
|
||||||
assertEquals("Go To Address/Label", actions.get(0).getName());
|
assertEquals("Go To Address/Label", CollectionUtils.any(actions).getName());
|
||||||
ActionContext actionContext = getActionContext();
|
ActionContext actionContext = getActionContext();
|
||||||
assertTrue(!actions.get(0).isEnabledForContext(actionContext));
|
assertTrue(!CollectionUtils.any(actions).isEnabledForContext(actionContext));
|
||||||
|
|
||||||
loadProgram("x86");
|
loadProgram("x86");
|
||||||
|
|
||||||
actionContext = getActionContext();
|
actionContext = getActionContext();
|
||||||
assertTrue(actions.get(0).isEnabledForContext(actionContext));
|
assertTrue(CollectionUtils.any(actions).isEnabledForContext(actionContext));
|
||||||
final ProgramManager pm = tool.getService(ProgramManager.class);
|
final ProgramManager pm = tool.getService(ProgramManager.class);
|
||||||
SwingUtilities.invokeAndWait(() -> pm.closeProgram(program, true));
|
runSwing(() -> pm.closeProgram(program, true));
|
||||||
actionContext = getActionContext();
|
actionContext = getActionContext();
|
||||||
assertTrue(!actions.get(0).isEnabledForContext(actionContext));
|
assertTrue(!CollectionUtils.any(actions).isEnabledForContext(actionContext));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -476,7 +475,7 @@ public class GoToPluginTest extends AbstractGhidraHeadedIntegrationTest {
|
||||||
performOkCallback();
|
performOkCallback();
|
||||||
|
|
||||||
assertEquals("No results for xyzabc*", dialog.getStatusText());
|
assertEquals("No results for xyzabc*", dialog.getStatusText());
|
||||||
SwingUtilities.invokeAndWait(() -> dialog.close());
|
runSwing(() -> dialog.close());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -561,7 +560,7 @@ public class GoToPluginTest extends AbstractGhidraHeadedIntegrationTest {
|
||||||
program.endTransaction(transactionID, true);
|
program.endTransaction(transactionID, true);
|
||||||
final JCheckBox cb = findComponent(dialog, JCheckBox.class);
|
final JCheckBox cb = findComponent(dialog, JCheckBox.class);
|
||||||
|
|
||||||
SwingUtilities.invokeAndWait(() -> {
|
runSwing(() -> {
|
||||||
cb.setSelected(false);
|
cb.setSelected(false);
|
||||||
dialog.setText("COm*");
|
dialog.setText("COm*");
|
||||||
|
|
||||||
|
@ -831,7 +830,7 @@ public class GoToPluginTest extends AbstractGhidraHeadedIntegrationTest {
|
||||||
Assert.assertNotNull(program);
|
Assert.assertNotNull(program);
|
||||||
|
|
||||||
final ProgramManager pm = tool.getService(ProgramManager.class);
|
final ProgramManager pm = tool.getService(ProgramManager.class);
|
||||||
SwingUtilities.invokeAndWait(() -> pm.openProgram(program.getDomainFile()));
|
runSwing(() -> pm.openProgram(program.getDomainFile()));
|
||||||
program.release(this);
|
program.release(this);
|
||||||
addrFactory = program.getAddressFactory();
|
addrFactory = program.getAddressFactory();
|
||||||
}
|
}
|
||||||
|
@ -965,7 +964,7 @@ public class GoToPluginTest extends AbstractGhidraHeadedIntegrationTest {
|
||||||
try {
|
try {
|
||||||
Memory memory = program.getMemory();
|
Memory memory = program.getMemory();
|
||||||
return memory.createInitializedBlock(name, addr(address), size, (byte) 0,
|
return memory.createInitializedBlock(name, addr(address), size, (byte) 0,
|
||||||
TaskMonitorAdapter.DUMMY_MONITOR, true);
|
TaskMonitor.DUMMY, true);
|
||||||
}
|
}
|
||||||
finally {
|
finally {
|
||||||
program.endTransaction(transactionID, true);
|
program.endTransaction(transactionID, true);
|
||||||
|
@ -1023,7 +1022,7 @@ public class GoToPluginTest extends AbstractGhidraHeadedIntegrationTest {
|
||||||
}
|
}
|
||||||
|
|
||||||
private void setText(final String text) throws Exception {
|
private void setText(final String text) throws Exception {
|
||||||
SwingUtilities.invokeAndWait(() -> dialog.setText(text));
|
runSwing(() -> dialog.setText(text));
|
||||||
}
|
}
|
||||||
|
|
||||||
private void performOkCallback() throws Exception {
|
private void performOkCallback() throws Exception {
|
||||||
|
@ -1035,17 +1034,7 @@ public class GoToPluginTest extends AbstractGhidraHeadedIntegrationTest {
|
||||||
}
|
}
|
||||||
|
|
||||||
private void waitForOKCallback() {
|
private void waitForOKCallback() {
|
||||||
int numWaits = 0;
|
waitForCondition(() -> runSwing(() -> okButton.isEnabled()));
|
||||||
while (++numWaits < 50 && !okButton.isEnabled()) {
|
|
||||||
try {
|
|
||||||
Thread.sleep(100);
|
|
||||||
}
|
|
||||||
catch (InterruptedException e) {
|
|
||||||
// no biggie, will try again
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Assert.assertNotEquals("Timed-out waiting for Go To dialog to finish", 50, numWaits);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void assumeCurrentAddressSpace(boolean b) {
|
private void assumeCurrentAddressSpace(boolean b) {
|
||||||
|
|
|
@ -20,8 +20,7 @@ import static org.junit.Assert.*;
|
||||||
import java.awt.Window;
|
import java.awt.Window;
|
||||||
import java.io.*;
|
import java.io.*;
|
||||||
import java.lang.reflect.InvocationTargetException;
|
import java.lang.reflect.InvocationTargetException;
|
||||||
import java.util.List;
|
import java.util.*;
|
||||||
import java.util.Map;
|
|
||||||
import java.util.concurrent.CountDownLatch;
|
import java.util.concurrent.CountDownLatch;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
import java.util.concurrent.atomic.AtomicInteger;
|
import java.util.concurrent.atomic.AtomicInteger;
|
||||||
|
@ -60,6 +59,7 @@ import ghidra.util.exception.CancelledException;
|
||||||
import ghidra.util.table.GhidraTable;
|
import ghidra.util.table.GhidraTable;
|
||||||
import ghidra.util.table.GhidraTableFilterPanel;
|
import ghidra.util.table.GhidraTableFilterPanel;
|
||||||
import ghidra.util.task.*;
|
import ghidra.util.task.*;
|
||||||
|
import util.CollectionUtils;
|
||||||
import utilities.util.FileUtilities;
|
import utilities.util.FileUtilities;
|
||||||
|
|
||||||
public abstract class AbstractGhidraScriptMgrPluginTest
|
public abstract class AbstractGhidraScriptMgrPluginTest
|
||||||
|
@ -272,10 +272,18 @@ public abstract class AbstractGhidraScriptMgrPluginTest
|
||||||
assertTrue(message, fullText.contains(piece));
|
assertTrue(message, fullText.contains(piece));
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void assertRunLastActionEnabled(boolean enabled) {
|
private DockingActionIf getRunLastScriptAction() {
|
||||||
final DockingActionIf runLastAction = getAction(plugin, "Rerun Last Script");
|
// note: this provider adds 2 versions of the same action--pick either
|
||||||
assertNotNull(runLastAction);
|
Set<DockingActionIf> actions =
|
||||||
|
getActionsByOwnerAndName(plugin.getTool(), plugin.getName(), "Rerun Last Script");
|
||||||
|
assertFalse(actions.isEmpty());
|
||||||
|
DockingActionIf runLastAction = CollectionUtils.any(actions);
|
||||||
|
return runLastAction;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void assertRunLastActionEnabled(boolean enabled) {
|
||||||
|
|
||||||
|
DockingActionIf runLastAction = getRunLastScriptAction();
|
||||||
final AtomicReference<Boolean> ref = new AtomicReference<>();
|
final AtomicReference<Boolean> ref = new AtomicReference<>();
|
||||||
runSwing(() -> ref.set(runLastAction.isEnabledForContext(new ActionContext())));
|
runSwing(() -> ref.set(runLastAction.isEnabledForContext(new ActionContext())));
|
||||||
assertEquals("Run Last Action not enabled as expected", enabled, ref.get());
|
assertEquals("Run Last Action not enabled as expected", enabled, ref.get());
|
||||||
|
@ -557,17 +565,15 @@ public abstract class AbstractGhidraScriptMgrPluginTest
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void pressRunLastScriptButton() {
|
protected void pressRunLastScriptButton() {
|
||||||
DockingActionIf action =
|
DockingActionIf runLastAction = getRunLastScriptAction();
|
||||||
getAction(plugin, GhidraScriptActionManager.RERUN_LAST_SHARED_ACTION_NAME);
|
performAction(runLastAction, false);
|
||||||
performAction(action, false);
|
|
||||||
waitForSwing();
|
waitForSwing();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void performGlobalRunLastScriptAction() {
|
protected void performGlobalRunLastScriptAction() {
|
||||||
DockingActionIf action =
|
// note: this action used to be different from the 'run last script'; currently they are
|
||||||
getAction(plugin, GhidraScriptActionManager.GLOBAL_RERUN_LAST_SHARED_ACTION_NAME);
|
// the same
|
||||||
performAction(action, false);
|
pressRunLastScriptButton();
|
||||||
waitForSwing();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected KeyBindingInputDialog pressKeyBindingAction() {
|
protected KeyBindingInputDialog pressKeyBindingAction() {
|
||||||
|
@ -1293,7 +1299,7 @@ public abstract class AbstractGhidraScriptMgrPluginTest
|
||||||
protected void assertToolKeyBinding(KeyStroke ks) {
|
protected void assertToolKeyBinding(KeyStroke ks) {
|
||||||
String actionOwner = GhidraScriptMgrPlugin.class.getSimpleName();
|
String actionOwner = GhidraScriptMgrPlugin.class.getSimpleName();
|
||||||
PluginTool tool = env.getTool();
|
PluginTool tool = env.getTool();
|
||||||
List<DockingActionIf> actions = tool.getDockingActionsByOwnerName(actionOwner);
|
Set<DockingActionIf> actions = getActionsByOwner(tool, actionOwner);
|
||||||
for (DockingActionIf action : actions) {
|
for (DockingActionIf action : actions) {
|
||||||
KeyStroke keyBinding = action.getKeyBinding();
|
KeyStroke keyBinding = action.getKeyBinding();
|
||||||
if (keyBinding == null) {
|
if (keyBinding == null) {
|
||||||
|
|
|
@ -684,8 +684,8 @@ public class SearchTextPlugin1Test extends AbstractGhidraHeadedIntegrationTest {
|
||||||
final GTable table = threadedTablePanel.getTable();
|
final GTable table = threadedTablePanel.getTable();
|
||||||
Random random = new Random();
|
Random random = new Random();
|
||||||
final int randomRow = random.nextInt(model.getRowCount());
|
final int randomRow = random.nextInt(model.getRowCount());
|
||||||
DockingActionIf deleteRowAction =
|
|
||||||
tool.getDockingActionsByFullActionName("Remove Items (TableServicePlugin)").get(0);
|
DockingActionIf deleteRowAction = getAction(tool, "TableServicePlugin", "Remove Items");
|
||||||
ProgramLocation toBeDeleted = model.getRowObject(randomRow);
|
ProgramLocation toBeDeleted = model.getRowObject(randomRow);
|
||||||
runSwing(() -> table.setRowSelectionInterval(randomRow, randomRow));
|
runSwing(() -> table.setRowSelectionInterval(randomRow, randomRow));
|
||||||
performAction(deleteRowAction, true);
|
performAction(deleteRowAction, true);
|
||||||
|
|
|
@ -1306,11 +1306,8 @@ public class SymbolTablePluginTest extends AbstractGhidraHeadedIntegrationTest {
|
||||||
|
|
||||||
private void setupSymbolTableFilterToShowParameters() throws Exception {
|
private void setupSymbolTableFilterToShowParameters() throws Exception {
|
||||||
// get the filter action - "Set Filter"
|
// get the filter action - "Set Filter"
|
||||||
List<DockingActionIf> actions =
|
|
||||||
tool.getDockingActionsByFullActionName("Set Filter (SymbolTablePlugin)");
|
DockingActionIf filterAction = getAction(tool, "SymbolTablePlugin", "Set Filter");
|
||||||
assertNotNull(actions);
|
|
||||||
assertTrue(actions.size() > 0);
|
|
||||||
DockingActionIf filterAction = actions.get(0);
|
|
||||||
|
|
||||||
// execute
|
// execute
|
||||||
performAction(filterAction, false);
|
performAction(filterAction, false);
|
||||||
|
|
|
@ -30,6 +30,7 @@ import org.junit.*;
|
||||||
|
|
||||||
import docking.ActionContext;
|
import docking.ActionContext;
|
||||||
import docking.action.DockingActionIf;
|
import docking.action.DockingActionIf;
|
||||||
|
import docking.test.AbstractDockingTest;
|
||||||
import docking.widgets.OptionDialog;
|
import docking.widgets.OptionDialog;
|
||||||
import docking.widgets.tree.GTreeNode;
|
import docking.widgets.tree.GTreeNode;
|
||||||
import docking.widgets.tree.GTreeRootNode;
|
import docking.widgets.tree.GTreeRootNode;
|
||||||
|
@ -596,10 +597,9 @@ public class ActionManager1Test extends AbstractGhidraHeadedIntegrationTest {
|
||||||
}
|
}
|
||||||
|
|
||||||
private DockingActionIf getAction(String actionName) {
|
private DockingActionIf getAction(String actionName) {
|
||||||
List<DockingActionIf> a =
|
DockingActionIf action =
|
||||||
frontEndTool.getDockingActionsByFullActionName(actionName + " (FrontEndPlugin)");
|
AbstractDockingTest.getAction(frontEndTool, "FrontEndPlugin", actionName);
|
||||||
Assert.assertEquals(1, a.size());
|
return action;
|
||||||
return a.get(0);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void expandTreePath(TreePath path) {
|
private void expandTreePath(TreePath path) {
|
||||||
|
|
|
@ -30,6 +30,7 @@ import org.junit.*;
|
||||||
import docking.ActionContext;
|
import docking.ActionContext;
|
||||||
import docking.action.DockingActionIf;
|
import docking.action.DockingActionIf;
|
||||||
import docking.action.ToggleDockingAction;
|
import docking.action.ToggleDockingAction;
|
||||||
|
import docking.test.AbstractDockingTest;
|
||||||
import docking.widgets.OptionDialog;
|
import docking.widgets.OptionDialog;
|
||||||
import docking.widgets.tree.GTreeNode;
|
import docking.widgets.tree.GTreeNode;
|
||||||
import docking.widgets.tree.GTreeRootNode;
|
import docking.widgets.tree.GTreeRootNode;
|
||||||
|
@ -60,10 +61,6 @@ public class ActionManager2Test extends AbstractGhidraHeadedIntegrationTest {
|
||||||
private DomainFolder rootFolder;
|
private DomainFolder rootFolder;
|
||||||
private GTreeRootNode rootNode;
|
private GTreeRootNode rootNode;
|
||||||
|
|
||||||
public ActionManager2Test() {
|
|
||||||
super();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Before
|
@Before
|
||||||
public void setUp() throws Exception {
|
public void setUp() throws Exception {
|
||||||
env = new TestEnv();
|
env = new TestEnv();
|
||||||
|
@ -363,10 +360,9 @@ public class ActionManager2Test extends AbstractGhidraHeadedIntegrationTest {
|
||||||
}
|
}
|
||||||
|
|
||||||
private DockingActionIf getAction(String actionName) {
|
private DockingActionIf getAction(String actionName) {
|
||||||
List<DockingActionIf> a =
|
DockingActionIf action =
|
||||||
frontEndTool.getDockingActionsByFullActionName(actionName + " (FrontEndPlugin)");
|
AbstractDockingTest.getAction(frontEndTool, "FrontEndPlugin", actionName);
|
||||||
assertEquals(1, a.size());
|
return action;
|
||||||
return a.get(0);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void setSelectionPath(final TreePath path) throws Exception {
|
private void setSelectionPath(final TreePath path) throws Exception {
|
||||||
|
|
|
@ -30,10 +30,10 @@ import javax.swing.tree.TreePath;
|
||||||
import org.junit.*;
|
import org.junit.*;
|
||||||
|
|
||||||
import docking.action.DockingActionIf;
|
import docking.action.DockingActionIf;
|
||||||
|
import docking.actions.KeyBindingUtils;
|
||||||
import docking.options.editor.OptionsDialog;
|
import docking.options.editor.OptionsDialog;
|
||||||
import docking.options.editor.OptionsPanel;
|
import docking.options.editor.OptionsPanel;
|
||||||
import docking.tool.util.DockingToolConstants;
|
import docking.tool.util.DockingToolConstants;
|
||||||
import docking.util.KeyBindingUtils;
|
|
||||||
import docking.widgets.filechooser.GhidraFileChooser;
|
import docking.widgets.filechooser.GhidraFileChooser;
|
||||||
import docking.widgets.tree.GTree;
|
import docking.widgets.tree.GTree;
|
||||||
import generic.io.NullWriter;
|
import generic.io.NullWriter;
|
||||||
|
@ -228,13 +228,13 @@ public class KeyBindingUtilsTest extends AbstractGhidraHeadedIntegrationTest {
|
||||||
// import the original values file through the tool
|
// import the original values file through the tool
|
||||||
importOptionsWithGUI(saveFile, true);
|
importOptionsWithGUI(saveFile, true);
|
||||||
// get the updated values that have not been applied
|
// get the updated values that have not been applied
|
||||||
Map<?, ?> optionsMap = (Map<?, ?>) getInstanceField("actionMap", panel);
|
Map<String, KeyStroke> keyStrokeMap = panel.getKeyStrokeMap();
|
||||||
|
|
||||||
debug("f");
|
debug("f");
|
||||||
|
|
||||||
// verify the data is the same as it was before the changes
|
// verify the data is the same as it was before the changes
|
||||||
boolean same = compareOptionsWithKeyStrokeMap(originalOptions, optionsMap);
|
boolean same = compareOptionsWithKeyStrokeMap(originalOptions, keyStrokeMap);
|
||||||
assertTrue("The Options object contains different data than was " + "imported.", same);
|
assertTrue("The Options object contains different data than was imported.", same);
|
||||||
|
|
||||||
debug("g");
|
debug("g");
|
||||||
|
|
||||||
|
@ -405,26 +405,26 @@ public class KeyBindingUtilsTest extends AbstractGhidraHeadedIntegrationTest {
|
||||||
}
|
}
|
||||||
|
|
||||||
private void setKeyBinding(String keyText, int keyCode) throws Exception {
|
private void setKeyBinding(String keyText, int keyCode) throws Exception {
|
||||||
List<DockingActionIf> list = tool.getAllActions();
|
Set<DockingActionIf> list = tool.getAllActions();
|
||||||
DockingActionIf action = null;
|
DockingActionIf arbitraryAction = null;
|
||||||
for (int i = 0; i < list.size(); i++) {
|
for (DockingActionIf action : list) {
|
||||||
action = list.get(i);
|
|
||||||
if (action.isKeyBindingManaged() && action.getKeyBinding() == null) {
|
if (action.isKeyBindingManaged() && action.getKeyBinding() == null) {
|
||||||
|
arbitraryAction = action;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (action == null) {
|
if (arbitraryAction == null) {
|
||||||
Assert.fail("Unable to find an action for which to set a key binding.");
|
Assert.fail("Unable to find an action for which to set a key binding.");
|
||||||
}
|
}
|
||||||
|
|
||||||
selectRowForAction(action);
|
selectRowForAction(arbitraryAction);
|
||||||
triggerText(keyField, keyText);
|
triggerText(keyField, keyText);
|
||||||
|
|
||||||
assertEquals(keyText.toUpperCase(), keyField.getText());
|
assertEquals(keyText.toUpperCase(), keyField.getText());
|
||||||
|
|
||||||
runSwing(() -> panel.apply());
|
runSwing(() -> panel.apply());
|
||||||
assertEquals(KeyStroke.getKeyStroke(keyCode, 0), action.getKeyBinding());
|
assertEquals(KeyStroke.getKeyStroke(keyCode, 0), arbitraryAction.getKeyBinding());
|
||||||
}
|
}
|
||||||
|
|
||||||
private void selectRowForAction(DockingActionIf action) throws Exception {
|
private void selectRowForAction(DockingActionIf action) throws Exception {
|
||||||
|
@ -533,20 +533,19 @@ public class KeyBindingUtilsTest extends AbstractGhidraHeadedIntegrationTest {
|
||||||
// compares the provided options with the mapping of property names to
|
// compares the provided options with the mapping of property names to
|
||||||
// keystrokes (the map is obtained from the key bindings panel after an
|
// keystrokes (the map is obtained from the key bindings panel after an
|
||||||
// import is done).
|
// import is done).
|
||||||
private boolean compareOptionsWithKeyStrokeMap(Options options, Map<?, ?> optionsMap) {
|
private boolean compareOptionsWithKeyStrokeMap(Options options,
|
||||||
|
Map<String, KeyStroke> panelKeyStrokeMap) {
|
||||||
List<String> propertyNames = options.getOptionNames();
|
List<String> propertyNames = options.getOptionNames();
|
||||||
for (String element : propertyNames) {
|
for (String element : propertyNames) {
|
||||||
boolean match = optionsMap.containsKey(element);
|
boolean match = panelKeyStrokeMap.containsKey(element);
|
||||||
|
|
||||||
Object value = invokeInstanceMethod("getKeyStroke", options,
|
KeyStroke optionsKs = options.getKeyStroke(element, null);
|
||||||
new Class[] { String.class, KeyStroke.class }, new Object[] { element, null });
|
KeyStroke panelKs = panelKeyStrokeMap.get(element);
|
||||||
Object value2 = optionsMap.get(element);
|
|
||||||
|
|
||||||
// if the value is null, then it would not have been placed into the
|
// if the value is null, then it would not have been placed into the options map
|
||||||
// options map in the key bindings panel, so we only care about
|
// in the key bindings panel, so we only care about non-null values
|
||||||
// non-null values
|
if (optionsKs != null) {
|
||||||
if (value != null) {
|
match &= (optionsKs.equals(panelKs));
|
||||||
match &= (value.equals(value2));
|
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
match = true;
|
match = true;
|
||||||
|
|
|
@ -20,7 +20,7 @@ import static org.junit.Assert.*;
|
||||||
import java.awt.Rectangle;
|
import java.awt.Rectangle;
|
||||||
import java.awt.event.InputEvent;
|
import java.awt.event.InputEvent;
|
||||||
import java.awt.event.KeyEvent;
|
import java.awt.event.KeyEvent;
|
||||||
import java.util.List;
|
import java.util.Set;
|
||||||
|
|
||||||
import javax.swing.*;
|
import javax.swing.*;
|
||||||
import javax.swing.table.*;
|
import javax.swing.table.*;
|
||||||
|
@ -29,10 +29,10 @@ import org.junit.*;
|
||||||
|
|
||||||
import docking.KeyEntryTextField;
|
import docking.KeyEntryTextField;
|
||||||
import docking.action.DockingActionIf;
|
import docking.action.DockingActionIf;
|
||||||
|
import docking.tool.util.DockingToolConstants;
|
||||||
import docking.widgets.MultiLineLabel;
|
import docking.widgets.MultiLineLabel;
|
||||||
import ghidra.app.plugin.core.codebrowser.CodeBrowserPlugin;
|
import ghidra.app.plugin.core.codebrowser.CodeBrowserPlugin;
|
||||||
import ghidra.framework.plugintool.PluginTool;
|
import ghidra.framework.plugintool.PluginTool;
|
||||||
import ghidra.framework.plugintool.util.ToolConstants;
|
|
||||||
import ghidra.test.AbstractGhidraHeadedIntegrationTest;
|
import ghidra.test.AbstractGhidraHeadedIntegrationTest;
|
||||||
import ghidra.test.TestEnv;
|
import ghidra.test.TestEnv;
|
||||||
import ghidra.util.Msg;
|
import ghidra.util.Msg;
|
||||||
|
@ -102,9 +102,8 @@ public class KeyBindingsTest extends AbstractGhidraHeadedIntegrationTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testManagedKeyBindings() {
|
public void testManagedKeyBindings() {
|
||||||
List<DockingActionIf> list = tool.getAllActions();
|
Set<DockingActionIf> list = tool.getAllActions();
|
||||||
for (int i = 0; i < list.size(); i++) {
|
for (DockingActionIf action : list) {
|
||||||
DockingActionIf action = list.get(i);
|
|
||||||
if (action.isKeyBindingManaged()) {
|
if (action.isKeyBindingManaged()) {
|
||||||
assertTrue(actionInTable(action));
|
assertTrue(actionInTable(action));
|
||||||
}
|
}
|
||||||
|
@ -128,10 +127,8 @@ public class KeyBindingsTest extends AbstractGhidraHeadedIntegrationTest {
|
||||||
@Test
|
@Test
|
||||||
public void testActionNotSelected() throws Exception {
|
public void testActionNotSelected() throws Exception {
|
||||||
table.clearSelection();
|
table.clearSelection();
|
||||||
List<DockingActionIf> list = tool.getAllActions();
|
Set<DockingActionIf> list = tool.getAllActions();
|
||||||
DockingActionIf action = null;
|
for (DockingActionIf action : list) {
|
||||||
for (int i = 0; i < list.size(); i++) {
|
|
||||||
action = list.get(i);
|
|
||||||
KeyStroke ks = getKeyStroke(action);
|
KeyStroke ks = getKeyStroke(action);
|
||||||
if (isKeyBindingManaged(action) && ks != KeyStroke.getKeyStroke(KeyEvent.VK_Z, 0)) {
|
if (isKeyBindingManaged(action) && ks != KeyStroke.getKeyStroke(KeyEvent.VK_Z, 0)) {
|
||||||
break;
|
break;
|
||||||
|
@ -318,10 +315,8 @@ public class KeyBindingsTest extends AbstractGhidraHeadedIntegrationTest {
|
||||||
}
|
}
|
||||||
|
|
||||||
private DockingActionIf getKeyBindingPluginAction() {
|
private DockingActionIf getKeyBindingPluginAction() {
|
||||||
List<DockingActionIf> list = tool.getAllActions();
|
Set<DockingActionIf> list = tool.getAllActions();
|
||||||
DockingActionIf action = null;
|
for (DockingActionIf action : list) {
|
||||||
for (int i = 0; i < list.size(); i++) {
|
|
||||||
action = list.get(i);
|
|
||||||
KeyStroke ks = action.getKeyBinding();
|
KeyStroke ks = action.getKeyBinding();
|
||||||
if (action.isKeyBindingManaged() && ks != null &&
|
if (action.isKeyBindingManaged() && ks != null &&
|
||||||
ks != KeyStroke.getKeyStroke(KeyEvent.VK_Z, 0)) {
|
ks != KeyStroke.getKeyStroke(KeyEvent.VK_Z, 0)) {
|
||||||
|
@ -372,7 +367,7 @@ public class KeyBindingsTest extends AbstractGhidraHeadedIntegrationTest {
|
||||||
|
|
||||||
private void setUpDialog() throws Exception {
|
private void setUpDialog() throws Exception {
|
||||||
runSwing(() -> {
|
runSwing(() -> {
|
||||||
panel = new KeyBindingsPanel(tool, tool.getOptions(ToolConstants.KEY_BINDINGS));
|
panel = new KeyBindingsPanel(tool, tool.getOptions(DockingToolConstants.KEY_BINDINGS));
|
||||||
|
|
||||||
dialog = new JDialog(tool.getToolFrame(), "Test KeyBindings", false);
|
dialog = new JDialog(tool.getToolFrame(), "Test KeyBindings", false);
|
||||||
dialog.getContentPane().add(panel);
|
dialog.getContentPane().add(panel);
|
||||||
|
@ -391,10 +386,8 @@ public class KeyBindingsTest extends AbstractGhidraHeadedIntegrationTest {
|
||||||
}
|
}
|
||||||
|
|
||||||
private void grabActionsWithoutKeybinding() {
|
private void grabActionsWithoutKeybinding() {
|
||||||
List<DockingActionIf> list = tool.getAllActions();
|
Set<DockingActionIf> list = tool.getAllActions();
|
||||||
DockingActionIf action = null;
|
for (DockingActionIf action : list) {
|
||||||
for (int i = 0; i < list.size(); i++) {
|
|
||||||
action = list.get(i);
|
|
||||||
if (!action.isKeyBindingManaged()) {
|
if (!action.isKeyBindingManaged()) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,8 +20,6 @@ import static org.junit.Assert.*;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
import javax.swing.SwingUtilities;
|
|
||||||
|
|
||||||
import org.junit.*;
|
import org.junit.*;
|
||||||
|
|
||||||
import docking.action.DockingActionIf;
|
import docking.action.DockingActionIf;
|
||||||
|
@ -74,7 +72,7 @@ public class ManageFrontEndToolTest extends AbstractGhidraHeadedIntegrationTest
|
||||||
@After
|
@After
|
||||||
public void tearDown() throws Exception {
|
public void tearDown() throws Exception {
|
||||||
|
|
||||||
SwingUtilities.invokeAndWait(() -> {
|
runSwing(() -> {
|
||||||
tool.setConfigChanged(false);
|
tool.setConfigChanged(false);
|
||||||
provider.close();
|
provider.close();
|
||||||
});
|
});
|
||||||
|
@ -99,33 +97,27 @@ public class ManageFrontEndToolTest extends AbstractGhidraHeadedIntegrationTest
|
||||||
|
|
||||||
final Plugin p = getPlugin(tool, ArchivePlugin.class);
|
final Plugin p = getPlugin(tool, ArchivePlugin.class);
|
||||||
assertNotNull(p);
|
assertNotNull(p);
|
||||||
SwingUtilities.invokeAndWait(() -> {
|
runSwing(() -> {
|
||||||
provider.close();
|
provider.close();
|
||||||
tool.removePlugins(new Plugin[] { p });
|
tool.removePlugins(new Plugin[] { p });
|
||||||
});
|
});
|
||||||
|
|
||||||
showProvider();
|
showProvider();
|
||||||
|
|
||||||
List<DockingActionIf> actions =
|
DockingActionIf action = getAction(tool, plugin.getName(), "Save Project");
|
||||||
tool.getDockingActionsByFullActionName("Save Project (" + plugin.getName() + ")");
|
performAction(action, true);
|
||||||
assertEquals(1, actions.size());
|
|
||||||
performAction(actions.get(0), true);
|
|
||||||
|
|
||||||
actions =
|
action = getAction(tool, plugin.getName(), "Close Project");
|
||||||
tool.getDockingActionsByFullActionName("Close Project (" + plugin.getName() + ")");
|
performAction(action, true);
|
||||||
assertEquals(1, actions.size());
|
|
||||||
performAction(actions.get(0), true);
|
|
||||||
assertTrue(!provider.isVisible());
|
assertTrue(!provider.isVisible());
|
||||||
}
|
}
|
||||||
|
|
||||||
private void showProvider() throws Exception {
|
private void showProvider() throws Exception {
|
||||||
List<DockingActionIf> actions =
|
|
||||||
tool.getDockingActionsByFullActionName("Configure Tool (Project Window)");
|
|
||||||
assertEquals(1, actions.size());
|
|
||||||
|
|
||||||
performAction(actions.get(0), true);
|
DockingActionIf action = getAction(tool, "Project Window", "Configure Tool");
|
||||||
|
performAction(action, true);
|
||||||
waitForPostedSwingRunnables();
|
waitForPostedSwingRunnables();
|
||||||
SwingUtilities.invokeAndWait(() -> tool.showConfig(false, false));
|
runSwing(() -> tool.showConfig(false, false));
|
||||||
|
|
||||||
provider = tool.getManagePluginsDialog();
|
provider = tool.getManagePluginsDialog();
|
||||||
pluginManagerComponent = (PluginManagerComponent) getInstanceField("comp", provider);
|
pluginManagerComponent = (PluginManagerComponent) getInstanceField("comp", provider);
|
||||||
|
|
|
@ -254,11 +254,9 @@ public class ManagePluginsTest extends AbstractGhidraHeadedIntegrationTest {
|
||||||
}
|
}
|
||||||
|
|
||||||
private void showProvider() {
|
private void showProvider() {
|
||||||
List<DockingActionIf> actions =
|
|
||||||
tool.getDockingActionsByFullActionName("Configure Tool (Tool)");
|
|
||||||
assertEquals(1, actions.size());
|
|
||||||
|
|
||||||
performAction(actions.get(0), true);
|
DockingActionIf action = getAction(tool, "Tool", "Configure Tool");
|
||||||
|
performAction(action, true);
|
||||||
waitForSwing();
|
waitForSwing();
|
||||||
provider = tool.getManagePluginsDialog();
|
provider = tool.getManagePluginsDialog();
|
||||||
pluginManagerComponent = (PluginManagerComponent) getInstanceField("comp", provider);
|
pluginManagerComponent = (PluginManagerComponent) getInstanceField("comp", provider);
|
||||||
|
|
|
@ -18,7 +18,6 @@ package ghidra.framework.project.tool;
|
||||||
import static org.junit.Assert.*;
|
import static org.junit.Assert.*;
|
||||||
|
|
||||||
import java.awt.Window;
|
import java.awt.Window;
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import org.junit.*;
|
import org.junit.*;
|
||||||
|
|
||||||
|
@ -56,7 +55,7 @@ public class CloseToolTest extends AbstractGhidraHeadedIntegrationTest {
|
||||||
public void tearDown() throws Exception {
|
public void tearDown() throws Exception {
|
||||||
executeOnSwingWithoutBlocking(() -> env.dispose());
|
executeOnSwingWithoutBlocking(() -> env.dispose());
|
||||||
|
|
||||||
closeAllWindowsAndFrames();
|
closeAllWindows();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -138,7 +137,7 @@ public class CloseToolTest extends AbstractGhidraHeadedIntegrationTest {
|
||||||
closeTool(tool);
|
closeTool(tool);
|
||||||
|
|
||||||
// check for warning dialog
|
// check for warning dialog
|
||||||
Window window = waitForWindow(tool.getToolFrame(), "Tool Busy", 2000);
|
Window window = waitForWindow("Tool Busy");
|
||||||
assertNotNull("Did not get tool busy dialog", window);
|
assertNotNull("Did not get tool busy dialog", window);
|
||||||
closeWindow(window);
|
closeWindow(window);
|
||||||
|
|
||||||
|
@ -146,7 +145,7 @@ public class CloseToolTest extends AbstractGhidraHeadedIntegrationTest {
|
||||||
closeProgram(tool, program);
|
closeProgram(tool, program);
|
||||||
|
|
||||||
// check for warning dialog
|
// check for warning dialog
|
||||||
window = waitForWindow(tool.getToolFrame(), "Close notepad Failed", 2000);
|
window = waitForWindow("Close notepad Failed");
|
||||||
assertNotNull("Did not get \"close failed\" dialog", window);
|
assertNotNull("Did not get \"close failed\" dialog", window);
|
||||||
closeWindow(window);
|
closeWindow(window);
|
||||||
|
|
||||||
|
@ -169,11 +168,9 @@ public class CloseToolTest extends AbstractGhidraHeadedIntegrationTest {
|
||||||
}
|
}
|
||||||
|
|
||||||
private void closeProgram(final PluginTool tool, final ProgramDB program) {
|
private void closeProgram(final PluginTool tool, final ProgramDB program) {
|
||||||
List<DockingActionIf> actionList =
|
|
||||||
tool.getDockingActionsByFullActionName("Close File (ProgramManagerPlugin)");
|
|
||||||
assertTrue(!actionList.isEmpty());
|
|
||||||
|
|
||||||
performAction(actionList.get(0), new ProgramActionContext(null, program), false);
|
DockingActionIf action = getAction(tool, "ProgramManagerPlugin", "Close File");
|
||||||
|
performAction(action, new ProgramActionContext(null, program), false);
|
||||||
|
|
||||||
waitForPostedSwingRunnables();
|
waitForPostedSwingRunnables();
|
||||||
}
|
}
|
||||||
|
|
|
@ -201,10 +201,9 @@ public class DateEditorTest extends AbstractGhidraHeadedIntegrationTest {
|
||||||
}
|
}
|
||||||
|
|
||||||
private void showProgramOptions() {
|
private void showProgramOptions() {
|
||||||
List<DockingActionIf> list = tool.getAllActions();
|
// TODO change to getAction("Program Options")
|
||||||
for (int i = 0; i < list.size(); i++) {
|
Set<DockingActionIf> list = tool.getAllActions();
|
||||||
|
for (DockingActionIf action : list) {
|
||||||
DockingActionIf action = list.get(i);
|
|
||||||
if (action.getName().equals("Program Options")) {
|
if (action.getName().equals("Program Options")) {
|
||||||
performAction(action, plugin.getProvider(), false);
|
performAction(action, plugin.getProvider(), false);
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -988,10 +988,9 @@ public class OptionsDialogTest extends AbstractGhidraHeadedIntegrationTest {
|
||||||
}
|
}
|
||||||
|
|
||||||
private void showOptionsDialog(PluginTool pluginTool) throws Exception {
|
private void showOptionsDialog(PluginTool pluginTool) throws Exception {
|
||||||
List<DockingActionIf> list = pluginTool.getAllActions();
|
// TODO change to getAction("Edit Options")
|
||||||
for (int i = 0; i < list.size(); i++) {
|
Set<DockingActionIf> list = pluginTool.getAllActions();
|
||||||
|
for (DockingActionIf action : list) {
|
||||||
DockingActionIf action = list.get(i);
|
|
||||||
if (action.getName().equals("Edit Options")) {
|
if (action.getName().equals("Edit Options")) {
|
||||||
performAction(action, false);
|
performAction(action, false);
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -19,7 +19,7 @@ import java.awt.Window;
|
||||||
import java.beans.PropertyChangeListener;
|
import java.beans.PropertyChangeListener;
|
||||||
import java.beans.PropertyVetoException;
|
import java.beans.PropertyVetoException;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.Set;
|
||||||
|
|
||||||
import javax.swing.ImageIcon;
|
import javax.swing.ImageIcon;
|
||||||
import javax.swing.event.ChangeListener;
|
import javax.swing.event.ChangeListener;
|
||||||
|
@ -438,18 +438,13 @@ public class DummyTool implements Tool {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<DockingActionIf> getAllActions() {
|
public Set<DockingActionIf> getAllActions() {
|
||||||
return Collections.emptyList();
|
return Collections.emptySet();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<DockingActionIf> getDockingActionsByOwnerName(String owner) {
|
public Set<DockingActionIf> getDockingActionsByOwnerName(String owner) {
|
||||||
return Collections.emptyList();
|
return Collections.emptySet();
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public List<DockingActionIf> getDockingActionsByFullActionName(String fullActionName) {
|
|
||||||
return Collections.emptyList();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -21,7 +21,6 @@ import java.awt.event.ActionListener;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.net.URL;
|
import java.net.URL;
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import javax.swing.*;
|
import javax.swing.*;
|
||||||
|
|
||||||
|
@ -97,9 +96,9 @@ public class SaveToolConfigDialogTest extends AbstractGhidraHeadedIntegrationTes
|
||||||
tc.remove("MyTestTool");
|
tc.remove("MyTestTool");
|
||||||
tc.remove("TestTool");
|
tc.remove("TestTool");
|
||||||
|
|
||||||
waitForPostedSwingRunnables();
|
waitForSwing();
|
||||||
tool.setConfigChanged(false);
|
tool.setConfigChanged(false);
|
||||||
SwingUtilities.invokeAndWait(() -> saveDialog.close());
|
runSwing(() -> saveDialog.close());
|
||||||
env.dispose();
|
env.dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -125,7 +124,7 @@ public class SaveToolConfigDialogTest extends AbstractGhidraHeadedIntegrationTes
|
||||||
pressButtonByText(saveDialog, "Save");
|
pressButtonByText(saveDialog, "Save");
|
||||||
|
|
||||||
assertTrue(!tool.hasConfigChanged());
|
assertTrue(!tool.hasConfigChanged());
|
||||||
waitForPostedSwingRunnables();
|
waitForSwing();
|
||||||
assertTrue(!saveDialog.isVisible());
|
assertTrue(!saveDialog.isVisible());
|
||||||
ToolChest tc = tool.getProject().getLocalToolChest();
|
ToolChest tc = tool.getProject().getLocalToolChest();
|
||||||
ToolTemplate config = tc.getToolTemplate("MyTestTool");
|
ToolTemplate config = tc.getToolTemplate("MyTestTool");
|
||||||
|
@ -142,7 +141,7 @@ public class SaveToolConfigDialogTest extends AbstractGhidraHeadedIntegrationTes
|
||||||
while (saveDialog.isVisible()) {
|
while (saveDialog.isVisible()) {
|
||||||
Thread.sleep(5);
|
Thread.sleep(5);
|
||||||
}
|
}
|
||||||
waitForPostedSwingRunnables();
|
waitForSwing();
|
||||||
assertEquals("Name cannot have spaces.", msg);
|
assertEquals("Name cannot have spaces.", msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -156,7 +155,7 @@ public class SaveToolConfigDialogTest extends AbstractGhidraHeadedIntegrationTes
|
||||||
pressButtonByText(saveDialog, "Save");
|
pressButtonByText(saveDialog, "Save");
|
||||||
|
|
||||||
assertTrue(!tool.hasConfigChanged());
|
assertTrue(!tool.hasConfigChanged());
|
||||||
waitForPostedSwingRunnables();
|
waitForSwing();
|
||||||
assertTrue(!saveDialog.isVisible());
|
assertTrue(!saveDialog.isVisible());
|
||||||
ToolChest tc = tool.getProject().getLocalToolChest();
|
ToolChest tc = tool.getProject().getLocalToolChest();
|
||||||
ToolTemplate template = tc.getToolTemplate("MyTestTool");
|
ToolTemplate template = tc.getToolTemplate("MyTestTool");
|
||||||
|
@ -180,7 +179,7 @@ public class SaveToolConfigDialogTest extends AbstractGhidraHeadedIntegrationTes
|
||||||
while (saveDialog.isVisible()) {
|
while (saveDialog.isVisible()) {
|
||||||
Thread.sleep(5);
|
Thread.sleep(5);
|
||||||
}
|
}
|
||||||
waitForPostedSwingRunnables();
|
waitForSwing();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -208,8 +207,7 @@ public class SaveToolConfigDialogTest extends AbstractGhidraHeadedIntegrationTes
|
||||||
final JButton browseButton = (JButton) findComponentByName(saveDialog, "BrowseButton");
|
final JButton browseButton = (JButton) findComponentByName(saveDialog, "BrowseButton");
|
||||||
pressButton(browseButton, false);
|
pressButton(browseButton, false);
|
||||||
|
|
||||||
final GhidraFileChooser chooser =
|
final GhidraFileChooser chooser = waitForDialogComponent(GhidraFileChooser.class);
|
||||||
waitForDialogComponent(GhidraFileChooser.class);
|
|
||||||
|
|
||||||
assertNotNull(chooser);
|
assertNotNull(chooser);
|
||||||
runSwing(() -> chooser.setSelectedFile(destFile));
|
runSwing(() -> chooser.setSelectedFile(destFile));
|
||||||
|
@ -240,7 +238,7 @@ public class SaveToolConfigDialogTest extends AbstractGhidraHeadedIntegrationTes
|
||||||
while (tc.getToolTemplate("MyTestTool") == null) {
|
while (tc.getToolTemplate("MyTestTool") == null) {
|
||||||
Thread.sleep(10);
|
Thread.sleep(10);
|
||||||
}
|
}
|
||||||
waitForPostedSwingRunnables();
|
waitForSwing();
|
||||||
|
|
||||||
setText(toolNameField, "MyTestTool", false);
|
setText(toolNameField, "MyTestTool", false);
|
||||||
|
|
||||||
|
@ -256,10 +254,9 @@ public class SaveToolConfigDialogTest extends AbstractGhidraHeadedIntegrationTes
|
||||||
JButton saveButton = findButtonByText(saveDialog, "Save");
|
JButton saveButton = findButtonByText(saveDialog, "Save");
|
||||||
saveButton.getActionListeners()[0].actionPerformed(null);
|
saveButton.getActionListeners()[0].actionPerformed(null);
|
||||||
});
|
});
|
||||||
waitForPostedSwingRunnables();
|
waitForSwing();
|
||||||
|
|
||||||
final OptionDialog d =
|
final OptionDialog d = waitForDialogComponent(OptionDialog.class);
|
||||||
waitForDialogComponent(tool.getToolFrame(), OptionDialog.class, 2000);
|
|
||||||
assertNotNull(d);
|
assertNotNull(d);
|
||||||
assertEquals("Overwrite Tool?", d.getTitle());
|
assertEquals("Overwrite Tool?", d.getTitle());
|
||||||
pressButtonByText(d.getComponent(), "Overwrite");
|
pressButtonByText(d.getComponent(), "Overwrite");
|
||||||
|
@ -267,7 +264,7 @@ public class SaveToolConfigDialogTest extends AbstractGhidraHeadedIntegrationTes
|
||||||
while (d.isVisible()) {
|
while (d.isVisible()) {
|
||||||
Thread.sleep(10);
|
Thread.sleep(10);
|
||||||
}
|
}
|
||||||
waitForPostedSwingRunnables();
|
waitForSwing();
|
||||||
|
|
||||||
assertTrue(!tool.hasConfigChanged());
|
assertTrue(!tool.hasConfigChanged());
|
||||||
}
|
}
|
||||||
|
@ -282,11 +279,11 @@ public class SaveToolConfigDialogTest extends AbstractGhidraHeadedIntegrationTes
|
||||||
while (tc.getToolTemplate("MyTestTool") == null) {
|
while (tc.getToolTemplate("MyTestTool") == null) {
|
||||||
Thread.sleep(10);
|
Thread.sleep(10);
|
||||||
}
|
}
|
||||||
waitForPostedSwingRunnables();
|
waitForSwing();
|
||||||
|
|
||||||
setText(toolNameField, "MyTestTool", false);
|
setText(toolNameField, "MyTestTool", false);
|
||||||
|
|
||||||
SwingUtilities.invokeAndWait(() -> {
|
runSwing(() -> {
|
||||||
// force a change to the tool config
|
// force a change to the tool config
|
||||||
try {
|
try {
|
||||||
tool.addPlugin(ByteViewerPlugin.class.getName());
|
tool.addPlugin(ByteViewerPlugin.class.getName());
|
||||||
|
@ -301,10 +298,9 @@ public class SaveToolConfigDialogTest extends AbstractGhidraHeadedIntegrationTes
|
||||||
JButton saveButton = findButtonByText(saveDialog, "Save");
|
JButton saveButton = findButtonByText(saveDialog, "Save");
|
||||||
saveButton.getActionListeners()[0].actionPerformed(null);
|
saveButton.getActionListeners()[0].actionPerformed(null);
|
||||||
});
|
});
|
||||||
waitForPostedSwingRunnables();
|
waitForSwing();
|
||||||
|
|
||||||
final OptionDialog d =
|
final OptionDialog d = waitForDialogComponent(OptionDialog.class);
|
||||||
waitForDialogComponent(OptionDialog.class);
|
|
||||||
assertNotNull(d);
|
assertNotNull(d);
|
||||||
assertEquals("Overwrite Tool?", d.getTitle());
|
assertEquals("Overwrite Tool?", d.getTitle());
|
||||||
pressButtonByText(d.getComponent(), "Cancel");
|
pressButtonByText(d.getComponent(), "Cancel");
|
||||||
|
@ -312,17 +308,16 @@ public class SaveToolConfigDialogTest extends AbstractGhidraHeadedIntegrationTes
|
||||||
while (d.isVisible()) {
|
while (d.isVisible()) {
|
||||||
Thread.sleep(10);
|
Thread.sleep(10);
|
||||||
}
|
}
|
||||||
waitForPostedSwingRunnables();
|
waitForSwing();
|
||||||
|
|
||||||
assertTrue(tool.hasConfigChanged());
|
assertTrue(tool.hasConfigChanged());
|
||||||
}
|
}
|
||||||
|
|
||||||
/////////////////////////////////////////////////////////////////////
|
|
||||||
private void showDialogs() throws Exception {
|
private void showDialogs() throws Exception {
|
||||||
List<DockingActionIf> actions =
|
|
||||||
tool.getDockingActionsByFullActionName("Save Tool As (Tool)");
|
DockingActionIf action = getAction(tool, "Tool", "Save Tool As");
|
||||||
performAction(actions.get(0), false);
|
performAction(action, false);
|
||||||
waitForPostedSwingRunnables();
|
waitForSwing();
|
||||||
|
|
||||||
saveDialog = waitForDialogComponent(SaveToolConfigDialog.class);
|
saveDialog = waitForDialogComponent(SaveToolConfigDialog.class);
|
||||||
|
|
||||||
|
@ -335,7 +330,7 @@ public class SaveToolConfigDialogTest extends AbstractGhidraHeadedIntegrationTes
|
||||||
private void setText(final JTextField field, final String text, final boolean doAction)
|
private void setText(final JTextField field, final String text, final boolean doAction)
|
||||||
throws Exception {
|
throws Exception {
|
||||||
|
|
||||||
SwingUtilities.invokeAndWait(() -> {
|
runSwing(() -> {
|
||||||
field.setText(text);
|
field.setText(text);
|
||||||
if (doAction) {
|
if (doAction) {
|
||||||
ActionListener[] listeners = field.getActionListeners();
|
ActionListener[] listeners = field.getActionListeners();
|
||||||
|
@ -344,6 +339,6 @@ public class SaveToolConfigDialogTest extends AbstractGhidraHeadedIntegrationTes
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
waitForPostedSwingRunnables();
|
waitForSwing();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,6 +27,7 @@ import docking.action.DockingAction;
|
||||||
import docking.widgets.fieldpanel.FieldPanel;
|
import docking.widgets.fieldpanel.FieldPanel;
|
||||||
import docking.widgets.fieldpanel.internal.FieldPanelCoordinator;
|
import docking.widgets.fieldpanel.internal.FieldPanelCoordinator;
|
||||||
import docking.widgets.fieldpanel.support.FieldLocation;
|
import docking.widgets.fieldpanel.support.FieldLocation;
|
||||||
|
import docking.widgets.label.GDHtmlLabel;
|
||||||
import ghidra.app.decompiler.DecompileOptions;
|
import ghidra.app.decompiler.DecompileOptions;
|
||||||
import ghidra.app.util.viewer.listingpanel.ProgramLocationListener;
|
import ghidra.app.util.viewer.listingpanel.ProgramLocationListener;
|
||||||
import ghidra.app.util.viewer.util.CodeComparisonPanel;
|
import ghidra.app.util.viewer.util.CodeComparisonPanel;
|
||||||
|
@ -255,8 +256,13 @@ public abstract class DecompilerCodeComparisonPanel<T extends DualDecompilerFiel
|
||||||
|
|
||||||
String leftTitle1 = FunctionUtility.getFunctionTitle(functions[LEFT]);
|
String leftTitle1 = FunctionUtility.getFunctionTitle(functions[LEFT]);
|
||||||
String rightTitle1 = FunctionUtility.getFunctionTitle(functions[RIGHT]);
|
String rightTitle1 = FunctionUtility.getFunctionTitle(functions[RIGHT]);
|
||||||
titlePanels[LEFT] = new TitledPanel(leftTitle1, cPanels[LEFT], 5);
|
|
||||||
titlePanels[RIGHT] = new TitledPanel(rightTitle1, cPanels[RIGHT], 5);
|
// use mutable labels, as the titles update when functions are selected
|
||||||
|
GDHtmlLabel leftTitleLabel = new GDHtmlLabel(leftTitle1);
|
||||||
|
GDHtmlLabel rightTitleLabel = new GDHtmlLabel(rightTitle1);
|
||||||
|
|
||||||
|
titlePanels[LEFT] = new TitledPanel(leftTitleLabel, cPanels[LEFT], 5);
|
||||||
|
titlePanels[RIGHT] = new TitledPanel(rightTitleLabel, cPanels[RIGHT], 5);
|
||||||
|
|
||||||
// Set the MINIMUM_PANEL_WIDTH for the left and right panel to prevent the split pane's
|
// Set the MINIMUM_PANEL_WIDTH for the left and right panel to prevent the split pane's
|
||||||
// divider from becoming locked (can't be moved) due to extra long title names.
|
// divider from becoming locked (can't be moved) due to extra long title names.
|
||||||
|
|
|
@ -35,6 +35,7 @@ import docking.*;
|
||||||
import docking.action.*;
|
import docking.action.*;
|
||||||
import docking.menu.ActionState;
|
import docking.menu.ActionState;
|
||||||
import docking.menu.MultiStateDockingAction;
|
import docking.menu.MultiStateDockingAction;
|
||||||
|
import docking.test.AbstractDockingTest;
|
||||||
import docking.widgets.EventTrigger;
|
import docking.widgets.EventTrigger;
|
||||||
import docking.widgets.OptionDialog;
|
import docking.widgets.OptionDialog;
|
||||||
import docking.widgets.dialogs.MultiLineInputDialog;
|
import docking.widgets.dialogs.MultiLineInputDialog;
|
||||||
|
@ -470,13 +471,11 @@ public abstract class AbstractFunctionGraphTest extends AbstractGhidraHeadedInte
|
||||||
protected void performReload() throws Exception {
|
protected void performReload() throws Exception {
|
||||||
|
|
||||||
String name = "Reset Graph";
|
String name = "Reset Graph";
|
||||||
List<DockingActionIf> actions =
|
|
||||||
tool.getDockingActionsByFullActionName(name + " (FunctionGraphPlugin)");
|
|
||||||
assertEquals("Could not find action: " + name, 1, actions.size());
|
|
||||||
|
|
||||||
|
DockingActionIf action = getAction(tool, graphPlugin.getName(), name);
|
||||||
long start = System.currentTimeMillis();
|
long start = System.currentTimeMillis();
|
||||||
|
|
||||||
performAction(actions.get(0), false);
|
performAction(action, false);
|
||||||
|
|
||||||
Window window = waitForWindow("Reset Graph?");
|
Window window = waitForWindow("Reset Graph?");
|
||||||
pressButtonByText(window, "Yes");
|
pressButtonByText(window, "Yes");
|
||||||
|
@ -917,20 +916,16 @@ public abstract class AbstractFunctionGraphTest extends AbstractGhidraHeadedInte
|
||||||
|
|
||||||
private void toggleSatellite() {
|
private void toggleSatellite() {
|
||||||
String name = "Display Satellite View";
|
String name = "Display Satellite View";
|
||||||
List<DockingActionIf> actions =
|
DockingActionIf action = getAction(tool, "FunctionGraphPlugin", name);
|
||||||
tool.getDockingActionsByFullActionName(name + " (FunctionGraphPlugin)");
|
ToggleDockingAction dockAction = (ToggleDockingAction) action;
|
||||||
assertEquals("Could not find action: " + name, 1, actions.size());
|
|
||||||
ToggleDockingAction dockAction = (ToggleDockingAction) actions.get(0);
|
|
||||||
performAction(dockAction, true);
|
performAction(dockAction, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void undockSatellite() {
|
protected void undockSatellite() {
|
||||||
String name = "Dock Satellite View";
|
String name = "Dock Satellite View";
|
||||||
List<DockingActionIf> actions =
|
|
||||||
tool.getDockingActionsByFullActionName(name + " (FunctionGraphPlugin)");
|
|
||||||
assertEquals("Could not find action: " + name, 1, actions.size());
|
|
||||||
|
|
||||||
ToggleDockingAction dockAction = (ToggleDockingAction) actions.get(0);
|
DockingActionIf action = getAction(tool, "FunctionGraphPlugin", name);
|
||||||
|
ToggleDockingAction dockAction = (ToggleDockingAction) action;
|
||||||
assertTrue(name + " action is not selected as expected", dockAction.isSelected());
|
assertTrue(name + " action is not selected as expected", dockAction.isSelected());
|
||||||
|
|
||||||
performAction(dockAction, true);
|
performAction(dockAction, true);
|
||||||
|
@ -938,11 +933,9 @@ public abstract class AbstractFunctionGraphTest extends AbstractGhidraHeadedInte
|
||||||
|
|
||||||
protected void redockSatellite() {
|
protected void redockSatellite() {
|
||||||
String name = "Dock Satellite View";
|
String name = "Dock Satellite View";
|
||||||
List<DockingActionIf> actions =
|
|
||||||
tool.getDockingActionsByFullActionName(name + " (FunctionGraphPlugin)");
|
|
||||||
assertEquals("Could not find action: " + name, 1, actions.size());
|
|
||||||
|
|
||||||
ToggleDockingAction dockAction = (ToggleDockingAction) actions.get(0);
|
DockingActionIf action = getAction(tool, "FunctionGraphPlugin", name);
|
||||||
|
ToggleDockingAction dockAction = (ToggleDockingAction) action;
|
||||||
assertFalse(name + " action is not selected as expected", dockAction.isSelected());
|
assertFalse(name + " action is not selected as expected", dockAction.isSelected());
|
||||||
|
|
||||||
performAction(dockAction, true);
|
performAction(dockAction, true);
|
||||||
|
@ -1210,10 +1203,8 @@ public abstract class AbstractFunctionGraphTest extends AbstractGhidraHeadedInte
|
||||||
|
|
||||||
protected FGController cloneGraph() {
|
protected FGController cloneGraph() {
|
||||||
|
|
||||||
List<DockingActionIf> actions = tool.getDockingActionsByFullActionName(
|
DockingActionIf snapshotAction =
|
||||||
"Function Graph Clone (" + graphPlugin.getName() + ")");
|
AbstractDockingTest.getAction(tool, graphPlugin.getName(), "Function Graph Clone");
|
||||||
assertEquals(1, actions.size());
|
|
||||||
DockingActionIf snapshotAction = actions.get(0);
|
|
||||||
performAction(snapshotAction, true);
|
performAction(snapshotAction, true);
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
|
@ -1429,6 +1420,7 @@ public abstract class AbstractFunctionGraphTest extends AbstractGhidraHeadedInte
|
||||||
assertSelected(ungroupedVertices);
|
assertSelected(ungroupedVertices);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
// @formatter:on
|
||||||
|
|
||||||
protected void doTestGroupingProperlyTranslatesEdgesFromGroupedVerticesToRealVertices() {
|
protected void doTestGroupingProperlyTranslatesEdgesFromGroupedVerticesToRealVertices() {
|
||||||
//
|
//
|
||||||
|
@ -1437,7 +1429,7 @@ public abstract class AbstractFunctionGraphTest extends AbstractGhidraHeadedInte
|
||||||
// need to test this functionality, but we don't have a jComplicatedTest, so we will do
|
// need to test this functionality, but we don't have a jComplicatedTest, so we will do
|
||||||
// it here.
|
// it here.
|
||||||
//
|
//
|
||||||
|
|
||||||
//
|
//
|
||||||
// Desired Behavior: We want to be able to group vertices, group grouped vertices and then
|
// Desired Behavior: We want to be able to group vertices, group grouped vertices and then
|
||||||
// ungroup them in any order. For us to be able to do this, our group
|
// ungroup them in any order. For us to be able to do this, our group
|
||||||
|
@ -1457,7 +1449,7 @@ public abstract class AbstractFunctionGraphTest extends AbstractGhidraHeadedInte
|
||||||
//
|
//
|
||||||
// The fix is mentioned in the Desired Behavior section.
|
// The fix is mentioned in the Desired Behavior section.
|
||||||
//
|
//
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
||||||
0) Initial Graph
|
0) Initial Graph
|
||||||
|
@ -1468,26 +1460,26 @@ public abstract class AbstractFunctionGraphTest extends AbstractGhidraHeadedInte
|
||||||
5
|
5
|
||||||
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
create12345Graph();
|
create12345Graph();
|
||||||
|
|
||||||
//
|
//
|
||||||
// Our graph maps from number to address like so:
|
// Our graph maps from number to address like so:
|
||||||
//
|
//
|
||||||
|
|
||||||
FGVertex v1 = vertex("100415a");
|
FGVertex v1 = vertex("100415a");
|
||||||
FGVertex v2 = vertex("1004178");
|
FGVertex v2 = vertex("1004178");
|
||||||
FGVertex v3 = vertex("1004192");
|
FGVertex v3 = vertex("1004192");
|
||||||
FGVertex v4 = vertex("1004196");
|
FGVertex v4 = vertex("1004196");
|
||||||
FGVertex v5 = vertex("100419c");
|
FGVertex v5 = vertex("100419c");
|
||||||
|
|
||||||
// verify initial graph
|
// verify initial graph
|
||||||
verifyEdge(v1, v2);
|
verifyEdge(v1, v2);
|
||||||
verifyEdge(v2, v3);
|
verifyEdge(v2, v3);
|
||||||
verifyEdge(v3, v4);
|
verifyEdge(v3, v4);
|
||||||
verifyEdge(v3, v5);
|
verifyEdge(v3, v5);
|
||||||
verifyEdgeCount(4);
|
verifyEdgeCount(4);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
1) Create two separate group vertices (A and B), such that A has an edge to B.
|
1) Create two separate group vertices (A and B), such that A has an edge to B.
|
||||||
|
|
||||||
|
@ -1497,14 +1489,14 @@ public abstract class AbstractFunctionGraphTest extends AbstractGhidraHeadedInte
|
||||||
5
|
5
|
||||||
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
GroupedFunctionGraphVertex groupA = group("A", v1, v2);
|
GroupedFunctionGraphVertex groupA = group("A", v1, v2);
|
||||||
GroupedFunctionGraphVertex groupB = group("B", v3, v4);
|
GroupedFunctionGraphVertex groupB = group("B", v3, v4);
|
||||||
|
|
||||||
verifyEdge(groupA, groupB);
|
verifyEdge(groupA, groupB);
|
||||||
verifyEdge(groupB, v5);
|
verifyEdge(groupB, v5);
|
||||||
verifyEdgeCount(2);// no other edges
|
verifyEdgeCount(2);// no other edges
|
||||||
|
|
||||||
/*
|
/*
|
||||||
2) Create a third group vertex (Z) that contains a non-grouped vertex *and* one
|
2) Create a third group vertex (Z) that contains a non-grouped vertex *and* one
|
||||||
of the other groups (B).
|
of the other groups (B).
|
||||||
|
@ -1515,12 +1507,12 @@ public abstract class AbstractFunctionGraphTest extends AbstractGhidraHeadedInte
|
||||||
)
|
)
|
||||||
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
GroupedFunctionGraphVertex groupZ = group("Z", groupB, v5);
|
GroupedFunctionGraphVertex groupZ = group("Z", groupB, v5);
|
||||||
|
|
||||||
verifyEdge(groupA, groupZ);
|
verifyEdge(groupA, groupZ);
|
||||||
verifyEdgeCount(1);
|
verifyEdgeCount(1);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
3) Now, ungroup the 1 remaining originally grouped vertex (A).
|
3) Now, ungroup the 1 remaining originally grouped vertex (A).
|
||||||
|
|
||||||
|
@ -1530,13 +1522,13 @@ public abstract class AbstractFunctionGraphTest extends AbstractGhidraHeadedInte
|
||||||
)
|
)
|
||||||
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
ungroup(groupA);
|
ungroup(groupA);
|
||||||
|
|
||||||
verifyEdge(v1, v2);
|
verifyEdge(v1, v2);
|
||||||
verifyEdge(v2, groupZ);
|
verifyEdge(v2, groupZ);
|
||||||
verifyEdgeCount(2);
|
verifyEdgeCount(2);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
||||||
4) Now, ungroup Z and go back to having one remaining group vertex (B)
|
4) Now, ungroup Z and go back to having one remaining group vertex (B)
|
||||||
|
@ -1547,14 +1539,14 @@ public abstract class AbstractFunctionGraphTest extends AbstractGhidraHeadedInte
|
||||||
5
|
5
|
||||||
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
ungroup(groupZ);
|
ungroup(groupZ);
|
||||||
|
|
||||||
verifyEdge(v1, v2);
|
verifyEdge(v1, v2);
|
||||||
verifyEdge(v2, groupB);
|
verifyEdge(v2, groupB);
|
||||||
verifyEdge(groupB, v5);
|
verifyEdge(groupB, v5);
|
||||||
verifyEdgeCount(3);
|
verifyEdgeCount(3);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
5) Finally, ungroup the last group and make sure the graph is restored
|
5) Finally, ungroup the last group and make sure the graph is restored
|
||||||
|
|
||||||
|
@ -1564,15 +1556,15 @@ public abstract class AbstractFunctionGraphTest extends AbstractGhidraHeadedInte
|
||||||
5
|
5
|
||||||
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
ungroup(groupB);
|
ungroup(groupB);
|
||||||
|
|
||||||
verifyEdge(v1, v2);
|
verifyEdge(v1, v2);
|
||||||
verifyEdge(v2, v3);
|
verifyEdge(v2, v3);
|
||||||
verifyEdge(v3, v4);
|
verifyEdge(v3, v4);
|
||||||
verifyEdge(v3, v5);
|
verifyEdge(v3, v5);
|
||||||
verifyEdgeCount(4);
|
verifyEdgeCount(4);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void doTestRestoringWhenCodeBlocksHaveChanged_DoesntRegroup() {
|
private void doTestRestoringWhenCodeBlocksHaveChanged_DoesntRegroup() {
|
||||||
|
@ -1587,28 +1579,28 @@ public abstract class AbstractFunctionGraphTest extends AbstractGhidraHeadedInte
|
||||||
// be found by the regrouping algorithm. Furthermore, the regrouping will not take place
|
// be found by the regrouping algorithm. Furthermore, the regrouping will not take place
|
||||||
// if at least two vertices cannot be found.
|
// if at least two vertices cannot be found.
|
||||||
//
|
//
|
||||||
|
|
||||||
//
|
//
|
||||||
// Pick a function and group some nodes.
|
// Pick a function and group some nodes.
|
||||||
//
|
//
|
||||||
FGData graphData = graphFunction("01002cf5");
|
FGData graphData = graphFunction("01002cf5");
|
||||||
FunctionGraph functionGraph = graphData.getFunctionGraph();
|
FunctionGraph functionGraph = graphData.getFunctionGraph();
|
||||||
|
|
||||||
Set<FGVertex> ungroupedVertices =
|
Set<FGVertex> ungroupedVertices =
|
||||||
selectVertices(functionGraph, "01002d11" /* LAB_01002d11 */, "01002cf5" /* ghidra */);
|
selectVertices(functionGraph, "01002d11" /* LAB_01002d11 */, "01002cf5" /* ghidra */);
|
||||||
|
|
||||||
group(ungroupedVertices);
|
group(ungroupedVertices);
|
||||||
|
|
||||||
// 5 edges expected:
|
// 5 edges expected:
|
||||||
// -01002cf5: 2 out
|
// -01002cf5: 2 out
|
||||||
// -01002cf5: 2 in, 1 out
|
// -01002cf5: 2 in, 1 out
|
||||||
int expectedGroupedEdgeCount = 5;
|
int expectedGroupedEdgeCount = 5;
|
||||||
GroupedFunctionGraphVertex groupedVertex = validateNewGroupedVertexFromVertices(
|
GroupedFunctionGraphVertex groupedVertex = validateNewGroupedVertexFromVertices(
|
||||||
functionGraph, ungroupedVertices, expectedGroupedEdgeCount);
|
functionGraph, ungroupedVertices, expectedGroupedEdgeCount);
|
||||||
|
|
||||||
AddressSetView addresses = groupedVertex.getAddresses();
|
AddressSetView addresses = groupedVertex.getAddresses();
|
||||||
Address minAddress = addresses.getMinAddress();
|
Address minAddress = addresses.getMinAddress();
|
||||||
|
|
||||||
//
|
//
|
||||||
// Ideally, we would like to save, close and re-open the program so that we can get
|
// Ideally, we would like to save, close and re-open the program so that we can get
|
||||||
// a round-trip saving and reloading. However, in the test environment, we cannot save
|
// a round-trip saving and reloading. However, in the test environment, we cannot save
|
||||||
|
@ -1618,12 +1610,12 @@ public abstract class AbstractFunctionGraphTest extends AbstractGhidraHeadedInte
|
||||||
//
|
//
|
||||||
graphFunction("0100415a");
|
graphFunction("0100415a");
|
||||||
clearCache();
|
clearCache();
|
||||||
|
|
||||||
//
|
//
|
||||||
// Add a label to trigger a code block change
|
// Add a label to trigger a code block change
|
||||||
//
|
//
|
||||||
createLabel("01002d18");// in the middle of the LAB_01002d11 code block
|
createLabel("01002d18");// in the middle of the LAB_01002d11 code block
|
||||||
|
|
||||||
//
|
//
|
||||||
// Relaunch the graph, which will use the above persisted group settings...
|
// Relaunch the graph, which will use the above persisted group settings...
|
||||||
//
|
//
|
||||||
|
@ -1646,18 +1638,18 @@ public abstract class AbstractFunctionGraphTest extends AbstractGhidraHeadedInte
|
||||||
// be found by the regrouping algorithm. Furthermore, the regrouping *will* still
|
// be found by the regrouping algorithm. Furthermore, the regrouping *will* still
|
||||||
// take place, as at least two vertices cannot be found.
|
// take place, as at least two vertices cannot be found.
|
||||||
//
|
//
|
||||||
|
|
||||||
//
|
//
|
||||||
// Pick a function and group some nodes.
|
// Pick a function and group some nodes.
|
||||||
//
|
//
|
||||||
FGData graphData = graphFunction("01002cf5");
|
FGData graphData = graphFunction("01002cf5");
|
||||||
FunctionGraph functionGraph = graphData.getFunctionGraph();
|
FunctionGraph functionGraph = graphData.getFunctionGraph();
|
||||||
|
|
||||||
Set<FGVertex> ungroupedVertices = selectVertices(functionGraph,
|
Set<FGVertex> ungroupedVertices = selectVertices(functionGraph,
|
||||||
"01002d11" /* LAB_01002d11 */, "01002cf5" /* ghidra */, "01002d1f" /* MyLocal */);
|
"01002d11" /* LAB_01002d11 */, "01002cf5" /* ghidra */, "01002d1f" /* MyLocal */);
|
||||||
|
|
||||||
group(ungroupedVertices);
|
group(ungroupedVertices);
|
||||||
|
|
||||||
// 5 edges expected:
|
// 5 edges expected:
|
||||||
// -01002cf5: 2 out
|
// -01002cf5: 2 out
|
||||||
// -01002d11: 2 in, (1 out that was removed)
|
// -01002d11: 2 in, (1 out that was removed)
|
||||||
|
@ -1665,11 +1657,11 @@ public abstract class AbstractFunctionGraphTest extends AbstractGhidraHeadedInte
|
||||||
int expectedGroupedEdgeCount = 6;
|
int expectedGroupedEdgeCount = 6;
|
||||||
GroupedFunctionGraphVertex groupedVertex = validateNewGroupedVertexFromVertices(
|
GroupedFunctionGraphVertex groupedVertex = validateNewGroupedVertexFromVertices(
|
||||||
functionGraph, ungroupedVertices, expectedGroupedEdgeCount);
|
functionGraph, ungroupedVertices, expectedGroupedEdgeCount);
|
||||||
|
|
||||||
AddressSetView addresses = groupedVertex.getAddresses();
|
AddressSetView addresses = groupedVertex.getAddresses();
|
||||||
Address minAddress = addresses.getMinAddress();
|
Address minAddress = addresses.getMinAddress();
|
||||||
Address maxAddress = addresses.getMaxAddress();
|
Address maxAddress = addresses.getMaxAddress();
|
||||||
|
|
||||||
//
|
//
|
||||||
// Ideally, we would like to save, close and re-open the program so that we can get
|
// Ideally, we would like to save, close and re-open the program so that we can get
|
||||||
// a round-trip saving and reloading. However, in the test environment, we cannot save
|
// a round-trip saving and reloading. However, in the test environment, we cannot save
|
||||||
|
@ -1679,12 +1671,12 @@ public abstract class AbstractFunctionGraphTest extends AbstractGhidraHeadedInte
|
||||||
//
|
//
|
||||||
graphFunction("0100415a");
|
graphFunction("0100415a");
|
||||||
clearCache();
|
clearCache();
|
||||||
|
|
||||||
//
|
//
|
||||||
// Add a label to trigger a code block change
|
// Add a label to trigger a code block change
|
||||||
//
|
//
|
||||||
Address labelAddress = createLabel("01002d18");// in the middle of the LAB_01002d11 code block
|
Address labelAddress = createLabel("01002d18");// in the middle of the LAB_01002d11 code block
|
||||||
|
|
||||||
//
|
//
|
||||||
// Relaunch the graph, which will use the above persisted group settings...
|
// Relaunch the graph, which will use the above persisted group settings...
|
||||||
//
|
//
|
||||||
|
@ -1694,22 +1686,22 @@ public abstract class AbstractFunctionGraphTest extends AbstractGhidraHeadedInte
|
||||||
FGVertex expectedGroupVertex = functionGraph.getVertexForAddress(minAddress);
|
FGVertex expectedGroupVertex = functionGraph.getVertexForAddress(minAddress);
|
||||||
assertTrue(expectedGroupVertex instanceof GroupedFunctionGraphVertex);
|
assertTrue(expectedGroupVertex instanceof GroupedFunctionGraphVertex);
|
||||||
assertEquals(maxAddress, expectedGroupVertex.getAddresses().getMaxAddress());
|
assertEquals(maxAddress, expectedGroupVertex.getAddresses().getMaxAddress());
|
||||||
|
|
||||||
// ...we expect that the two original grouped vertices have again been grouped...
|
// ...we expect that the two original grouped vertices have again been grouped...
|
||||||
FGVertex splitVertex =
|
FGVertex splitVertex =
|
||||||
functionGraph.getVertexForAddress(getAddress("01002d11") /* LAB_01002d11 */);
|
functionGraph.getVertexForAddress(getAddress("01002d11") /* LAB_01002d11 */);
|
||||||
assertTrue("The split vertex should not have been regrouped",
|
assertTrue("The split vertex should not have been regrouped",
|
||||||
!(splitVertex instanceof GroupedFunctionGraphVertex));
|
!(splitVertex instanceof GroupedFunctionGraphVertex));
|
||||||
|
|
||||||
FGVertex unchangedVertex =
|
FGVertex unchangedVertex =
|
||||||
functionGraph.getVertexForAddress(getAddress("01002cf5") /* ghidra */);
|
functionGraph.getVertexForAddress(getAddress("01002cf5") /* ghidra */);
|
||||||
assertTrue("An unchanged vertex should have been regrouped: " + unchangedVertex,
|
assertTrue("An unchanged vertex should have been regrouped: " + unchangedVertex,
|
||||||
(unchangedVertex instanceof GroupedFunctionGraphVertex));
|
(unchangedVertex instanceof GroupedFunctionGraphVertex));
|
||||||
|
|
||||||
unchangedVertex = functionGraph.getVertexForAddress(getAddress("01002d1f") /* MyLocal */);
|
unchangedVertex = functionGraph.getVertexForAddress(getAddress("01002d1f") /* MyLocal */);
|
||||||
assertTrue("An unchanged vertex should have been regrouped: " + unchangedVertex,
|
assertTrue("An unchanged vertex should have been regrouped: " + unchangedVertex,
|
||||||
(unchangedVertex instanceof GroupedFunctionGraphVertex));
|
(unchangedVertex instanceof GroupedFunctionGraphVertex));
|
||||||
|
|
||||||
// ...but the newly created code block has not
|
// ...but the newly created code block has not
|
||||||
FGVertex newlyCreatedVertex = functionGraph.getVertexForAddress(labelAddress);
|
FGVertex newlyCreatedVertex = functionGraph.getVertexForAddress(labelAddress);
|
||||||
assertNotNull(newlyCreatedVertex);
|
assertNotNull(newlyCreatedVertex);
|
||||||
|
@ -1722,30 +1714,30 @@ public abstract class AbstractFunctionGraphTest extends AbstractGhidraHeadedInte
|
||||||
// However, if the affected vertex is grouped, then the FG will not split the node, but
|
// However, if the affected vertex is grouped, then the FG will not split the node, but
|
||||||
// should still show the 'stale' indicator.
|
// should still show the 'stale' indicator.
|
||||||
//
|
//
|
||||||
|
|
||||||
//
|
//
|
||||||
// Pick a function and group some nodes.
|
// Pick a function and group some nodes.
|
||||||
//
|
//
|
||||||
FGData graphData = graphFunction("01002cf5");
|
FGData graphData = graphFunction("01002cf5");
|
||||||
FunctionGraph functionGraph = graphData.getFunctionGraph();
|
FunctionGraph functionGraph = graphData.getFunctionGraph();
|
||||||
|
|
||||||
Set<FGVertex> ungroupedVertices =
|
Set<FGVertex> ungroupedVertices =
|
||||||
selectVertices(functionGraph, "01002d11" /* LAB_01002d11 */, "01002cf5" /* ghidra */);
|
selectVertices(functionGraph, "01002d11" /* LAB_01002d11 */, "01002cf5" /* ghidra */);
|
||||||
|
|
||||||
group(ungroupedVertices);
|
group(ungroupedVertices);
|
||||||
|
|
||||||
// 5 edges expected:
|
// 5 edges expected:
|
||||||
// -01002cf5: 2 out
|
// -01002cf5: 2 out
|
||||||
// -01002cf5: 2 in, 1 out
|
// -01002cf5: 2 in, 1 out
|
||||||
int expectedGroupedEdgeCount = 5;
|
int expectedGroupedEdgeCount = 5;
|
||||||
GroupedFunctionGraphVertex groupedVertex = validateNewGroupedVertexFromVertices(
|
GroupedFunctionGraphVertex groupedVertex = validateNewGroupedVertexFromVertices(
|
||||||
functionGraph, ungroupedVertices, expectedGroupedEdgeCount);
|
functionGraph, ungroupedVertices, expectedGroupedEdgeCount);
|
||||||
|
|
||||||
//
|
//
|
||||||
// Add a label to trigger a code block change
|
// Add a label to trigger a code block change
|
||||||
//
|
//
|
||||||
Address labelAddress = createLabel("01002d18");// in the middle of the LAB_01002d11 code block
|
Address labelAddress = createLabel("01002d18");// in the middle of the LAB_01002d11 code block
|
||||||
|
|
||||||
//
|
//
|
||||||
// Make sure the newly created code block does not have a corresponding vertex
|
// Make sure the newly created code block does not have a corresponding vertex
|
||||||
//
|
//
|
||||||
|
@ -1792,7 +1784,7 @@ public abstract class AbstractFunctionGraphTest extends AbstractGhidraHeadedInte
|
||||||
Msg.debug(this, "\t" + v);
|
Msg.debug(this, "\t" + v);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Assert.fail("Did not find group vertex at " + address + ". Instead found " + vertex);
|
Assert.fail("Did not find group vertex at " + address + ". Instead found " + vertex);
|
||||||
}
|
}
|
||||||
return (GroupedFunctionGraphVertex) vertex;
|
return (GroupedFunctionGraphVertex) vertex;
|
||||||
|
@ -1819,7 +1811,7 @@ public abstract class AbstractFunctionGraphTest extends AbstractGhidraHeadedInte
|
||||||
protected FGData graphFunction(String functionAddress) {
|
protected FGData graphFunction(String functionAddress) {
|
||||||
// Find a good test function.
|
// Find a good test function.
|
||||||
goToAddress(functionAddress);
|
goToAddress(functionAddress);
|
||||||
|
|
||||||
FGData graphData = getFunctionGraphData();
|
FGData graphData = getFunctionGraphData();
|
||||||
assertNotNull(graphData);
|
assertNotNull(graphData);
|
||||||
assertTrue("Unexpectedly received an empty FunctionGraphData", graphData.hasResults());
|
assertTrue("Unexpectedly received an empty FunctionGraphData", graphData.hasResults());
|
||||||
|
@ -1838,22 +1830,22 @@ public abstract class AbstractFunctionGraphTest extends AbstractGhidraHeadedInte
|
||||||
DockingAction action = (DockingAction) TestUtils.getInstanceField("groupAction", component);
|
DockingAction action = (DockingAction) TestUtils.getInstanceField("groupAction", component);
|
||||||
performAction(action, graphProvider, false);
|
performAction(action, graphProvider, false);
|
||||||
waitForAnimation();
|
waitForAnimation();
|
||||||
|
|
||||||
MultiLineInputDialog dialog = waitForDialogComponent(MultiLineInputDialog.class);
|
MultiLineInputDialog dialog = waitForDialogComponent(MultiLineInputDialog.class);
|
||||||
if (groupVertexText != null) {
|
if (groupVertexText != null) {
|
||||||
final JTextArea inputTextArea = (JTextArea) getInstanceField("inputTextArea", dialog);
|
final JTextArea inputTextArea = (JTextArea) getInstanceField("inputTextArea", dialog);
|
||||||
runSwing(() -> inputTextArea.setText(groupVertexText));
|
runSwing(() -> inputTextArea.setText(groupVertexText));
|
||||||
}
|
}
|
||||||
|
|
||||||
pressButtonByText(dialog.getComponent(), "OK");
|
pressButtonByText(dialog.getComponent(), "OK");
|
||||||
|
|
||||||
if (groupVertexText != null) {
|
if (groupVertexText != null) {
|
||||||
String value = dialog.getValue();
|
String value = dialog.getValue();
|
||||||
assertEquals("Group vertex text was not set in the dialog", groupVertexText, value);
|
assertEquals("Group vertex text was not set in the dialog", groupVertexText, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
waitForAnimation();
|
waitForAnimation();
|
||||||
|
|
||||||
FGController controller = getFunctionGraphController();
|
FGController controller = getFunctionGraphController();
|
||||||
FGData data = controller.getFunctionGraphData();
|
FGData data = controller.getFunctionGraphData();
|
||||||
FunctionGraph fg = data.getFunctionGraph();
|
FunctionGraph fg = data.getFunctionGraph();
|
||||||
|
@ -1861,19 +1853,19 @@ public abstract class AbstractFunctionGraphTest extends AbstractGhidraHeadedInte
|
||||||
}
|
}
|
||||||
|
|
||||||
protected GroupedFunctionGraphVertex group(String groupName, FGVertex... vertices) {
|
protected GroupedFunctionGraphVertex group(String groupName, FGVertex... vertices) {
|
||||||
|
|
||||||
HashSet<FGVertex> set = new HashSet<>();
|
HashSet<FGVertex> set = new HashSet<>();
|
||||||
for (FGVertex v : vertices) {
|
for (FGVertex v : vertices) {
|
||||||
set.add(v);
|
set.add(v);
|
||||||
}
|
}
|
||||||
|
|
||||||
pickVertices(set);
|
pickVertices(set);
|
||||||
GroupedFunctionGraphVertex groupVertex = group(set, groupName);
|
GroupedFunctionGraphVertex groupVertex = group(set, groupName);
|
||||||
|
|
||||||
// for debugging
|
// for debugging
|
||||||
Object componentPanel = getComponent(groupVertex);
|
Object componentPanel = getComponent(groupVertex);
|
||||||
setInstanceField("title", componentPanel, groupName);
|
setInstanceField("title", componentPanel, groupName);
|
||||||
|
|
||||||
return groupVertex;
|
return groupVertex;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1887,23 +1879,22 @@ public abstract class AbstractFunctionGraphTest extends AbstractGhidraHeadedInte
|
||||||
runSwing(() -> {
|
runSwing(() -> {
|
||||||
PickedState<FGVertex> pickedState = getPickedState();
|
PickedState<FGVertex> pickedState = getPickedState();
|
||||||
pickedState.clear();
|
pickedState.clear();
|
||||||
|
|
||||||
for (FGVertex vertex : vertices) {
|
for (FGVertex vertex : vertices) {
|
||||||
pickedState.pick(vertex, true);
|
pickedState.pick(vertex, true);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
protected GroupedFunctionGraphVertex regroup(FGVertex vertex) {
|
protected GroupedFunctionGraphVertex regroup(FGVertex vertex) {
|
||||||
|
|
||||||
DockingActionIf regroupAction = getRegroupAction(vertex);
|
DockingActionIf regroupAction = getRegroupAction(vertex);
|
||||||
if (regroupAction == null) {
|
if (regroupAction == null) {
|
||||||
Assert.fail("Did not find the regroup action on vertex: " + vertex.getTitle());
|
Assert.fail("Did not find the regroup action on vertex: " + vertex.getTitle());
|
||||||
}
|
}
|
||||||
performAction(regroupAction, false);
|
performAction(regroupAction, false);
|
||||||
waitForBusyGraph();
|
waitForBusyGraph();
|
||||||
|
|
||||||
FGController controller = getFunctionGraphController();
|
FGController controller = getFunctionGraphController();
|
||||||
FGData data = controller.getFunctionGraphData();
|
FGData data = controller.getFunctionGraphData();
|
||||||
FunctionGraph fg = data.getFunctionGraph();
|
FunctionGraph fg = data.getFunctionGraph();
|
||||||
|
@ -1912,12 +1903,12 @@ public abstract class AbstractFunctionGraphTest extends AbstractGhidraHeadedInte
|
||||||
|
|
||||||
private void removeEdge(FunctionGraph functionGraph, Address startAddress,
|
private void removeEdge(FunctionGraph functionGraph, Address startAddress,
|
||||||
Address destinationAddress) {
|
Address destinationAddress) {
|
||||||
|
|
||||||
Graph<FGVertex, FGEdge> graph = functionGraph;
|
Graph<FGVertex, FGEdge> graph = functionGraph;
|
||||||
|
|
||||||
FGVertex startVertex = functionGraph.getVertexForAddress(startAddress);
|
FGVertex startVertex = functionGraph.getVertexForAddress(startAddress);
|
||||||
FGVertex destinationVertex = functionGraph.getVertexForAddress(destinationAddress);
|
FGVertex destinationVertex = functionGraph.getVertexForAddress(destinationAddress);
|
||||||
|
|
||||||
FGEdge edge = graph.findEdge(startVertex, destinationVertex);
|
FGEdge edge = graph.findEdge(startVertex, destinationVertex);
|
||||||
runSwing(() -> graph.removeEdge(edge));
|
runSwing(() -> graph.removeEdge(edge));
|
||||||
FGController controller = getFunctionGraphController();
|
FGController controller = getFunctionGraphController();
|
||||||
|
@ -1927,10 +1918,10 @@ public abstract class AbstractFunctionGraphTest extends AbstractGhidraHeadedInte
|
||||||
protected void removeFromUncollapsedGroup(FGVertex... vertices) {
|
protected void removeFromUncollapsedGroup(FGVertex... vertices) {
|
||||||
FunctionGraph functionGraph = getFunctionGraph();
|
FunctionGraph functionGraph = getFunctionGraph();
|
||||||
selectVertices(functionGraph, vertices);
|
selectVertices(functionGraph, vertices);
|
||||||
|
|
||||||
DockingActionIf action = getAction(graphPlugin, "Remove From Group");
|
DockingActionIf action = getAction(graphPlugin, "Remove From Group");
|
||||||
assertNotNull(action);
|
assertNotNull(action);
|
||||||
|
|
||||||
performAction(action, graphProvider, false);
|
performAction(action, graphProvider, false);
|
||||||
waitForBusyGraph();
|
waitForBusyGraph();
|
||||||
}
|
}
|
||||||
|
@ -1944,35 +1935,32 @@ public abstract class AbstractFunctionGraphTest extends AbstractGhidraHeadedInte
|
||||||
}
|
}
|
||||||
|
|
||||||
protected FGData reset() {
|
protected FGData reset() {
|
||||||
List<DockingActionIf> actions =
|
|
||||||
tool.getDockingActionsByFullActionName("Reset Graph (FunctionGraphPlugin)");
|
DockingActionIf action = getAction(tool, graphPlugin.getName(), "Reset Graph");
|
||||||
assertEquals(1, actions.size());
|
|
||||||
DockingActionIf action = actions.get(0);
|
|
||||||
|
|
||||||
performAction(action, graphProvider, false);
|
performAction(action, graphProvider, false);
|
||||||
|
|
||||||
OptionDialog dialog = waitForDialogComponent(OptionDialog.class);
|
OptionDialog dialog = waitForDialogComponent(OptionDialog.class);
|
||||||
pressButtonByText(dialog, "Yes");
|
pressButtonByText(dialog, "Yes");
|
||||||
|
|
||||||
// wait for the threaded graph layout code
|
// wait for the threaded graph layout code
|
||||||
return getFunctionGraphData();
|
return getFunctionGraphData();
|
||||||
}
|
}
|
||||||
|
|
||||||
private Set<FGVertex> selectVertices(FunctionGraph functionGraph, FGVertex... vertices) {
|
private Set<FGVertex> selectVertices(FunctionGraph functionGraph, FGVertex... vertices) {
|
||||||
|
|
||||||
Set<FGVertex> set = new HashSet<>();
|
Set<FGVertex> set = new HashSet<>();
|
||||||
for (FGVertex vertex : vertices) {
|
for (FGVertex vertex : vertices) {
|
||||||
set.add(vertex);
|
set.add(vertex);
|
||||||
}
|
}
|
||||||
|
|
||||||
pickVertices(set);
|
pickVertices(set);
|
||||||
|
|
||||||
waitForSwing();
|
waitForSwing();
|
||||||
return set;
|
return set;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected Set<FGVertex> selectVertices(FunctionGraph functionGraph, String... addressString) {
|
protected Set<FGVertex> selectVertices(FunctionGraph functionGraph, String... addressString) {
|
||||||
|
|
||||||
Set<FGVertex> vertices = new HashSet<>();
|
Set<FGVertex> vertices = new HashSet<>();
|
||||||
for (String string : addressString) {
|
for (String string : addressString) {
|
||||||
Address vertexAddress = getAddress(string);
|
Address vertexAddress = getAddress(string);
|
||||||
|
@ -1980,26 +1968,26 @@ public abstract class AbstractFunctionGraphTest extends AbstractGhidraHeadedInte
|
||||||
assertNotNull("No vertex for address: " + vertexAddress, vertex);
|
assertNotNull("No vertex for address: " + vertexAddress, vertex);
|
||||||
vertices.add(vertex);
|
vertices.add(vertex);
|
||||||
}
|
}
|
||||||
|
|
||||||
pickVertices(vertices);
|
pickVertices(vertices);
|
||||||
|
|
||||||
waitForSwing();
|
waitForSwing();
|
||||||
return vertices;
|
return vertices;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void setGroupText(GroupedFunctionGraphVertex group, final String newText) {
|
protected void setGroupText(GroupedFunctionGraphVertex group, final String newText) {
|
||||||
|
|
||||||
final GroupedFunctionGraphVertex updatedGroup = update(group);
|
final GroupedFunctionGraphVertex updatedGroup = update(group);
|
||||||
runSwing(() -> updatedGroup.editLabel(null), false);
|
runSwing(() -> updatedGroup.editLabel(null), false);
|
||||||
|
|
||||||
Window window = waitForWindow("Enter Group Vertex Text");
|
Window window = waitForWindow("Enter Group Vertex Text");
|
||||||
assertNotNull(window);
|
assertNotNull(window);
|
||||||
|
|
||||||
final JTextArea textArea = findComponent(window, JTextArea.class);
|
final JTextArea textArea = findComponent(window, JTextArea.class);
|
||||||
runSwing(() -> textArea.setText(newText));
|
runSwing(() -> textArea.setText(newText));
|
||||||
|
|
||||||
pressButtonByText(window, "OK");
|
pressButtonByText(window, "OK");
|
||||||
|
|
||||||
waitForSwing();
|
waitForSwing();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2018,9 +2006,9 @@ public abstract class AbstractFunctionGraphTest extends AbstractGhidraHeadedInte
|
||||||
action.setCurrentActionState(state);
|
action.setCurrentActionState(state);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected FGData triggerPersistence(String functionAddress) {
|
protected FGData triggerPersistence(String functionAddress) {
|
||||||
|
@ -2033,7 +2021,7 @@ public abstract class AbstractFunctionGraphTest extends AbstractGhidraHeadedInte
|
||||||
//
|
//
|
||||||
graphFunction("0100415a");
|
graphFunction("0100415a");
|
||||||
clearCache();
|
clearCache();
|
||||||
|
|
||||||
//
|
//
|
||||||
// Graph the original function and make sure that the previously grouped nodes is again
|
// Graph the original function and make sure that the previously grouped nodes is again
|
||||||
// grouped.
|
// grouped.
|
||||||
|
@ -2046,9 +2034,9 @@ public abstract class AbstractFunctionGraphTest extends AbstractGhidraHeadedInte
|
||||||
// Unusual Code: for some of the regroup actions, group vertices are created and restored,
|
// Unusual Code: for some of the regroup actions, group vertices are created and restored,
|
||||||
// but are always equal. Thus, the Function Graph works correctly, but the
|
// but are always equal. Thus, the Function Graph works correctly, but the
|
||||||
// test can get out-of-sync, so we update before we use it
|
// test can get out-of-sync, so we update before we use it
|
||||||
|
|
||||||
groupedVertex = getGroupVertex(getFunctionGraph(), groupedVertex.getVertexAddress());
|
groupedVertex = getGroupVertex(getFunctionGraph(), groupedVertex.getVertexAddress());
|
||||||
|
|
||||||
ungroup(groupedVertex);
|
ungroup(groupedVertex);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2063,45 +2051,42 @@ public abstract class AbstractFunctionGraphTest extends AbstractGhidraHeadedInte
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void ungroupAll() {
|
protected void ungroupAll() {
|
||||||
List<DockingActionIf> actions =
|
|
||||||
tool.getDockingActionsByFullActionName("Ungroup All Vertices (FunctionGraphPlugin)");
|
DockingActionIf action = getAction(tool, "FunctionGraphPlugin", "Ungroup All Vertices");
|
||||||
assertEquals(1, actions.size());
|
|
||||||
DockingActionIf action = actions.get(0);
|
|
||||||
|
|
||||||
performAction(action, graphProvider, false);
|
performAction(action, graphProvider, false);
|
||||||
|
|
||||||
OptionDialog dialog = waitForDialogComponent(OptionDialog.class);
|
OptionDialog dialog = waitForDialogComponent(OptionDialog.class);
|
||||||
pressButtonByText(dialog, "Yes");
|
pressButtonByText(dialog, "Yes");
|
||||||
|
|
||||||
// wait for the threaded graph layout code
|
// wait for the threaded graph layout code
|
||||||
waitForBusyGraph();
|
waitForBusyGraph();
|
||||||
}
|
}
|
||||||
|
|
||||||
//==================================================================================================
|
//==================================================================================================
|
||||||
// Private Methods
|
// Private Methods
|
||||||
//==================================================================================================
|
//==================================================================================================
|
||||||
|
|
||||||
private GroupedFunctionGraphVertex update(GroupedFunctionGraphVertex group) {
|
private GroupedFunctionGraphVertex update(GroupedFunctionGraphVertex group) {
|
||||||
// Unusual Code: for some of the regroup actions, group vertices are created and restored,
|
// Unusual Code: for some of the regroup actions, group vertices are created and restored,
|
||||||
// but are always equal. Thus, the Function Graph works correctly, but the
|
// but are always equal. Thus, the Function Graph works correctly, but the
|
||||||
// test can get out-of-sync, so we update before we use it
|
// test can get out-of-sync, so we update before we use it
|
||||||
return getGroupVertex(getFunctionGraph(), group.getVertexAddress());
|
return getGroupVertex(getFunctionGraph(), group.getVertexAddress());
|
||||||
}
|
}
|
||||||
|
|
||||||
protected GroupedFunctionGraphVertex validateNewGroupedVertexFromVertices(
|
protected GroupedFunctionGraphVertex validateNewGroupedVertexFromVertices(
|
||||||
FunctionGraph functionGraph, Set<FGVertex> vertices, int expectedGroupedEdgeCount) {
|
FunctionGraph functionGraph, Set<FGVertex> vertices, int expectedGroupedEdgeCount) {
|
||||||
|
|
||||||
FGVertex aVertex = vertices.iterator().next();
|
FGVertex aVertex = vertices.iterator().next();
|
||||||
FGVertex currentVertex = functionGraph.getVertexForAddress(aVertex.getVertexAddress());
|
FGVertex currentVertex = functionGraph.getVertexForAddress(aVertex.getVertexAddress());
|
||||||
assertTrue(currentVertex instanceof GroupedFunctionGraphVertex);
|
assertTrue(currentVertex instanceof GroupedFunctionGraphVertex);
|
||||||
GroupedFunctionGraphVertex groupedVertex = (GroupedFunctionGraphVertex) currentVertex;
|
GroupedFunctionGraphVertex groupedVertex = (GroupedFunctionGraphVertex) currentVertex;
|
||||||
|
|
||||||
//
|
//
|
||||||
// make sure we have new edges
|
// make sure we have new edges
|
||||||
//
|
//
|
||||||
Graph<FGVertex, FGEdge> graph = functionGraph;
|
Graph<FGVertex, FGEdge> graph = functionGraph;
|
||||||
Collection<FGEdge> groupedEdges = graph.getIncidentEdges(groupedVertex);
|
Collection<FGEdge> groupedEdges = graph.getIncidentEdges(groupedVertex);
|
||||||
|
|
||||||
assertEquals("Ungrouped edges not replaced with new edges for the grouped vertex",
|
assertEquals("Ungrouped edges not replaced with new edges for the grouped vertex",
|
||||||
expectedGroupedEdgeCount, groupedEdges.size());
|
expectedGroupedEdgeCount, groupedEdges.size());
|
||||||
assertSelected(groupedVertex);
|
assertSelected(groupedVertex);
|
||||||
|
@ -2127,7 +2112,7 @@ public abstract class AbstractFunctionGraphTest extends AbstractGhidraHeadedInte
|
||||||
FGData data = getFunctionGraphData();
|
FGData data = getFunctionGraphData();
|
||||||
FunctionGraph functionGraph = data.getFunctionGraph();
|
FunctionGraph functionGraph = data.getFunctionGraph();
|
||||||
Graph<FGVertex, FGEdge> graph = functionGraph;
|
Graph<FGVertex, FGEdge> graph = functionGraph;
|
||||||
|
|
||||||
FGEdge edge = graph.findEdge(start, destination);
|
FGEdge edge = graph.findEdge(start, destination);
|
||||||
assertNotNull("No edge exists for vertices: " + start + " and " + destination, edge);
|
assertNotNull("No edge exists for vertices: " + start + " and " + destination, edge);
|
||||||
}
|
}
|
||||||
|
@ -2166,7 +2151,7 @@ public abstract class AbstractFunctionGraphTest extends AbstractGhidraHeadedInte
|
||||||
ComponentProvider provider = tool.getComponentProvider(FGSatelliteUndockedProvider.NAME);
|
ComponentProvider provider = tool.getComponentProvider(FGSatelliteUndockedProvider.NAME);
|
||||||
assertUndockedProviderShowing(provider);
|
assertUndockedProviderShowing(provider);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void assertUndockedProviderShowing(ComponentProvider satellite) {
|
protected void assertUndockedProviderShowing(ComponentProvider satellite) {
|
||||||
assertNotNull("Undocked provider is not installed when it should be", satellite);
|
assertNotNull("Undocked provider is not installed when it should be", satellite);
|
||||||
assertTrue("Undocked provider is not showing after being undocked", satellite.isVisible());
|
assertTrue("Undocked provider is not showing after being undocked", satellite.isVisible());
|
||||||
|
@ -2176,7 +2161,7 @@ public abstract class AbstractFunctionGraphTest extends AbstractGhidraHeadedInte
|
||||||
Double scale = getGraphScale(getPrimaryGraphViewer());
|
Double scale = getGraphScale(getPrimaryGraphViewer());
|
||||||
int result = Double.compare(scale, 1.0);
|
int result = Double.compare(scale, 1.0);
|
||||||
assertEquals("Graph not fully zoomed-in; scale: " + scale, 0, result);
|
assertEquals("Graph not fully zoomed-in; scale: " + scale, 0, result);
|
||||||
|
|
||||||
FGVertex v = getFocusedVertex();
|
FGVertex v = getFocusedVertex();
|
||||||
Rectangle cursorBounds = v.getCursorBounds();
|
Rectangle cursorBounds = v.getCursorBounds();
|
||||||
Window graphWindow = windowForComponent(getPrimaryGraphViewer());
|
Window graphWindow = windowForComponent(getPrimaryGraphViewer());
|
||||||
|
@ -2196,13 +2181,13 @@ public abstract class AbstractFunctionGraphTest extends AbstractGhidraHeadedInte
|
||||||
DockingAction action =
|
DockingAction action =
|
||||||
(DockingAction) TestUtils.getInstanceField("chooseColorAction", setColorAction);
|
(DockingAction) TestUtils.getInstanceField("chooseColorAction", setColorAction);
|
||||||
performAction(action, graphProvider, false);
|
performAction(action, graphProvider, false);
|
||||||
|
|
||||||
Window chooserWindow = waitForWindow("Please Select Background Color");
|
Window chooserWindow = waitForWindow("Please Select Background Color");
|
||||||
Object colorChooserDialog = chooserWindow;// the name is the real type
|
Object colorChooserDialog = chooserWindow;// the name is the real type
|
||||||
JColorChooser chooser =
|
JColorChooser chooser =
|
||||||
(JColorChooser) TestUtils.getInstanceField("chooserPane", colorChooserDialog);
|
(JColorChooser) TestUtils.getInstanceField("chooserPane", colorChooserDialog);
|
||||||
chooser.setColor(testColor);
|
chooser.setColor(testColor);
|
||||||
|
|
||||||
JButton okButton = findButtonByText(chooserWindow, "OK");
|
JButton okButton = findButtonByText(chooserWindow, "OK");
|
||||||
runSwing(() -> okButton.doClick());
|
runSwing(() -> okButton.doClick());
|
||||||
waitForSwing();
|
waitForSwing();
|
||||||
|
@ -2216,32 +2201,32 @@ public abstract class AbstractFunctionGraphTest extends AbstractGhidraHeadedInte
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void debugAction(DockingAction copyAction, ActionContext context) {
|
protected void debugAction(DockingAction copyAction, ActionContext context) {
|
||||||
|
|
||||||
Msg.debug(this, "Copy action not enabled at location " + codeBrowser.getCurrentLocation());
|
Msg.debug(this, "Copy action not enabled at location " + codeBrowser.getCurrentLocation());
|
||||||
|
|
||||||
FGVertex focusedVertex = getFocusedVertex();
|
FGVertex focusedVertex = getFocusedVertex();
|
||||||
Msg.debug(this, "\tfocused vertex: " + focusedVertex);
|
Msg.debug(this, "\tfocused vertex: " + focusedVertex);
|
||||||
|
|
||||||
Msg.debug(this, "\tcontext: " + context);
|
Msg.debug(this, "\tcontext: " + context);
|
||||||
|
|
||||||
// Figure out which check in the action failed
|
// Figure out which check in the action failed
|
||||||
Object clipboardService = getInstanceField("clipboardService", copyAction);
|
Object clipboardService = getInstanceField("clipboardService", copyAction);
|
||||||
Msg.debug(this, "\tservice: " + clipboardService);
|
Msg.debug(this, "\tservice: " + clipboardService);
|
||||||
|
|
||||||
Boolean result = (Boolean) invokeInstanceMethod("isValidContext", clipboardService,
|
Boolean result = (Boolean) invokeInstanceMethod("isValidContext", clipboardService,
|
||||||
new Class[] { ActionContext.class }, new Object[] { context });
|
new Class[] { ActionContext.class }, new Object[] { context });
|
||||||
Msg.debug(this, "\tisValidContext()?: " + result);
|
Msg.debug(this, "\tisValidContext()?: " + result);
|
||||||
|
|
||||||
result = (Boolean) invokeInstanceMethod("canCopy", clipboardService);
|
result = (Boolean) invokeInstanceMethod("canCopy", clipboardService);
|
||||||
Msg.debug(this, "\tcanCopy: " + result);
|
Msg.debug(this, "\tcanCopy: " + result);
|
||||||
|
|
||||||
Boolean copyFromSelectionEnabled =
|
Boolean copyFromSelectionEnabled =
|
||||||
(Boolean) getInstanceField("copyFromSelectionEnabled", clipboardService);
|
(Boolean) getInstanceField("copyFromSelectionEnabled", clipboardService);
|
||||||
Msg.debug(this, "\tcopyFromSelectionEnabled: " + copyFromSelectionEnabled);
|
Msg.debug(this, "\tcopyFromSelectionEnabled: " + copyFromSelectionEnabled);
|
||||||
|
|
||||||
String stringContent = (String) getInstanceField("stringContent", clipboardService);
|
String stringContent = (String) getInstanceField("stringContent", clipboardService);
|
||||||
Msg.debug(this, "\tstringContent: " + stringContent);
|
Msg.debug(this, "\tstringContent: " + stringContent);
|
||||||
|
|
||||||
Object location = getInstanceField("currentLocation", clipboardService);
|
Object location = getInstanceField("currentLocation", clipboardService);
|
||||||
Msg.debug(this, "\tservice location: " + location);
|
Msg.debug(this, "\tservice location: " + location);
|
||||||
}
|
}
|
||||||
|
@ -2258,7 +2243,7 @@ public abstract class AbstractFunctionGraphTest extends AbstractGhidraHeadedInte
|
||||||
ProgramLocation location = getLocationForAddressString(startAddressString);
|
ProgramLocation location = getLocationForAddressString(startAddressString);
|
||||||
assertTrue(graphData.containsLocation(location));
|
assertTrue(graphData.containsLocation(location));
|
||||||
FunctionGraph functionGraph = graphData.getFunctionGraph();
|
FunctionGraph functionGraph = graphData.getFunctionGraph();
|
||||||
|
|
||||||
// locate vertex with cursor
|
// locate vertex with cursor
|
||||||
FGVertex focusedVertex = getFocusVertex(functionGraph);
|
FGVertex focusedVertex = getFocusVertex(functionGraph);
|
||||||
assertNotNull("We did not start with a focused vertex", focusedVertex);
|
assertNotNull("We did not start with a focused vertex", focusedVertex);
|
||||||
|
@ -2274,7 +2259,7 @@ public abstract class AbstractFunctionGraphTest extends AbstractGhidraHeadedInte
|
||||||
protected SetVertexMostRecentColorAction getSetMostRecentColorAction(FGVertex vertex) {
|
protected SetVertexMostRecentColorAction getSetMostRecentColorAction(FGVertex vertex) {
|
||||||
// this action is odd in that it is not installed in the tool, but is owned by each
|
// this action is odd in that it is not installed in the tool, but is owned by each
|
||||||
// vertex directly
|
// vertex directly
|
||||||
|
|
||||||
JComponent internalGraphComponent = vertex.getComponent();
|
JComponent internalGraphComponent = vertex.getComponent();
|
||||||
return (SetVertexMostRecentColorAction) getInstanceField("setVertexMostRecentAction",
|
return (SetVertexMostRecentColorAction) getInstanceField("setVertexMostRecentAction",
|
||||||
internalGraphComponent);
|
internalGraphComponent);
|
||||||
|
@ -2284,7 +2269,7 @@ public abstract class AbstractFunctionGraphTest extends AbstractGhidraHeadedInte
|
||||||
Address addr = getAddress(address);
|
Address addr = getAddress(address);
|
||||||
GoToService goToService = tool.getService(GoToService.class);
|
GoToService goToService = tool.getService(GoToService.class);
|
||||||
goToService.goTo(addr);
|
goToService.goTo(addr);
|
||||||
|
|
||||||
waitForBusyGraph();
|
waitForBusyGraph();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2299,11 +2284,9 @@ public abstract class AbstractFunctionGraphTest extends AbstractGhidraHeadedInte
|
||||||
|
|
||||||
protected void navigateBack() {
|
protected void navigateBack() {
|
||||||
String name = "Previous in History Buffer";
|
String name = "Previous in History Buffer";
|
||||||
List<DockingActionIf> actions =
|
|
||||||
tool.getDockingActionsByFullActionName(name + " (NextPrevAddressPlugin)");
|
DockingActionIf action = getAction(tool, "NextPrevAddressPlugin", name);
|
||||||
assertEquals("Could not find action: " + name, 1, actions.size());
|
performAction(action, true);
|
||||||
|
|
||||||
performAction(actions.get(0), true);
|
|
||||||
waitForBusyGraph();
|
waitForBusyGraph();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2320,18 +2303,16 @@ public abstract class AbstractFunctionGraphTest extends AbstractGhidraHeadedInte
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void setGraphWindowSize(final int width, final int height) {
|
protected void setGraphWindowSize(final int width, final int height) {
|
||||||
|
|
||||||
final Window graphWindow = windowForComponent(getPrimaryGraphViewer());
|
final Window graphWindow = windowForComponent(getPrimaryGraphViewer());
|
||||||
runSwing(() -> graphWindow.setSize(width, height));
|
runSwing(() -> graphWindow.setSize(width, height));
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void toggleSatalliteVisible(boolean expectedVisible) {
|
protected void toggleSatalliteVisible(boolean expectedVisible) {
|
||||||
String name = "Display Satellite View";
|
String name = "Display Satellite View";
|
||||||
List<DockingActionIf> actions =
|
|
||||||
tool.getDockingActionsByFullActionName(name + " (FunctionGraphPlugin)");
|
DockingActionIf action = getAction(tool, "FunctionGraphPlugin", name);
|
||||||
assertEquals("Could not find action: " + name, 1, actions.size());
|
ToggleDockingAction displayAction = (ToggleDockingAction) action;
|
||||||
|
|
||||||
ToggleDockingAction displayAction = (ToggleDockingAction) actions.get(0);
|
|
||||||
setToggleActionSelected(displayAction, new ActionContext(), expectedVisible);
|
setToggleActionSelected(displayAction, new ActionContext(), expectedVisible);
|
||||||
//
|
//
|
||||||
// // make sure the action is not already in the state we expect
|
// // make sure the action is not already in the state we expect
|
||||||
|
|
|
@ -177,10 +177,8 @@ public class FunctionGraphPlugin2Test extends AbstractFunctionGraphTest {
|
||||||
GraphPerspectiveInfo<FGVertex, FGEdge> primaryPerspective =
|
GraphPerspectiveInfo<FGVertex, FGEdge> primaryPerspective =
|
||||||
primaryController.getGraphPerspective(location);
|
primaryController.getGraphPerspective(location);
|
||||||
|
|
||||||
List<DockingActionIf> actions = tool.getDockingActionsByFullActionName(
|
DockingActionIf snapshotAction =
|
||||||
"Function Graph Clone (" + graphPlugin.getName() + ")");
|
getAction(tool, graphPlugin.getName(), "Function Graph Clone");
|
||||||
assertEquals(1, actions.size());
|
|
||||||
DockingActionIf snapshotAction = actions.get(0);
|
|
||||||
performAction(snapshotAction, true);
|
performAction(snapshotAction, true);
|
||||||
|
|
||||||
assertEquals(1, disconnectedProviders.size());
|
assertEquals(1, disconnectedProviders.size());
|
||||||
|
|
|
@ -21,7 +21,7 @@ import java.awt.*;
|
||||||
import java.awt.event.ActionListener;
|
import java.awt.event.ActionListener;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
import java.util.List;
|
import java.util.Set;
|
||||||
|
|
||||||
import javax.swing.*;
|
import javax.swing.*;
|
||||||
|
|
||||||
|
@ -589,7 +589,7 @@ public class DiffTestAdapter extends AbstractGhidraHeadedIntegrationTest {
|
||||||
}
|
}
|
||||||
|
|
||||||
public static DockingActionIf getToolAction(PluginTool tool, String name) {
|
public static DockingActionIf getToolAction(PluginTool tool, String name) {
|
||||||
List<DockingActionIf> actions = tool.getDockingActionsByOwnerName("Tool");
|
Set<DockingActionIf> actions = getActionsByOwner(tool, "Tool");
|
||||||
for (DockingActionIf action : actions) {
|
for (DockingActionIf action : actions) {
|
||||||
if (name.equals(action.getName())) {
|
if (name.equals(action.getName())) {
|
||||||
return action;
|
return action;
|
||||||
|
|
|
@ -17,9 +17,11 @@ package ghidra.feature.vt.gui.plugin;
|
||||||
|
|
||||||
import java.net.URL;
|
import java.net.URL;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
import javax.swing.*;
|
import javax.swing.*;
|
||||||
|
|
||||||
|
import docking.action.DockingActionIf;
|
||||||
import docking.help.Help;
|
import docking.help.Help;
|
||||||
import docking.help.HelpService;
|
import docking.help.HelpService;
|
||||||
import docking.wizard.WizardManager;
|
import docking.wizard.WizardManager;
|
||||||
|
@ -121,14 +123,29 @@ public class VTPlugin extends Plugin {
|
||||||
createActions();
|
createActions();
|
||||||
registerServiceProvided(VTController.class, controller);
|
registerServiceProvided(VTController.class, controller);
|
||||||
tool.setUnconfigurable();
|
tool.setUnconfigurable();
|
||||||
tool.removeAction(tool.getDockingActionsByFullActionName("Save Tool As (Tool)").get(0));
|
|
||||||
tool.removeAction(tool.getDockingActionsByFullActionName("Export Tool (Tool)").get(0));
|
DockingActionIf saveAs = getToolAction("Save Tool As");
|
||||||
|
tool.removeAction(saveAs);
|
||||||
|
|
||||||
|
DockingActionIf export = getToolAction("Export Tool");
|
||||||
|
tool.removeAction(export);
|
||||||
|
|
||||||
new MatchStatusUpdaterAssociationHook(controller);
|
new MatchStatusUpdaterAssociationHook(controller);
|
||||||
new ImpliedMatchAssociationHook(controller);
|
new ImpliedMatchAssociationHook(controller);
|
||||||
|
|
||||||
initializeOptions();
|
initializeOptions();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private DockingActionIf getToolAction(String actionName) {
|
||||||
|
Set<DockingActionIf> actions = tool.getDockingActionsByOwnerName("Tool");
|
||||||
|
for (DockingActionIf action : actions) {
|
||||||
|
if (action.getName().equals(actionName)) {
|
||||||
|
return action;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
throw new IllegalArgumentException("Unable to find Tool action '" + actionName + "'");
|
||||||
|
}
|
||||||
|
|
||||||
private void initializeOptions() {
|
private void initializeOptions() {
|
||||||
Options options = tool.getOptions(GhidraOptions.CATEGORY_BROWSER_DISPLAY);
|
Options options = tool.getOptions(GhidraOptions.CATEGORY_BROWSER_DISPLAY);
|
||||||
options.registerOptionsEditor(new ListingDisplayOptionsEditor(this, options));
|
options.registerOptionsEditor(new ListingDisplayOptionsEditor(this, options));
|
||||||
|
|
|
@ -17,8 +17,7 @@ package ghidra.feature.vt.gui.plugin;
|
||||||
|
|
||||||
import java.awt.Component;
|
import java.awt.Component;
|
||||||
import java.io.*;
|
import java.io.*;
|
||||||
import java.util.ArrayList;
|
import java.util.*;
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import javax.swing.KeyStroke;
|
import javax.swing.KeyStroke;
|
||||||
|
|
||||||
|
@ -27,6 +26,7 @@ import org.jdom.output.XMLOutputter;
|
||||||
|
|
||||||
import docking.ActionContext;
|
import docking.ActionContext;
|
||||||
import docking.action.*;
|
import docking.action.*;
|
||||||
|
import docking.tool.util.DockingToolConstants;
|
||||||
import docking.widgets.OptionDialog;
|
import docking.widgets.OptionDialog;
|
||||||
import docking.widgets.fieldpanel.FieldPanel;
|
import docking.widgets.fieldpanel.FieldPanel;
|
||||||
import docking.widgets.fieldpanel.support.FieldSelection;
|
import docking.widgets.fieldpanel.support.FieldSelection;
|
||||||
|
@ -153,17 +153,17 @@ public class VTSubToolManager implements VTControllerListener, OptionsChangeList
|
||||||
catch (PluginException e) {
|
catch (PluginException e) {
|
||||||
Msg.error(this, "Failed to create subordinate tool: " + toolName);
|
Msg.error(this, "Failed to create subordinate tool: " + toolName);
|
||||||
}
|
}
|
||||||
|
|
||||||
newTool.setToolName(toolName);
|
newTool.setToolName(toolName);
|
||||||
newTool.removeAction(newTool.getDockingActionsByFullActionName("Save Tool (Tool)").get(0));
|
|
||||||
newTool.removeAction(
|
DockingActionIf save = getToolAction(newTool, "Save Tool");
|
||||||
newTool.getDockingActionsByFullActionName("Save Tool As (Tool)").get(0));
|
newTool.removeAction(save);
|
||||||
// newTool.removeAction(newTool.getDockableActionsByFullActionName("Export
|
|
||||||
// Tool (Tool)").get(0));
|
|
||||||
createMarkupActions(newTool);
|
createMarkupActions(newTool);
|
||||||
|
|
||||||
newTool.setConfigChanged(false);
|
newTool.setConfigChanged(false);
|
||||||
|
|
||||||
ToolOptions options = newTool.getOptions(ToolConstants.KEY_BINDINGS);
|
ToolOptions options = newTool.getOptions(DockingToolConstants.KEY_BINDINGS);
|
||||||
options.addOptionsChangeListener(this);
|
options.addOptionsChangeListener(this);
|
||||||
|
|
||||||
// custom VT actions
|
// custom VT actions
|
||||||
|
@ -172,6 +172,16 @@ public class VTSubToolManager implements VTControllerListener, OptionsChangeList
|
||||||
return newTool;
|
return newTool;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private DockingActionIf getToolAction(Tool tool, String actionName) {
|
||||||
|
Set<DockingActionIf> actions = tool.getDockingActionsByOwnerName("Tool");
|
||||||
|
for (DockingActionIf action : actions) {
|
||||||
|
if (action.getName().equals(actionName)) {
|
||||||
|
return action;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
throw new IllegalArgumentException("Unable to find Tool action '" + actionName + "'");
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void optionsChanged(ToolOptions options, String optionName, Object oldValue,
|
public void optionsChanged(ToolOptions options, String optionName, Object oldValue,
|
||||||
Object newValue) {
|
Object newValue) {
|
||||||
|
|
|
@ -17,7 +17,6 @@ package docking;
|
||||||
|
|
||||||
import java.awt.*;
|
import java.awt.*;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import javax.swing.JFrame;
|
import javax.swing.JFrame;
|
||||||
|
|
||||||
|
@ -116,22 +115,16 @@ public abstract class AbstractDockingTool implements DockingTool {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<DockingActionIf> getAllActions() {
|
public Set<DockingActionIf> getAllActions() {
|
||||||
return actionMgr.getAllActions();
|
Set<DockingActionIf> actions = actionMgr.getAllActions();
|
||||||
}
|
DockingActionManager am = winMgr.getActionManager();
|
||||||
|
actions.addAll(am.getAllActions());
|
||||||
@Override
|
|
||||||
public List<DockingActionIf> getDockingActionsByOwnerName(String owner) {
|
|
||||||
List<DockingActionIf> actions = actionMgr.getActions(owner);
|
|
||||||
return actions;
|
return actions;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<DockingActionIf> getDockingActionsByFullActionName(String fullActionName) {
|
public Set<DockingActionIf> getDockingActionsByOwnerName(String owner) {
|
||||||
Set<DockingActionIf> set = new HashSet<>();
|
return actionMgr.getActions(owner);
|
||||||
set.addAll(actionMgr.getDockingActionsByFullActionName(fullActionName));
|
|
||||||
set.addAll(winMgr.getActions(fullActionName));
|
|
||||||
return new ArrayList<>(set);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -28,6 +28,8 @@ import org.jdesktop.animation.timing.TimingTargetAdapter;
|
||||||
|
|
||||||
import docking.action.ActionContextProvider;
|
import docking.action.ActionContextProvider;
|
||||||
import docking.action.DockingActionIf;
|
import docking.action.DockingActionIf;
|
||||||
|
import docking.actions.ActionAdapter;
|
||||||
|
import docking.actions.KeyBindingUtils;
|
||||||
import docking.event.mouse.GMouseListenerAdapter;
|
import docking.event.mouse.GMouseListenerAdapter;
|
||||||
import docking.menu.DockingToolbarButton;
|
import docking.menu.DockingToolbarButton;
|
||||||
import docking.util.*;
|
import docking.util.*;
|
||||||
|
|
|
@ -44,11 +44,6 @@ public class DockingActionManager {
|
||||||
private PopupActionManager popupActionManager;
|
private PopupActionManager popupActionManager;
|
||||||
private DockingAction keyBindingsAction;
|
private DockingAction keyBindingsAction;
|
||||||
|
|
||||||
/**
|
|
||||||
* Constructs a new ActionManager
|
|
||||||
* @param frame the frame to contain the menu and toolbar.
|
|
||||||
* @param enableDiagnosticActions if true additional diagnostic actions will enabled
|
|
||||||
*/
|
|
||||||
DockingActionManager(DockingWindowManager winMgr) {
|
DockingActionManager(DockingWindowManager winMgr) {
|
||||||
menuGroupMap = new MenuGroupMap();
|
menuGroupMap = new MenuGroupMap();
|
||||||
|
|
||||||
|
@ -90,9 +85,10 @@ public class DockingActionManager {
|
||||||
/**
|
/**
|
||||||
* Register a specific Help content location for a component.
|
* Register a specific Help content location for a component.
|
||||||
* The DocWinListener will be notified with the help location if the specified
|
* The DocWinListener will be notified with the help location if the specified
|
||||||
* component 'c' has focus and the help key is pressed.
|
* component 'c' has focus and the help key is pressed.
|
||||||
|
*
|
||||||
* @param c component
|
* @param c component
|
||||||
* @param helpURL help content URL
|
* @param helpLocation the help location
|
||||||
*/
|
*/
|
||||||
static void setHelpLocation(JComponent c, HelpLocation helpLocation) {
|
static void setHelpLocation(JComponent c, HelpLocation helpLocation) {
|
||||||
DockingWindowManager.getHelpService().registerHelp(c, helpLocation);
|
DockingWindowManager.getHelpService().registerHelp(c, helpLocation);
|
||||||
|
@ -149,41 +145,18 @@ public class DockingActionManager {
|
||||||
globalActions.remove(action);
|
globalActions.remove(action);
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<DockingActionIf> getAllDockingActionsByFullActionName(String fullActionName) {
|
public Set<DockingActionIf> getAllActions() {
|
||||||
|
|
||||||
// Note: this method is called by non-Swing test code. Synchronize access to the
|
// Note: this method is called by non-Swing test code. Synchronize access to the
|
||||||
// data structures in this class in order to prevent concurrent mod exceptions.
|
// data structures in this class in order to prevent concurrent mod exceptions.
|
||||||
List<DockingActionIf> actions = new ArrayList<>();
|
Set<DockingActionIf> actions = new HashSet<>();
|
||||||
SystemUtilities.runSwingNow(() -> {
|
SystemUtilities.runSwingNow(() -> {
|
||||||
actions.addAll(getGlobalDockingActionsByFullActionName(fullActionName));
|
actions.addAll(globalActions);
|
||||||
actions.addAll(getLocalDockingActionsByFullActionName(fullActionName));
|
actions.addAll(keyBindingsManager.getLocalActions());
|
||||||
});
|
});
|
||||||
return actions;
|
return actions;
|
||||||
}
|
}
|
||||||
|
|
||||||
private List<DockingActionIf> getGlobalDockingActionsByFullActionName(String fullActionName) {
|
|
||||||
List<DockingActionIf> matchingActions = new ArrayList<>();
|
|
||||||
ArrayList<DockingActionIf> existingAction = new ArrayList<>(globalActions);
|
|
||||||
for (DockingActionIf action : existingAction) {
|
|
||||||
if (fullActionName.equals(action.getFullName())) {
|
|
||||||
matchingActions.add(action);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return matchingActions;
|
|
||||||
}
|
|
||||||
|
|
||||||
private List<DockingActionIf> getLocalDockingActionsByFullActionName(String fullActionName) {
|
|
||||||
List<DockingActionIf> matchingActions = new ArrayList<>();
|
|
||||||
ArrayList<DockingActionIf> existingAction =
|
|
||||||
new ArrayList<>(keyBindingsManager.getLocalActions());
|
|
||||||
for (DockingActionIf action : existingAction) {
|
|
||||||
if (fullActionName.equals(action.getFullName())) {
|
|
||||||
matchingActions.add(action);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return matchingActions;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Action getDockingKeyAction(KeyStroke keyStroke) {
|
public Action getDockingKeyAction(KeyStroke keyStroke) {
|
||||||
return keyBindingsManager.getDockingKeyAction(keyStroke);
|
return keyBindingsManager.getDockingKeyAction(keyStroke);
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,13 +16,17 @@
|
||||||
package docking;
|
package docking;
|
||||||
|
|
||||||
import java.awt.Window;
|
import java.awt.Window;
|
||||||
import java.util.List;
|
import java.util.Set;
|
||||||
|
|
||||||
import javax.swing.ImageIcon;
|
import javax.swing.ImageIcon;
|
||||||
|
|
||||||
import docking.action.DockingActionIf;
|
import docking.action.DockingActionIf;
|
||||||
import ghidra.framework.options.ToolOptions;
|
import ghidra.framework.options.ToolOptions;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generic tool interface for managing {@link ComponentProvider}s and
|
||||||
|
* {@link DockingActionIf actions}
|
||||||
|
*/
|
||||||
public interface DockingTool {
|
public interface DockingTool {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -125,25 +129,27 @@ public interface DockingTool {
|
||||||
public void removeLocalAction(ComponentProvider componentProvider, DockingActionIf action);
|
public void removeLocalAction(ComponentProvider componentProvider, DockingActionIf action);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return a list of all actions in the tool.
|
* Return a set of all actions in the tool.
|
||||||
* @return list of all actions
|
*
|
||||||
|
* <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
|
||||||
|
* owner name, such as "My Action (MyPlugin)".
|
||||||
|
*
|
||||||
|
* @return set of all actions
|
||||||
*/
|
*/
|
||||||
public List<DockingActionIf> getAllActions();
|
public Set<DockingActionIf> getAllActions();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 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
|
||||||
|
* actions exist that share the same full name (the full name is the action name with the
|
||||||
|
* owner name, such as "My Action (MyPlugin)".
|
||||||
|
*
|
||||||
* @param owner the action owner's name
|
* @param owner the action owner's name
|
||||||
* @return the actions
|
* @return the actions
|
||||||
*/
|
*/
|
||||||
public List<DockingActionIf> getDockingActionsByOwnerName(String owner);
|
public Set<DockingActionIf> getDockingActionsByOwnerName(String owner);
|
||||||
|
|
||||||
/**
|
|
||||||
* Return an list of actions with the given full name
|
|
||||||
* @param fullActionName action name that includes the owner's name in
|
|
||||||
* parentheses, e.g. "MyAction (MyPlugin)"
|
|
||||||
* @return the actions
|
|
||||||
*/
|
|
||||||
public List<DockingActionIf> getDockingActionsByFullActionName(String fullActionName);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Shows or hides the component provider in the tool
|
* Shows or hides the component provider in the tool
|
||||||
|
|
|
@ -666,22 +666,6 @@ public class DockingWindowManager implements PropertyChangeListener, Placeholder
|
||||||
scheduleUpdate();
|
scheduleUpdate();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Adds an action that will be associated with the given provider. These actions will
|
|
||||||
* appear in the local header for the component as a toolbar button or a drop-down menu
|
|
||||||
* item if it has an icon and menu path respectively.
|
|
||||||
* @param provider the provider whose header on which the action is to be placed.
|
|
||||||
* @param action the action to add to the providers header bar.
|
|
||||||
*/
|
|
||||||
public void addLocalAction(ComponentProvider provider, DockingActionIf action) {
|
|
||||||
ComponentPlaceholder placeholder = getActivePlaceholder(provider);
|
|
||||||
if (placeholder == null) {
|
|
||||||
throw new IllegalArgumentException("Unknown component provider: " + provider);
|
|
||||||
}
|
|
||||||
placeholder.addAction(action);
|
|
||||||
actionManager.addLocalAction(action, provider);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Removes the action from the given provider's header bar.
|
* Removes the action from the given provider's header bar.
|
||||||
* @param provider the provider whose header bar from which the action should be removed.
|
* @param provider the provider whose header bar from which the action should be removed.
|
||||||
|
@ -695,13 +679,33 @@ public class DockingWindowManager implements PropertyChangeListener, Placeholder
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//==================================================================================================
|
||||||
|
// Package-level Action Methods
|
||||||
|
//==================================================================================================
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds an action that will be associated with the given provider. These actions will
|
||||||
|
* appear in the local header for the component as a toolbar button or a drop-down menu
|
||||||
|
* item if it has an icon and menu path respectively.
|
||||||
|
* @param provider the provider whose header on which the action is to be placed.
|
||||||
|
* @param action the action to add to the providers header bar.
|
||||||
|
*/
|
||||||
|
void addLocalAction(ComponentProvider provider, DockingActionIf action) {
|
||||||
|
ComponentPlaceholder placeholder = getActivePlaceholder(provider);
|
||||||
|
if (placeholder == null) {
|
||||||
|
throw new IllegalArgumentException("Unknown component provider: " + provider);
|
||||||
|
}
|
||||||
|
placeholder.addAction(action);
|
||||||
|
actionManager.addLocalAction(action, provider);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Adds an action to the global menu or toolbar which appear in the main frame. If
|
* Adds an action to the global menu or toolbar which appear in the main frame. If
|
||||||
* the action has a menu path, it will be in the menu. If it has an icon, it will
|
* the action has a menu path, it will be in the menu. If it has an icon, it will
|
||||||
* appear in the toolbar.
|
* appear in the toolbar.
|
||||||
* @param action the action to be added.
|
* @param action the action to be added.
|
||||||
*/
|
*/
|
||||||
public void addToolAction(DockingActionIf action) {
|
void addToolAction(DockingActionIf action) {
|
||||||
actionManager.addToolAction(action);
|
actionManager.addToolAction(action);
|
||||||
scheduleUpdate();
|
scheduleUpdate();
|
||||||
}
|
}
|
||||||
|
@ -710,15 +714,23 @@ public class DockingWindowManager implements PropertyChangeListener, Placeholder
|
||||||
* Removes the given action from the global menu and toolbar.
|
* Removes the given action from the global menu and toolbar.
|
||||||
* @param action the action to be removed.
|
* @param action the action to be removed.
|
||||||
*/
|
*/
|
||||||
public void removeToolAction(DockingActionIf action) {
|
void removeToolAction(DockingActionIf action) {
|
||||||
actionManager.removeToolAction(action);
|
actionManager.removeToolAction(action);
|
||||||
scheduleUpdate();
|
scheduleUpdate();
|
||||||
}
|
}
|
||||||
|
|
||||||
public Collection<DockingActionIf> getActions(String fullActionName) {
|
/**
|
||||||
return actionManager.getAllDockingActionsByFullActionName(fullActionName);
|
* Returns all actions registered with this manager
|
||||||
|
* @return the actions
|
||||||
|
*/
|
||||||
|
public Set<DockingActionIf> getAllActions() {
|
||||||
|
return actionManager.getAllActions();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//==================================================================================================
|
||||||
|
// End Package-level Methods
|
||||||
|
//==================================================================================================
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Hides or shows the component associated with the given provider.
|
* Hides or shows the component associated with the given provider.
|
||||||
* <p><br>
|
* <p><br>
|
||||||
|
|
|
@ -0,0 +1,72 @@
|
||||||
|
/* ###
|
||||||
|
* IP: GHIDRA
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package docking;
|
||||||
|
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
import docking.action.DockingActionIf;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A class that exists primarily to provide access to action-related package-level methods of the
|
||||||
|
* {@link DockingWindowManager}. This allows the manager's interface to hide methods that
|
||||||
|
* don't make sense for public consumption.
|
||||||
|
*/
|
||||||
|
public class DockingWindowManagerActionUpdater {
|
||||||
|
|
||||||
|
private DockingWindowManager windowManager;
|
||||||
|
|
||||||
|
public DockingWindowManagerActionUpdater(DockingWindowManager windowManager) {
|
||||||
|
this.windowManager = windowManager;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds an action to the global menu or toolbar which appear in the main frame. If the action
|
||||||
|
* has a menu path, it will be in the menu. If it has an icon, it will appear in the toolbar.
|
||||||
|
* @param action the action to be added
|
||||||
|
*/
|
||||||
|
public void addToolAction(DockingActionIf action) {
|
||||||
|
windowManager.addToolAction(action);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Removes the given action from the global menu and toolbar
|
||||||
|
* @param action the action to be removed
|
||||||
|
*/
|
||||||
|
public void removeToolAction(DockingActionIf action) {
|
||||||
|
windowManager.removeToolAction(action);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns all actions registered with this manager
|
||||||
|
* @return the actions
|
||||||
|
*/
|
||||||
|
public Set<DockingActionIf> getAllActions() {
|
||||||
|
return windowManager.getAllActions();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds an action that will be associated with the given provider. These actions will
|
||||||
|
* appear in the local header for the component as a toolbar button or a drop-down menu
|
||||||
|
* item if it has an icon and menu path respectively.
|
||||||
|
*
|
||||||
|
* @param provider the provider whose header on which the action is to be placed
|
||||||
|
* @param action the action to add to the providers header bar
|
||||||
|
*/
|
||||||
|
public void addLocalAction(ComponentProvider provider, DockingActionIf action) {
|
||||||
|
windowManager.addLocalAction(provider, action);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -25,7 +25,7 @@ import java.awt.event.KeyListener;
|
||||||
import javax.swing.*;
|
import javax.swing.*;
|
||||||
import javax.swing.text.JTextComponent;
|
import javax.swing.text.JTextComponent;
|
||||||
|
|
||||||
import docking.util.KeyBindingUtils;
|
import docking.actions.KeyBindingUtils;
|
||||||
import ghidra.util.bean.GGlassPane;
|
import ghidra.util.bean.GGlassPane;
|
||||||
import ghidra.util.exception.AssertException;
|
import ghidra.util.exception.AssertException;
|
||||||
|
|
||||||
|
|
|
@ -16,9 +16,10 @@
|
||||||
package docking.action;
|
package docking.action;
|
||||||
|
|
||||||
import java.awt.Component;
|
import java.awt.Component;
|
||||||
import java.util.List;
|
import java.util.Set;
|
||||||
|
|
||||||
import docking.*;
|
import docking.*;
|
||||||
|
import docking.actions.KeyBindingUtils;
|
||||||
import ghidra.util.Msg;
|
import ghidra.util.Msg;
|
||||||
import ghidra.util.ReservedKeyBindings;
|
import ghidra.util.ReservedKeyBindings;
|
||||||
|
|
||||||
|
@ -51,20 +52,20 @@ public class KeyBindingAction extends DockingAction {
|
||||||
|
|
||||||
if (!action.isKeyBindingManaged()) {
|
if (!action.isKeyBindingManaged()) {
|
||||||
Component parent = windowManager.getActiveComponent();
|
Component parent = windowManager.getActiveComponent();
|
||||||
Msg.showInfo(getClass(), parent, "Unable to Set Keybinding", "Action \"" +
|
Msg.showInfo(getClass(), parent, "Unable to Set Keybinding",
|
||||||
getActionName(action) + "\" is not keybinding managed and thus a " +
|
"Action \"" + getActionName(action) + "\" is not keybinding managed and thus a " +
|
||||||
"keybinding cannot be set.");
|
"keybinding cannot be set.");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
KeyEntryDialog d = new KeyEntryDialog(action, dockingActionManager);
|
KeyEntryDialog d = new KeyEntryDialog(action, dockingActionManager);
|
||||||
windowManager.showDialog(d);
|
DockingWindowManager.showDialog(d);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Checks to see if the given action is key binding-managed by another action at the
|
* Checks to see if the given action is key binding-managed by another action at the
|
||||||
* tool-level and returns that tool-level action if found.
|
* tool-level and returns that tool-level action if found.
|
||||||
* @param dockableAction The action for which to check for tool-level actions
|
* @param dockingAction The action for which to check for tool-level actions
|
||||||
* @return A tool-level action if one is found; otherwise, the original action
|
* @return A tool-level action if one is found; otherwise, the original action
|
||||||
*/
|
*/
|
||||||
private DockingActionIf maybeGetToolLevelAction(DockingActionIf dockingAction) {
|
private DockingActionIf maybeGetToolLevelAction(DockingActionIf dockingAction) {
|
||||||
|
@ -72,15 +73,13 @@ public class KeyBindingAction extends DockingAction {
|
||||||
return dockingAction;
|
return dockingAction;
|
||||||
}
|
}
|
||||||
|
|
||||||
// It is not key binding managed, which means that it may have tool-level representation
|
// It is not key binding managed, which means that it may be a shared key binding
|
||||||
// that allows for key binding editing (think DummyKeyBindingsOptionsAction).
|
String actionName = dockingAction.getName();
|
||||||
|
Set<DockingActionIf> allActions = dockingActionManager.getAllActions();
|
||||||
// Bad form (code duplication)--code from DockingAction.getFullName()
|
DockingActionIf sharedAction =
|
||||||
String actionToolName = dockingAction.getName() + " (Tool)";
|
KeyBindingUtils.getSharedKeyBindingAction(allActions, actionName);
|
||||||
List<DockingActionIf> actions =
|
if (sharedAction != null) {
|
||||||
dockingActionManager.getAllDockingActionsByFullActionName(actionToolName);
|
return sharedAction;
|
||||||
for (DockingActionIf action : actions) {
|
|
||||||
return action;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return dockingAction;
|
return dockingAction;
|
||||||
|
|
|
@ -23,6 +23,7 @@ import javax.swing.*;
|
||||||
import javax.swing.text.*;
|
import javax.swing.text.*;
|
||||||
|
|
||||||
import docking.*;
|
import docking.*;
|
||||||
|
import docking.actions.KeyBindingUtils;
|
||||||
import docking.widgets.label.GIconLabel;
|
import docking.widgets.label.GIconLabel;
|
||||||
import ghidra.util.HelpLocation;
|
import ghidra.util.HelpLocation;
|
||||||
import ghidra.util.ReservedKeyBindings;
|
import ghidra.util.ReservedKeyBindings;
|
||||||
|
@ -92,12 +93,9 @@ public class KeyEntryDialog extends DialogComponentProvider {
|
||||||
labelPanel.add(pane);
|
labelPanel.add(pane);
|
||||||
labelPanel.add(Box.createHorizontalStrut(5));
|
labelPanel.add(Box.createHorizontalStrut(5));
|
||||||
|
|
||||||
keyEntryField = new KeyEntryTextField(20, new KeyEntryListener() {
|
keyEntryField = new KeyEntryTextField(20, keyStroke -> {
|
||||||
@Override
|
okButton.setEnabled(true);
|
||||||
public void processEntry(KeyStroke keyStroke) {
|
updateCollisionPane(keyStroke);
|
||||||
okButton.setEnabled(true);
|
|
||||||
updateCollisionPane(keyStroke);
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
defaultPanel.add(labelPanel, BorderLayout.NORTH);
|
defaultPanel.add(labelPanel, BorderLayout.NORTH);
|
||||||
|
@ -146,8 +144,9 @@ public class KeyEntryDialog extends DialogComponentProvider {
|
||||||
|
|
||||||
clearStatusText();
|
clearStatusText();
|
||||||
|
|
||||||
List<DockingActionIf> actions =
|
Set<DockingActionIf> allActions = actionManager.getAllActions();
|
||||||
actionManager.getAllDockingActionsByFullActionName(action.getFullName());
|
Set<DockingActionIf> actions =
|
||||||
|
KeyBindingUtils.getActions(allActions, action.getOwner(), action.getName());
|
||||||
for (DockingActionIf element : actions) {
|
for (DockingActionIf element : actions) {
|
||||||
if (element.isKeyBindingManaged()) {
|
if (element.isKeyBindingManaged()) {
|
||||||
element.setUnvalidatedKeyBindingData(new KeyBindingData(keyStroke));
|
element.setUnvalidatedKeyBindingData(new KeyBindingData(keyStroke));
|
||||||
|
@ -160,7 +159,7 @@ public class KeyEntryDialog extends DialogComponentProvider {
|
||||||
private void setUpAttributes() {
|
private void setUpAttributes() {
|
||||||
textAttrSet = new SimpleAttributeSet();
|
textAttrSet = new SimpleAttributeSet();
|
||||||
textAttrSet.addAttribute(StyleConstants.FontFamily, "Tahoma");
|
textAttrSet.addAttribute(StyleConstants.FontFamily, "Tahoma");
|
||||||
textAttrSet.addAttribute(StyleConstants.FontSize, new Integer(11));
|
textAttrSet.addAttribute(StyleConstants.FontSize, Integer.valueOf(11));
|
||||||
textAttrSet.addAttribute(StyleConstants.Foreground, Color.BLUE);
|
textAttrSet.addAttribute(StyleConstants.Foreground, Color.BLUE);
|
||||||
|
|
||||||
tabAttrSet = new SimpleAttributeSet();
|
tabAttrSet = new SimpleAttributeSet();
|
||||||
|
@ -207,7 +206,7 @@ public class KeyEntryDialog extends DialogComponentProvider {
|
||||||
Map<String, DockingActionIf> nameMap = new HashMap<>(list.size());
|
Map<String, DockingActionIf> nameMap = new HashMap<>(list.size());
|
||||||
|
|
||||||
// the list may have multiple matches for a single owner, which we do not want (see
|
// the list may have multiple matches for a single owner, which we do not want (see
|
||||||
// DummyKeyBindingsOptionsAction)
|
// SharedStubKeyBindingAction)
|
||||||
for (DockingActionIf dockableAction : list) {
|
for (DockingActionIf dockableAction : list) {
|
||||||
if (shouldAddAction(dockableAction)) {
|
if (shouldAddAction(dockableAction)) {
|
||||||
// this overwrites same named actions
|
// this overwrites same named actions
|
||||||
|
@ -218,9 +217,6 @@ public class KeyEntryDialog extends DialogComponentProvider {
|
||||||
return new ArrayList<>(nameMap.values());
|
return new ArrayList<>(nameMap.values());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the multiple key action for the given keystroke.
|
|
||||||
*/
|
|
||||||
private MultipleKeyAction getMultipleKeyAction(KeyStroke ks) {
|
private MultipleKeyAction getMultipleKeyAction(KeyStroke ks) {
|
||||||
Action keyAction = actionManager.getDockingKeyAction(ks);
|
Action keyAction = actionManager.getDockingKeyAction(ks);
|
||||||
if (keyAction instanceof MultipleKeyAction) {
|
if (keyAction instanceof MultipleKeyAction) {
|
||||||
|
@ -230,6 +226,11 @@ public class KeyEntryDialog extends DialogComponentProvider {
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean shouldAddAction(DockingActionIf dockableAction) {
|
private boolean shouldAddAction(DockingActionIf dockableAction) {
|
||||||
return dockableAction.isKeyBindingManaged();
|
if (dockableAction.isKeyBindingManaged()) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// shared key bindings are handled specially
|
||||||
|
return !dockableAction.usesSharedKeyBinding();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,7 +13,7 @@
|
||||||
* See the License for the specific language governing permissions and
|
* See the License for the specific language governing permissions and
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
package docking.util;
|
package docking.actions;
|
||||||
|
|
||||||
import java.awt.event.ActionEvent;
|
import java.awt.event.ActionEvent;
|
||||||
import java.beans.PropertyChangeEvent;
|
import java.beans.PropertyChangeEvent;
|
|
@ -18,9 +18,12 @@ package docking.actions;
|
||||||
import java.beans.PropertyChangeEvent;
|
import java.beans.PropertyChangeEvent;
|
||||||
import java.beans.PropertyChangeListener;
|
import java.beans.PropertyChangeListener;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
import java.util.function.Predicate;
|
||||||
|
|
||||||
import javax.swing.KeyStroke;
|
import javax.swing.KeyStroke;
|
||||||
|
|
||||||
|
import org.apache.commons.collections4.map.LazyMap;
|
||||||
|
|
||||||
import docking.*;
|
import docking.*;
|
||||||
import docking.action.*;
|
import docking.action.*;
|
||||||
import docking.tool.util.DockingToolConstants;
|
import docking.tool.util.DockingToolConstants;
|
||||||
|
@ -33,13 +36,16 @@ import ghidra.util.exception.AssertException;
|
||||||
public class DockingToolActionManager implements PropertyChangeListener {
|
public class DockingToolActionManager implements PropertyChangeListener {
|
||||||
|
|
||||||
private DockingWindowManager winMgr;
|
private DockingWindowManager winMgr;
|
||||||
private Map<String, List<DockingActionIf>> actionMap = new HashMap<>();
|
private DockingWindowManagerActionUpdater winMgrActionUpdater;
|
||||||
|
|
||||||
|
private Map<String, List<DockingActionIf>> actionMap =
|
||||||
|
LazyMap.lazyMap(new HashMap<>(), () -> new ArrayList<>());
|
||||||
private Map<String, SharedStubKeyBindingAction> sharedActionMap = new HashMap<>();
|
private Map<String, SharedStubKeyBindingAction> sharedActionMap = new HashMap<>();
|
||||||
private ToolOptions keyBindingOptions;
|
private ToolOptions keyBindingOptions;
|
||||||
private DockingTool dockingTool;
|
private DockingTool dockingTool;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Construct an ActionManager.
|
* Construct an ActionManager
|
||||||
*
|
*
|
||||||
* @param tool tool using this ActionManager
|
* @param tool tool using this ActionManager
|
||||||
* @param windowManager manager of the "Docking" arrangement of a set of components
|
* @param windowManager manager of the "Docking" arrangement of a set of components
|
||||||
|
@ -48,6 +54,7 @@ public class DockingToolActionManager implements PropertyChangeListener {
|
||||||
public DockingToolActionManager(DockingTool tool, DockingWindowManager windowManager) {
|
public DockingToolActionManager(DockingTool tool, DockingWindowManager windowManager) {
|
||||||
this.dockingTool = tool;
|
this.dockingTool = tool;
|
||||||
this.winMgr = windowManager;
|
this.winMgr = windowManager;
|
||||||
|
this.winMgrActionUpdater = new DockingWindowManagerActionUpdater(winMgr);
|
||||||
keyBindingOptions = tool.getOptions(DockingToolConstants.KEY_BINDINGS);
|
keyBindingOptions = tool.getOptions(DockingToolConstants.KEY_BINDINGS);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -58,26 +65,32 @@ public class DockingToolActionManager implements PropertyChangeListener {
|
||||||
private void addActionToMap(DockingActionIf action) {
|
private void addActionToMap(DockingActionIf action) {
|
||||||
String name = action.getFullName();
|
String name = action.getFullName();
|
||||||
List<DockingActionIf> actionList = actionMap.get(name);
|
List<DockingActionIf> actionList = actionMap.get(name);
|
||||||
if (actionList == null) {
|
|
||||||
List<DockingActionIf> newList = new ArrayList<>();
|
List<DockingActionIf> list = actionMap.get(name);
|
||||||
newList.add(action);
|
if (!list.isEmpty()) {
|
||||||
actionMap.put(name, newList);
|
KeyBindingUtils.assertSameDefaultKeyBindings(action, actionList);
|
||||||
}
|
|
||||||
else {
|
|
||||||
actionList.add(action);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
actionList.add(action);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void removeActionFromMap(DockingActionIf action) {
|
private void removeActionFromMap(DockingActionIf action) {
|
||||||
String name = action.getFullName();
|
String name = action.getFullName();
|
||||||
List<DockingActionIf> actionList = actionMap.get(name);
|
actionMap.get(name).remove(action);
|
||||||
if (actionList == null) {
|
}
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (actionList.remove(action) && actionList.isEmpty()) {
|
/**
|
||||||
actionMap.remove(name);
|
* Add an action that works specifically with a component provider.
|
||||||
}
|
* @param provider provider associated with the action
|
||||||
|
* @param action local action to the provider
|
||||||
|
*/
|
||||||
|
public synchronized void addLocalAction(ComponentProvider provider, DockingActionIf action) {
|
||||||
|
checkForAlreadyAddedAction(provider, action);
|
||||||
|
|
||||||
|
action.addPropertyChangeListener(this);
|
||||||
|
addActionToMap(action);
|
||||||
|
setKeyBindingOption(action);
|
||||||
|
winMgrActionUpdater.addLocalAction(provider, action);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -88,7 +101,7 @@ public class DockingToolActionManager implements PropertyChangeListener {
|
||||||
action.addPropertyChangeListener(this);
|
action.addPropertyChangeListener(this);
|
||||||
addActionToMap(action);
|
addActionToMap(action);
|
||||||
setKeyBindingOption(action);
|
setKeyBindingOption(action);
|
||||||
winMgr.addToolAction(action);
|
winMgrActionUpdater.addToolAction(action);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void setKeyBindingOption(DockingActionIf action) {
|
private void setKeyBindingOption(DockingActionIf action) {
|
||||||
|
@ -135,7 +148,7 @@ public class DockingToolActionManager implements PropertyChangeListener {
|
||||||
public synchronized void removeToolAction(DockingActionIf action) {
|
public synchronized void removeToolAction(DockingActionIf action) {
|
||||||
action.removePropertyChangeListener(this);
|
action.removePropertyChangeListener(this);
|
||||||
removeActionFromMap(action);
|
removeActionFromMap(action);
|
||||||
winMgr.removeToolAction(action);
|
winMgrActionUpdater.removeToolAction(action);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -143,32 +156,16 @@ public class DockingToolActionManager implements PropertyChangeListener {
|
||||||
* @param owner owner of the actions to remove
|
* @param owner owner of the actions to remove
|
||||||
*/
|
*/
|
||||||
public synchronized void removeToolActions(String owner) {
|
public synchronized void removeToolActions(String owner) {
|
||||||
List<DockingActionIf> actions = getActions(owner);
|
Predicate<String> ownerMatches = actionOwner -> actionOwner.equals(owner);
|
||||||
|
Set<DockingActionIf> actions = getActions(ownerMatches);
|
||||||
for (DockingActionIf action : actions) {
|
for (DockingActionIf action : actions) {
|
||||||
removeToolAction(action);
|
removeToolAction(action);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Add an action that works specifically with a component provider.
|
|
||||||
* @param provider provider associated with the action
|
|
||||||
* @param action local action to the provider
|
|
||||||
*/
|
|
||||||
public synchronized void addLocalAction(ComponentProvider provider, DockingActionIf action) {
|
|
||||||
checkForAlreadyAddedAction(provider, action);
|
|
||||||
|
|
||||||
action.addPropertyChangeListener(this);
|
|
||||||
addActionToMap(action);
|
|
||||||
setKeyBindingOption(action);
|
|
||||||
winMgr.addLocalAction(provider, action);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void checkForAlreadyAddedAction(ComponentProvider provider, DockingActionIf action) {
|
private void checkForAlreadyAddedAction(ComponentProvider provider, DockingActionIf action) {
|
||||||
String name = action.getFullName();
|
String name = action.getFullName();
|
||||||
List<DockingActionIf> actionList = actionMap.get(name);
|
List<DockingActionIf> actionList = actionMap.get(name);
|
||||||
if (actionList == null) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (actionList.contains(action)) {
|
if (actionList.contains(action)) {
|
||||||
throw new AssertException("Cannot add the same action more than once. Provider " +
|
throw new AssertException("Cannot add the same action more than once. Provider " +
|
||||||
provider.getName() + " - action: " + name);
|
provider.getName() + " - action: " + name);
|
||||||
|
@ -193,46 +190,38 @@ public class DockingToolActionManager implements PropertyChangeListener {
|
||||||
* @param fullName full name for the action, e.g., "My Action (My Plugin)"
|
* @param fullName full name for the action, e.g., "My Action (My Plugin)"
|
||||||
* @return list of actions; empty if no action exists with the given name
|
* @return list of actions; empty if no action exists with the given name
|
||||||
*/
|
*/
|
||||||
public List<DockingActionIf> getDockingActionsByFullActionName(String fullName) {
|
public Set<DockingActionIf> getDockingActionsByFullActionName(String fullName) {
|
||||||
List<DockingActionIf> list = actionMap.get(fullName);
|
List<DockingActionIf> list = actionMap.get(fullName);
|
||||||
if (list == null) {
|
return new HashSet<>(list);
|
||||||
list = new ArrayList<>();
|
|
||||||
}
|
|
||||||
|
|
||||||
return new ArrayList<>(list);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns a list of actions whose owner matches the given owner or all actions if the given
|
* Returns a list of actions whose owner matches the given predicate.
|
||||||
* owner is null.
|
*
|
||||||
* <p>
|
|
||||||
* This method will only return a single instance of any named action, even if multiple
|
|
||||||
* actions have been registered with the same name.
|
|
||||||
* <p>
|
|
||||||
* Note: Actions with the same name are assumed to be different instances of the same action.
|
* Note: Actions with the same name are assumed to be different instances of the same action.
|
||||||
*
|
*
|
||||||
* @param owner The of the action, or null to get all actions
|
* @param ownerFilter the predicate that is used to test if the owners are the same; to get
|
||||||
|
* all actions, return an 'always true' predicate
|
||||||
* @return a list of deduped actions.
|
* @return a list of deduped actions.
|
||||||
*/
|
*/
|
||||||
private List<DockingActionIf> getUniqueActionList(String owner) {
|
private Set<DockingActionIf> getActions(Predicate<String> ownerFilter) {
|
||||||
|
|
||||||
List<DockingActionIf> matchingActionList = new ArrayList<>();
|
Set<DockingActionIf> result = new HashSet<>();
|
||||||
for (List<DockingActionIf> actionList : actionMap.values()) {
|
for (List<DockingActionIf> list : actionMap.values()) {
|
||||||
// we only want *one* instance of duplicate actions
|
for (DockingActionIf action : list) {
|
||||||
DockingActionIf action = actionList.get(0);
|
if (ownerFilter.test(action.getOwner())) {
|
||||||
if (owner == null || action.getOwner().equals(owner)) {
|
result.addAll(list);
|
||||||
matchingActionList.add(action);
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// these are the 'shared' actions that are needed in order to appear in the options UI
|
|
||||||
for (DockingActionIf action : sharedActionMap.values()) {
|
for (DockingActionIf action : sharedActionMap.values()) {
|
||||||
if (owner == null || action.getOwner().equals(owner)) {
|
if (ownerFilter.test(action.getOwner())) {
|
||||||
matchingActionList.add(action);
|
result.add(action);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return matchingActionList;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -241,17 +230,18 @@ public class DockingToolActionManager implements PropertyChangeListener {
|
||||||
* @return array of actions; zero length array is returned if no
|
* @return array of actions; zero length array is returned if no
|
||||||
* action exists with the given name
|
* action exists with the given name
|
||||||
*/
|
*/
|
||||||
public synchronized List<DockingActionIf> getActions(String owner) {
|
public synchronized Set<DockingActionIf> getActions(String owner) {
|
||||||
List<DockingActionIf> list = getUniqueActionList(owner);
|
Predicate<String> ownerMatches = actionOwner -> actionOwner.equals(owner);
|
||||||
return list;
|
return getActions(ownerMatches);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get a list of all actions in the tool.
|
* Get a list of all actions in the tool
|
||||||
* @return list of PluginAction objects
|
* @return list of PluginAction objects
|
||||||
*/
|
*/
|
||||||
public List<DockingActionIf> getAllActions() {
|
public synchronized Set<DockingActionIf> getAllActions() {
|
||||||
return getUniqueActionList(null);
|
Predicate<String> allOwnersMatch = name -> true;
|
||||||
|
return getActions(allOwnersMatch);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -262,7 +252,7 @@ public class DockingToolActionManager implements PropertyChangeListener {
|
||||||
*/
|
*/
|
||||||
public synchronized void restoreKeyBindings() {
|
public synchronized void restoreKeyBindings() {
|
||||||
keyBindingOptions = dockingTool.getOptions(DockingToolConstants.KEY_BINDINGS);
|
keyBindingOptions = dockingTool.getOptions(DockingToolConstants.KEY_BINDINGS);
|
||||||
List<DockingActionIf> actions = getAllActions();
|
Set<DockingActionIf> actions = getAllActions();
|
||||||
for (DockingActionIf action : actions) {
|
for (DockingActionIf action : actions) {
|
||||||
if (!action.isKeyBindingManaged()) {
|
if (!action.isKeyBindingManaged()) {
|
||||||
continue;
|
continue;
|
||||||
|
@ -284,10 +274,7 @@ public class DockingToolActionManager implements PropertyChangeListener {
|
||||||
while (iterator.hasNext()) {
|
while (iterator.hasNext()) {
|
||||||
DockingActionIf action = iterator.next();
|
DockingActionIf action = iterator.next();
|
||||||
String name = action.getFullName();
|
String name = action.getFullName();
|
||||||
List<DockingActionIf> actionList = actionMap.get(name);
|
actionMap.get(name).remove(action);
|
||||||
if (actionList != null && actionList.remove(action) && actionList.isEmpty()) {
|
|
||||||
actionMap.remove(name);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -13,11 +13,12 @@
|
||||||
* See the License for the specific language governing permissions and
|
* See the License for the specific language governing permissions and
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
package docking.util;
|
package docking.actions;
|
||||||
|
|
||||||
import java.awt.Component;
|
import java.awt.Component;
|
||||||
import java.awt.KeyboardFocusManager;
|
import java.awt.KeyboardFocusManager;
|
||||||
import java.io.*;
|
import java.io.*;
|
||||||
|
import java.util.*;
|
||||||
|
|
||||||
import javax.swing.*;
|
import javax.swing.*;
|
||||||
|
|
||||||
|
@ -27,8 +28,10 @@ import org.jdom.*;
|
||||||
import org.jdom.input.SAXBuilder;
|
import org.jdom.input.SAXBuilder;
|
||||||
import org.jdom.output.XMLOutputter;
|
import org.jdom.output.XMLOutputter;
|
||||||
|
|
||||||
import docking.action.ActionContextProvider;
|
import com.google.common.collect.Sets;
|
||||||
import docking.action.DockingAction;
|
|
||||||
|
import docking.DockingTool;
|
||||||
|
import docking.action.*;
|
||||||
import docking.widgets.filechooser.GhidraFileChooser;
|
import docking.widgets.filechooser.GhidraFileChooser;
|
||||||
import ghidra.framework.options.ToolOptions;
|
import ghidra.framework.options.ToolOptions;
|
||||||
import ghidra.framework.preferences.Preferences;
|
import ghidra.framework.preferences.Preferences;
|
||||||
|
@ -37,6 +40,8 @@ import ghidra.util.filechooser.GhidraFileChooserModel;
|
||||||
import ghidra.util.filechooser.GhidraFileFilter;
|
import ghidra.util.filechooser.GhidraFileFilter;
|
||||||
import ghidra.util.xml.GenericXMLOutputter;
|
import ghidra.util.xml.GenericXMLOutputter;
|
||||||
import ghidra.util.xml.XmlUtilities;
|
import ghidra.util.xml.XmlUtilities;
|
||||||
|
import util.CollectionUtils;
|
||||||
|
import utilities.util.reflection.ReflectionUtilities;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A class to provide utilities for system key bindings, such as importing and
|
* A class to provide utilities for system key bindings, such as importing and
|
||||||
|
@ -81,6 +86,7 @@ public class KeyBindingUtils {
|
||||||
* If there is a problem reading the data then the user will be shown an
|
* If there is a problem reading the data then the user will be shown an
|
||||||
* error dialog.
|
* error dialog.
|
||||||
*
|
*
|
||||||
|
* @param inputStream the input stream from which to read options
|
||||||
* @return An options object that is composed of key binding names and their
|
* @return An options object that is composed of key binding names and their
|
||||||
* associated keystrokes.
|
* associated keystrokes.
|
||||||
*/
|
*/
|
||||||
|
@ -232,9 +238,8 @@ public class KeyBindingUtils {
|
||||||
* @param keyStroke the keystroke for to which the action will be bound
|
* @param keyStroke the keystroke for to which the action will be bound
|
||||||
* @param action the action to execute when the given keystroke is triggered
|
* @param action the action to execute when the given keystroke is triggered
|
||||||
* @param focusCondition the focus condition under which to bind the action
|
* @param focusCondition the focus condition under which to bind the action
|
||||||
* ({@link JComponent#getInputMap(int)})
|
* ({@link JComponent#getInputMap(int)}). See {@link JComponent} for more info;
|
||||||
* @param focusCondition see {@link JComponent} for more info; the default
|
* the default is usually {@link JComponent#WHEN_FOCUSED}
|
||||||
* is usually {@link JComponent#WHEN_FOCUSED}
|
|
||||||
*/
|
*/
|
||||||
public static void registerAction(JComponent component, KeyStroke keyStroke, Action action,
|
public static void registerAction(JComponent component, KeyStroke keyStroke, Action action,
|
||||||
int focusCondition) {
|
int focusCondition) {
|
||||||
|
@ -324,6 +329,116 @@ public class KeyBindingUtils {
|
||||||
return (binding == null) ? null : actionMap.get(binding);
|
return (binding == null) ? null : actionMap.get(binding);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A utility method to get all key binding actions. This method will remove duplicate
|
||||||
|
* actions and will only return actions that are {@link DockingActionIf#isKeyBindingManaged()}
|
||||||
|
*
|
||||||
|
* @param tool the tool containing the actions
|
||||||
|
* @return the actions mapped by their full name (e.g., 'Name (OwnerName)')
|
||||||
|
*/
|
||||||
|
public static Map<String, DockingActionIf> getAllKeyBindingActions(DockingTool tool) {
|
||||||
|
|
||||||
|
Map<String, DockingActionIf> deduper = new HashMap<>();
|
||||||
|
Set<DockingActionIf> actions = tool.getAllActions();
|
||||||
|
for (DockingActionIf action : actions) {
|
||||||
|
if (isIgnored(action)) {
|
||||||
|
// don't bother tracking non-keybinding actions; this would be a mistake due
|
||||||
|
// to the potential for a shared key binding action overwriting its
|
||||||
|
// SharedStubKeyBindingAction
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
deduper.put(action.getFullName(), action);
|
||||||
|
}
|
||||||
|
|
||||||
|
return deduper;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A utility method to get all key binding actions that have the given owner.
|
||||||
|
* This method will remove duplicate actions and will only return actions
|
||||||
|
* that are {@link DockingActionIf#isKeyBindingManaged()}
|
||||||
|
*
|
||||||
|
* @param tool the tool containing the actions
|
||||||
|
* @param owner the action owner name
|
||||||
|
* @return the actions
|
||||||
|
*/
|
||||||
|
public static Set<DockingActionIf> getKeyBindingActions(DockingTool tool, String owner) {
|
||||||
|
|
||||||
|
Map<String, DockingActionIf> deduper = new HashMap<>();
|
||||||
|
Set<DockingActionIf> actions = tool.getDockingActionsByOwnerName(owner);
|
||||||
|
for (DockingActionIf action : actions) {
|
||||||
|
if (isIgnored(action)) {
|
||||||
|
// don't bother tracking non-keybinding actions; this would be a mistake due
|
||||||
|
// to the potential for a shared key binding action overwriting its
|
||||||
|
// SharedStubKeyBindingAction
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
deduper.put(action.getFullName(), action);
|
||||||
|
}
|
||||||
|
|
||||||
|
return CollectionUtils.asSet(deduper.values());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns all actions that match the given owner and name
|
||||||
|
*
|
||||||
|
* @param tool the tool containing the actions
|
||||||
|
* @param owner the owner
|
||||||
|
* @param name the name
|
||||||
|
* @return the actions
|
||||||
|
*/
|
||||||
|
public static Set<DockingActionIf> getActions(DockingTool tool, String owner, String name) {
|
||||||
|
Set<DockingActionIf> actions = tool.getDockingActionsByOwnerName(owner);
|
||||||
|
return getActions(actions, owner, name);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns all actions that match the given owner and name
|
||||||
|
*
|
||||||
|
* @param allActions the universe of actions
|
||||||
|
* @param owner the owner
|
||||||
|
* @param name the name
|
||||||
|
* @return the actions
|
||||||
|
*/
|
||||||
|
public static Set<DockingActionIf> getActions(Set<DockingActionIf> allActions, String owner,
|
||||||
|
String name) {
|
||||||
|
|
||||||
|
Set<DockingActionIf> ownerMatch =
|
||||||
|
Sets.filter(allActions, action -> action.getOwner().equals(owner));
|
||||||
|
return Sets.filter(ownerMatch, action -> action.getName().equals(name));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A method to locate the {@link SharedStubKeyBindingAction} representative for the given
|
||||||
|
* action name. This method is not useful to general clients.
|
||||||
|
*
|
||||||
|
* @param allActions all actions in the system
|
||||||
|
* @param sharedName the name of the shared action
|
||||||
|
* @return the shared action representative
|
||||||
|
*/
|
||||||
|
public static DockingActionIf getSharedKeyBindingAction(Set<DockingActionIf> allActions,
|
||||||
|
String sharedName) {
|
||||||
|
|
||||||
|
Set<DockingActionIf> toolActions = getActions(allActions, "Tool", sharedName);
|
||||||
|
|
||||||
|
//@formatter:off
|
||||||
|
return toolActions
|
||||||
|
.stream()
|
||||||
|
.filter(action -> action instanceof SharedStubKeyBindingAction)
|
||||||
|
.findAny()
|
||||||
|
.orElse(null)
|
||||||
|
;
|
||||||
|
//@formatter:on
|
||||||
|
}
|
||||||
|
|
||||||
|
private static boolean isIgnored(DockingActionIf action) {
|
||||||
|
// not keybinding managed; a shared keybinding implies that this action should not be in
|
||||||
|
// the UI, as there will be a single proxy in place of all actions sharing that binding
|
||||||
|
return !action.isKeyBindingManaged() || action.usesSharedKeyBinding();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Takes the existing docking action and allows it to be registered with
|
* Takes the existing docking action and allows it to be registered with
|
||||||
* Swing components
|
* Swing components
|
||||||
|
@ -341,6 +456,46 @@ public class KeyBindingUtils {
|
||||||
return new ActionAdapter(action);
|
return new ActionAdapter(action);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static void assertSameDefaultKeyBindings(DockingActionIf newAction,
|
||||||
|
List<DockingActionIf> existingActions) {
|
||||||
|
|
||||||
|
KeyBindingData newDefaultBinding = newAction.getDefaultKeyBindingData();
|
||||||
|
KeyStroke defaultKs = getKeyStroke(newDefaultBinding);
|
||||||
|
for (DockingActionIf action : existingActions) {
|
||||||
|
KeyBindingData existingDefaultBinding = action.getDefaultKeyBindingData();
|
||||||
|
KeyStroke existingKs = getKeyStroke(existingDefaultBinding);
|
||||||
|
if (!Objects.equals(defaultKs, existingKs)) {
|
||||||
|
logDifferentKeyBindingsWarnigMessage(newAction, action, existingKs);
|
||||||
|
break; // one warning seems like enough
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void logDifferentKeyBindingsWarnigMessage(DockingActionIf newAction,
|
||||||
|
DockingActionIf existingAction, KeyStroke existingDefaultKs) {
|
||||||
|
|
||||||
|
//@formatter:off
|
||||||
|
String s = "Shared Key Binding Actions have different default values. These " +
|
||||||
|
"must be the same." +
|
||||||
|
"\n\tAction name: '"+existingAction.getName()+"'" +
|
||||||
|
"\n\tAction 1: " + existingAction.getInceptionInformation() +
|
||||||
|
"\n\t\tKey Binding: " + existingDefaultKs +
|
||||||
|
"\n\tAction 2: " + newAction.getInceptionInformation() +
|
||||||
|
"\n\t\tKey Binding: " + newAction.getKeyBinding() +
|
||||||
|
"\nUsing the " +
|
||||||
|
"first value set - " + existingDefaultKs;
|
||||||
|
//@formatter:on
|
||||||
|
|
||||||
|
Msg.warn(KeyBindingUtils.class, s, ReflectionUtilities.createJavaFilteredThrowable());
|
||||||
|
}
|
||||||
|
|
||||||
|
private static KeyStroke getKeyStroke(KeyBindingData data) {
|
||||||
|
if (data == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return data.getKeyBinding();
|
||||||
|
}
|
||||||
|
|
||||||
//==================================================================================================
|
//==================================================================================================
|
||||||
// Private Methods
|
// Private Methods
|
||||||
//==================================================================================================
|
//==================================================================================================
|
|
@ -25,8 +25,6 @@ import docking.DockingWindowManager;
|
||||||
import docking.action.*;
|
import docking.action.*;
|
||||||
import ghidra.framework.options.OptionsChangeListener;
|
import ghidra.framework.options.OptionsChangeListener;
|
||||||
import ghidra.framework.options.ToolOptions;
|
import ghidra.framework.options.ToolOptions;
|
||||||
import ghidra.util.Msg;
|
|
||||||
import utilities.util.reflection.ReflectionUtilities;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A stub action that allows key bindings to be edited through the key bindings options. This
|
* A stub action that allows key bindings to be edited through the key bindings options. This
|
||||||
|
@ -95,7 +93,8 @@ public class SharedStubKeyBindingAction extends DockingAction implements Options
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
logDifferentKeyBindingsWarnigMessage(newAction, existingAction, existingDefaultKs);
|
KeyBindingUtils.logDifferentKeyBindingsWarnigMessage(newAction, existingAction,
|
||||||
|
existingDefaultKs);
|
||||||
|
|
||||||
//
|
//
|
||||||
// Not sure which keystroke to prefer here--keep the first one that was set
|
// Not sure which keystroke to prefer here--keep the first one that was set
|
||||||
|
@ -111,24 +110,6 @@ public class SharedStubKeyBindingAction extends DockingAction implements Options
|
||||||
return newDefaultKs;
|
return newDefaultKs;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void logDifferentKeyBindingsWarnigMessage(DockingActionIf newAction,
|
|
||||||
DockingActionIf existingAction, KeyStroke existingDefaultKs) {
|
|
||||||
|
|
||||||
//@formatter:off
|
|
||||||
String s = "Shared Key Binding Actions have different deafult values. These " +
|
|
||||||
"must be the same." +
|
|
||||||
"\n\tAction name: '"+existingAction.getName()+"'" +
|
|
||||||
"\n\tAction 1: " + existingAction.getInceptionInformation() +
|
|
||||||
"\n\t\tKey Binding: " + existingDefaultKs +
|
|
||||||
"\n\tAction 2: " + newAction.getInceptionInformation() +
|
|
||||||
"\n\t\tKey Binding: " + newAction.getKeyBinding() +
|
|
||||||
"\nUsing the " +
|
|
||||||
"first value set - " + existingDefaultKs;
|
|
||||||
//@formatter:on
|
|
||||||
|
|
||||||
Msg.warn(this, s, ReflectionUtilities.createJavaFilteredThrowable());
|
|
||||||
}
|
|
||||||
|
|
||||||
private void updateActionKeyStrokeFromOptions(DockingActionIf action, KeyStroke defaultKs) {
|
private void updateActionKeyStrokeFromOptions(DockingActionIf action, KeyStroke defaultKs) {
|
||||||
|
|
||||||
KeyStroke optionsKs = getKeyStrokeFromOptions(defaultKs);
|
KeyStroke optionsKs = getKeyStrokeFromOptions(defaultKs);
|
||||||
|
|
|
@ -32,7 +32,7 @@ import javax.swing.text.Document;
|
||||||
|
|
||||||
import docking.DockingUtils;
|
import docking.DockingUtils;
|
||||||
import docking.DockingWindowManager;
|
import docking.DockingWindowManager;
|
||||||
import docking.util.KeyBindingUtils;
|
import docking.actions.KeyBindingUtils;
|
||||||
import docking.widgets.*;
|
import docking.widgets.*;
|
||||||
import ghidra.util.Msg;
|
import ghidra.util.Msg;
|
||||||
import ghidra.util.exception.AssertException;
|
import ghidra.util.exception.AssertException;
|
||||||
|
|
|
@ -38,6 +38,8 @@ import org.apache.commons.io.FilenameUtils;
|
||||||
import org.apache.commons.lang3.StringUtils;
|
import org.apache.commons.lang3.StringUtils;
|
||||||
import org.junit.*;
|
import org.junit.*;
|
||||||
|
|
||||||
|
import com.google.common.collect.Sets;
|
||||||
|
|
||||||
import docking.*;
|
import docking.*;
|
||||||
import docking.action.DockingActionIf;
|
import docking.action.DockingActionIf;
|
||||||
import docking.action.ToggleDockingActionIf;
|
import docking.action.ToggleDockingActionIf;
|
||||||
|
@ -1098,23 +1100,48 @@ public abstract class AbstractDockingTest extends AbstractGenericTest {
|
||||||
* @param name the name to match
|
* @param name the name to match
|
||||||
* @return the matching actions; empty list if no matches
|
* @return the matching actions; empty list if no matches
|
||||||
*/
|
*/
|
||||||
public static Set<DockingActionIf> getActions(DockingTool tool, String name) {
|
public static Set<DockingActionIf> getActionsByName(DockingTool tool, String name) {
|
||||||
|
|
||||||
Set<DockingActionIf> actions = new HashSet<>();
|
Set<DockingActionIf> result = new HashSet<>();
|
||||||
|
|
||||||
List<DockingActionIf> toolActions = tool.getAllActions();
|
Set<DockingActionIf> toolActions = tool.getAllActions();
|
||||||
for (DockingActionIf action : toolActions) {
|
for (DockingActionIf action : toolActions) {
|
||||||
if (action.getName().equals(name)) {
|
if (action.getName().equals(name)) {
|
||||||
actions.add(action);
|
result.add(action);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return actions;
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A helper method to find all actions with the given owner's name
|
||||||
|
*
|
||||||
|
* @param tool the tool containing all system actions
|
||||||
|
* @param name the owner's name to match
|
||||||
|
* @return the matching actions; empty list if no matches
|
||||||
|
*/
|
||||||
|
public static Set<DockingActionIf> getActionsByOwner(DockingTool tool, String name) {
|
||||||
|
return tool.getDockingActionsByOwnerName(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A helper method to find all actions by name, with the given owner's name
|
||||||
|
*
|
||||||
|
* @param tool the tool containing all system actions
|
||||||
|
* @param owner the owner's name
|
||||||
|
* @param name the owner's name to match
|
||||||
|
* @return the matching actions; empty list if no matches
|
||||||
|
*/
|
||||||
|
public static Set<DockingActionIf> getActionsByOwnerAndName(DockingTool tool, String owner,
|
||||||
|
String name) {
|
||||||
|
Set<DockingActionIf> ownerActions = tool.getDockingActionsByOwnerName(owner);
|
||||||
|
return Sets.filter(ownerActions, action -> action.getName().equals(name));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Finds the singular tool action by the given name. If more than one action exists with
|
* Finds the singular tool action by the given name. If more than one action exists with
|
||||||
* that name, then an exception is thrown. If you want more than one matching action,
|
* that name, then an exception is thrown. If you want more than one matching action,
|
||||||
* the call {@link #getActions(DockingTool, String)} instead.
|
* the call {@link #getActionsByName(DockingTool, String)} instead.
|
||||||
*
|
*
|
||||||
* <P>Note: more specific test case subclasses provide other methods for finding actions
|
* <P>Note: more specific test case subclasses provide other methods for finding actions
|
||||||
* when you have an owner name (which is usually the plugin name).
|
* when you have an owner name (which is usually the plugin name).
|
||||||
|
@ -1125,7 +1152,7 @@ public abstract class AbstractDockingTest extends AbstractGenericTest {
|
||||||
*/
|
*/
|
||||||
public static DockingActionIf getAction(DockingTool tool, String name) {
|
public static DockingActionIf getAction(DockingTool tool, String name) {
|
||||||
|
|
||||||
Set<DockingActionIf> actions = getActions(tool, name);
|
Set<DockingActionIf> actions = getActionsByName(tool, name);
|
||||||
if (actions.isEmpty()) {
|
if (actions.isEmpty()) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
@ -1140,7 +1167,7 @@ public abstract class AbstractDockingTest extends AbstractGenericTest {
|
||||||
/**
|
/**
|
||||||
* Finds the action by the given owner name and action name.
|
* Finds the action by the given owner name and action name.
|
||||||
* If you do not know the owner name, then use
|
* If you do not know the owner name, then use
|
||||||
* the call {@link #getActions(DockingTool, String)} instead.
|
* the call {@link #getActionsByName(DockingTool, String)} instead.
|
||||||
*
|
*
|
||||||
* <P>Note: more specific test case subclasses provide other methods for finding actions
|
* <P>Note: more specific test case subclasses provide other methods for finding actions
|
||||||
* when you have an owner name (which is usually the plugin name).
|
* when you have an owner name (which is usually the plugin name).
|
||||||
|
@ -1151,8 +1178,7 @@ public abstract class AbstractDockingTest extends AbstractGenericTest {
|
||||||
* @return the matching action; null if no matching action can be found
|
* @return the matching action; null if no matching action can be found
|
||||||
*/
|
*/
|
||||||
public static DockingActionIf getAction(DockingTool tool, String owner, String name) {
|
public static DockingActionIf getAction(DockingTool tool, String owner, String name) {
|
||||||
String fullName = name + " (" + owner + ")";
|
Set<DockingActionIf> actions = getActionsByOwnerAndName(tool, owner, name);
|
||||||
List<DockingActionIf> actions = tool.getDockingActionsByFullActionName(fullName);
|
|
||||||
if (actions.isEmpty()) {
|
if (actions.isEmpty()) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
@ -1160,7 +1186,7 @@ public abstract class AbstractDockingTest extends AbstractGenericTest {
|
||||||
if (actions.size() > 1) {
|
if (actions.size() > 1) {
|
||||||
// This shouldn't happen
|
// This shouldn't happen
|
||||||
throw new AssertionFailedError(
|
throw new AssertionFailedError(
|
||||||
"Found more than one action for name '" + fullName + "'");
|
"Found more than one action for name '" + name + " (" + owner + ")'");
|
||||||
}
|
}
|
||||||
|
|
||||||
return CollectionUtils.any(actions);
|
return CollectionUtils.any(actions);
|
||||||
|
|
|
@ -442,7 +442,9 @@ public abstract class AbstractSortedTableModel<T> extends AbstractGTableModel<T>
|
||||||
public int compare(T t1, T t2) {
|
public int compare(T t1, T t2) {
|
||||||
|
|
||||||
// at this point we compare the rows, since all of the sorting column values are equal
|
// at this point we compare the rows, since all of the sorting column values are equal
|
||||||
if (t1 instanceof Comparable) {
|
// (Warning: there is a chance that the two objects are comparable, but not on each
|
||||||
|
// other. In this case, a ClassCastException will be thrown)
|
||||||
|
if (t1 instanceof Comparable && t2 instanceof Comparable) {
|
||||||
return ((Comparable) t1).compareTo(t2);
|
return ((Comparable) t1).compareTo(t2);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -31,7 +31,7 @@ import javax.swing.table.*;
|
||||||
|
|
||||||
import docking.*;
|
import docking.*;
|
||||||
import docking.action.*;
|
import docking.action.*;
|
||||||
import docking.util.KeyBindingUtils;
|
import docking.actions.KeyBindingUtils;
|
||||||
import docking.widgets.OptionDialog;
|
import docking.widgets.OptionDialog;
|
||||||
import docking.widgets.dialogs.SettingsDialog;
|
import docking.widgets.dialogs.SettingsDialog;
|
||||||
import docking.widgets.filechooser.GhidraFileChooser;
|
import docking.widgets.filechooser.GhidraFileChooser;
|
||||||
|
|
|
@ -36,7 +36,7 @@ import ghidra.framework.options.ToolOptions;
|
||||||
import ghidra.util.Msg;
|
import ghidra.util.Msg;
|
||||||
import ghidra.util.SpyErrorLogger;
|
import ghidra.util.SpyErrorLogger;
|
||||||
|
|
||||||
public class SharedKeybindingDockingActionTest extends AbstractDockingTest {
|
public class SharedKeyBindingDockingActionTest extends AbstractDockingTest {
|
||||||
|
|
||||||
private static final String SHARED_NAME = "Shared Action Name";
|
private static final String SHARED_NAME = "Shared Action Name";
|
||||||
private static final String SHARED_OWNER = SharedStubKeyBindingAction.SHARED_OWNER;
|
private static final String SHARED_OWNER = SharedStubKeyBindingAction.SHARED_OWNER;
|
||||||
|
@ -158,8 +158,7 @@ public class SharedKeybindingDockingActionTest extends AbstractDockingTest {
|
||||||
tool.removeAction(action2);
|
tool.removeAction(action2);
|
||||||
assertActionNotInTool(action2);
|
assertActionNotInTool(action2);
|
||||||
|
|
||||||
String sharedName = action1.getFullName();
|
assertNoSharedKeyBindingStubInstalled(action1);
|
||||||
assertNoSharedKeyBindingStubInstalled(sharedName);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -271,8 +270,7 @@ public class SharedKeybindingDockingActionTest extends AbstractDockingTest {
|
||||||
tool.removeLocalAction(provider, action2);
|
tool.removeLocalAction(provider, action2);
|
||||||
assertActionNotInTool(action2);
|
assertActionNotInTool(action2);
|
||||||
|
|
||||||
String sharedName = action1.getFullName();
|
assertNoSharedKeyBindingStubInstalled(action1);
|
||||||
assertNoSharedKeyBindingStubInstalled(sharedName);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -293,7 +291,65 @@ public class SharedKeybindingDockingActionTest extends AbstractDockingTest {
|
||||||
assertActionNotInTool(action2);
|
assertActionNotInTool(action2);
|
||||||
|
|
||||||
String sharedName = action1.getFullName();
|
String sharedName = action1.getFullName();
|
||||||
assertNoSharedKeyBindingStubInstalled(sharedName);
|
assertNoSharedKeyBindingStubInstalled(action1);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testNonSharedKeyBinding_SameActionAddedTwice() {
|
||||||
|
//
|
||||||
|
// We support adding the same action twice. (This can happen when a transient component
|
||||||
|
// provider is repeatedly shown, such as a search results provider.) Make sure we get
|
||||||
|
// a warning if the same action is added twice, but with different key bindings.
|
||||||
|
//
|
||||||
|
// Note: in this context, two actions are considered to be the same if they share the
|
||||||
|
// same name and owner.
|
||||||
|
//
|
||||||
|
|
||||||
|
TestAction action1 = new TestAction(OWNER_1, DEFAULT_KS_1);
|
||||||
|
TestAction action1Copy = new TestAction(OWNER_1, DEFAULT_KS_1);
|
||||||
|
|
||||||
|
tool.addAction(action1);
|
||||||
|
tool.addAction(action1Copy);
|
||||||
|
assertActionInTool(action1);
|
||||||
|
assertActionInTool(action1Copy);
|
||||||
|
|
||||||
|
assertNoLoggedMessages();
|
||||||
|
|
||||||
|
tool.removeAction(action1);
|
||||||
|
assertActionNotInTool(action1);
|
||||||
|
assertActionInTool(action1Copy);
|
||||||
|
|
||||||
|
tool.removeAction(action1Copy);
|
||||||
|
assertActionNotInTool(action1Copy);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testNonSharedKeyBinding_DifferentActionsWithSameFullName() {
|
||||||
|
//
|
||||||
|
// We support adding the same action twice. (This can happen when a transient component
|
||||||
|
// provider is repeatedly shown, such as a search results provider.) Make sure we get
|
||||||
|
// a warning if the same action is added twice, but with different key bindings.
|
||||||
|
//
|
||||||
|
// Note: in this context, two actions are considered to be the same if they share the
|
||||||
|
// same name and owner.
|
||||||
|
//
|
||||||
|
|
||||||
|
TestAction action1 = new TestAction(OWNER_1, DEFAULT_KS_1);
|
||||||
|
TestAction action1Copy = new TestAction(OWNER_1, DEFAULT_KS_DIFFERENT_THAN_1);
|
||||||
|
|
||||||
|
tool.addAction(action1);
|
||||||
|
tool.addAction(action1Copy);
|
||||||
|
assertActionInTool(action1);
|
||||||
|
assertActionInTool(action1Copy);
|
||||||
|
|
||||||
|
assertImproperDefaultBindingMessage();
|
||||||
|
|
||||||
|
tool.removeAction(action1);
|
||||||
|
assertActionNotInTool(action1);
|
||||||
|
assertActionInTool(action1Copy);
|
||||||
|
|
||||||
|
tool.removeAction(action1Copy);
|
||||||
|
assertActionNotInTool(action1Copy);
|
||||||
}
|
}
|
||||||
|
|
||||||
//==================================================================================================
|
//==================================================================================================
|
||||||
|
@ -317,7 +373,7 @@ public class SharedKeybindingDockingActionTest extends AbstractDockingTest {
|
||||||
|
|
||||||
private void assertActionInTool(TestAction action) {
|
private void assertActionInTool(TestAction action) {
|
||||||
|
|
||||||
Set<DockingActionIf> actions = getActions(tool, action.getName());
|
Set<DockingActionIf> actions = getActionsByName(tool, action.getName());
|
||||||
for (DockingActionIf toolAction : actions) {
|
for (DockingActionIf toolAction : actions) {
|
||||||
if (toolAction == action) {
|
if (toolAction == action) {
|
||||||
return;
|
return;
|
||||||
|
@ -328,16 +384,19 @@ public class SharedKeybindingDockingActionTest extends AbstractDockingTest {
|
||||||
}
|
}
|
||||||
|
|
||||||
private void assertActionNotInTool(TestAction action) {
|
private void assertActionNotInTool(TestAction action) {
|
||||||
Set<DockingActionIf> actions = getActions(tool, action.getName());
|
Set<DockingActionIf> actions = getActionsByName(tool, action.getName());
|
||||||
for (DockingActionIf toolAction : actions) {
|
for (DockingActionIf toolAction : actions) {
|
||||||
assertNotSame(toolAction, action);
|
assertNotSame(toolAction, action);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void assertNoSharedKeyBindingStubInstalled(String sharedName) {
|
private void assertNoSharedKeyBindingStubInstalled(DockingActionIf action) {
|
||||||
List<DockingActionIf> actions = tool.getDockingActionsByFullActionName(sharedName);
|
|
||||||
assertTrue("There should be no actions registered for '" + sharedName + "'",
|
String name = action.getName();
|
||||||
actions.isEmpty());
|
String owner = action.getOwner();
|
||||||
|
DockingActionIf sharedAction = getAction(tool, owner, name);
|
||||||
|
assertNull("There should be no actions registered for '" + name + " (" + owner + ")'",
|
||||||
|
sharedAction);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void setSharedKeyBinding(KeyStroke newKs) {
|
private void setSharedKeyBinding(KeyStroke newKs) {
|
||||||
|
@ -355,7 +414,7 @@ public class SharedKeybindingDockingActionTest extends AbstractDockingTest {
|
||||||
}
|
}
|
||||||
|
|
||||||
private void assertImproperDefaultBindingMessage() {
|
private void assertImproperDefaultBindingMessage() {
|
||||||
spyLogger.assertLogMessage("shared", "key", "binding", "action", "different", "default");
|
spyLogger.assertLogMessage("shared", "key", "binding", "actions", "different", "default");
|
||||||
}
|
}
|
||||||
|
|
||||||
private void assertKeyBinding(TestAction action, KeyStroke expectedKs) {
|
private void assertKeyBinding(TestAction action, KeyStroke expectedKs) {
|
|
@ -26,7 +26,7 @@ import org.junit.Test;
|
||||||
|
|
||||||
import generic.test.AbstractGenericTest;
|
import generic.test.AbstractGenericTest;
|
||||||
|
|
||||||
public class DockingActionKeybindingTest extends AbstractGenericTest {
|
public class DockingActionKeyBindingTest extends AbstractGenericTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testKeybinding_Unmodified() {
|
public void testKeybinding_Unmodified() {
|
|
@ -846,23 +846,25 @@ public class StringUtilities {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Turn the given list into an attractive string, with the separator of you choosing.
|
* Turn the given data into an attractive string, with the separator of your choosing
|
||||||
*
|
*
|
||||||
* @param list the list from which a string will be generated
|
* @param collection the data from which a string will be generated
|
||||||
* @param separator the string used to separate elements
|
* @param separator the string used to separate elements
|
||||||
* @return a string representation of the given list
|
* @return a string representation of the given list
|
||||||
*/
|
*/
|
||||||
public static String toString(List<?> list, String separator) {
|
public static String toString(Collection<?> collection, String separator) {
|
||||||
if (list == null) {
|
if (collection == null) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int i = 0;
|
||||||
StringBuffer buffer = new StringBuffer("[ ");
|
StringBuffer buffer = new StringBuffer("[ ");
|
||||||
for (int i = 0; i < list.size(); i++) {
|
for (Object o : collection) {
|
||||||
buffer.append(list.get(i).toString());
|
buffer.append(o.toString());
|
||||||
if (i + 1 < list.size()) {
|
if (i + 1 < collection.size()) {
|
||||||
buffer.append(separator);
|
buffer.append(separator);
|
||||||
}
|
}
|
||||||
|
i++;
|
||||||
}
|
}
|
||||||
|
|
||||||
buffer.append(" ]");
|
buffer.append(" ]");
|
||||||
|
|
|
@ -22,7 +22,7 @@ import javax.swing.*;
|
||||||
import javax.swing.tree.TreePath;
|
import javax.swing.tree.TreePath;
|
||||||
|
|
||||||
import docking.DockingUtils;
|
import docking.DockingUtils;
|
||||||
import docking.util.KeyBindingUtils;
|
import docking.actions.KeyBindingUtils;
|
||||||
import docking.widgets.tree.*;
|
import docking.widgets.tree.*;
|
||||||
import docking.widgets.tree.support.GTreeRenderer;
|
import docking.widgets.tree.support.GTreeRenderer;
|
||||||
import ghidra.framework.main.FrontEndTool;
|
import ghidra.framework.main.FrontEndTool;
|
||||||
|
|
|
@ -21,6 +21,7 @@ import javax.swing.Icon;
|
||||||
import javax.swing.event.ChangeListener;
|
import javax.swing.event.ChangeListener;
|
||||||
|
|
||||||
import docking.action.DockingActionIf;
|
import docking.action.DockingActionIf;
|
||||||
|
import docking.actions.KeyBindingUtils;
|
||||||
import ghidra.framework.plugintool.util.*;
|
import ghidra.framework.plugintool.util.*;
|
||||||
import ghidra.util.Msg;
|
import ghidra.util.Msg;
|
||||||
import resources.ResourceManager;
|
import resources.ResourceManager;
|
||||||
|
@ -212,12 +213,12 @@ public class PluginConfigurationModel {
|
||||||
* @param pluginDescription The description for which to find loaded actions.
|
* @param pluginDescription The description for which to find loaded actions.
|
||||||
* @return all of the actions loaded by the Plugin represented by the given PluginDescription.
|
* @return all of the actions loaded by the Plugin represented by the given PluginDescription.
|
||||||
*/
|
*/
|
||||||
public List<DockingActionIf> getActionsForPlugin(PluginDescription pluginDescription) {
|
public Set<DockingActionIf> getActionsForPlugin(PluginDescription pluginDescription) {
|
||||||
if (!isLoaded(pluginDescription)) {
|
if (!isLoaded(pluginDescription)) {
|
||||||
return Collections.emptyList();
|
return Collections.emptySet();
|
||||||
}
|
}
|
||||||
|
|
||||||
return tool.getDockingActionsByOwnerName(pluginDescription.getName());
|
return KeyBindingUtils.getKeyBindingActions(tool, pluginDescription.getName());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -20,6 +20,7 @@ import java.beans.PropertyChangeEvent;
|
||||||
import java.beans.PropertyChangeListener;
|
import java.beans.PropertyChangeListener;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Map.Entry;
|
||||||
|
|
||||||
import javax.swing.*;
|
import javax.swing.*;
|
||||||
import javax.swing.event.ListSelectionEvent;
|
import javax.swing.event.ListSelectionEvent;
|
||||||
|
@ -30,8 +31,8 @@ import docking.DockingUtils;
|
||||||
import docking.KeyEntryTextField;
|
import docking.KeyEntryTextField;
|
||||||
import docking.action.DockingActionIf;
|
import docking.action.DockingActionIf;
|
||||||
import docking.action.KeyBindingData;
|
import docking.action.KeyBindingData;
|
||||||
|
import docking.actions.KeyBindingUtils;
|
||||||
import docking.tool.util.DockingToolConstants;
|
import docking.tool.util.DockingToolConstants;
|
||||||
import docking.util.KeyBindingUtils;
|
|
||||||
import docking.widgets.MultiLineLabel;
|
import docking.widgets.MultiLineLabel;
|
||||||
import docking.widgets.OptionDialog;
|
import docking.widgets.OptionDialog;
|
||||||
import docking.widgets.label.GIconLabel;
|
import docking.widgets.label.GIconLabel;
|
||||||
|
@ -39,8 +40,7 @@ import docking.widgets.table.*;
|
||||||
import ghidra.framework.options.Options;
|
import ghidra.framework.options.Options;
|
||||||
import ghidra.framework.options.ToolOptions;
|
import ghidra.framework.options.ToolOptions;
|
||||||
import ghidra.framework.plugintool.PluginTool;
|
import ghidra.framework.plugintool.PluginTool;
|
||||||
import ghidra.util.HTMLUtilities;
|
import ghidra.util.*;
|
||||||
import ghidra.util.ReservedKeyBindings;
|
|
||||||
import ghidra.util.exception.AssertException;
|
import ghidra.util.exception.AssertException;
|
||||||
import ghidra.util.layout.PairLayout;
|
import ghidra.util.layout.PairLayout;
|
||||||
import ghidra.util.layout.VerticalLayout;
|
import ghidra.util.layout.VerticalLayout;
|
||||||
|
@ -65,11 +65,13 @@ public class KeyBindingsPanel extends JPanel {
|
||||||
private KeyBindingsTableModel tableModel;
|
private KeyBindingsTableModel tableModel;
|
||||||
private ListSelectionModel selectionModel;
|
private ListSelectionModel selectionModel;
|
||||||
private Options options;
|
private Options options;
|
||||||
private Map<String, KeyStroke> actionMap; // map action name to keystroke
|
|
||||||
private Map<String, List<String>> keyMap; // map keystroke name to ArrayList of action names
|
private Map<String, DockingActionIf> actionsByFullName;
|
||||||
private List<DockingActionIf> actionList;
|
private Map<String, List<String>> actionNamesByKeyStroke;
|
||||||
private Map<String, KeyStroke> originalValues; // original mapping for action name to
|
private Map<String, KeyStroke> keyStrokesByFullName;
|
||||||
// keystroke (to know what changed)
|
private Map<String, KeyStroke> originalValues; // to know what has been changed
|
||||||
|
private List<DockingActionIf> tableActions;
|
||||||
|
|
||||||
private KeyEntryTextField ksField;
|
private KeyEntryTextField ksField;
|
||||||
private boolean unappliedChanges;
|
private boolean unappliedChanges;
|
||||||
|
|
||||||
|
@ -81,7 +83,7 @@ public class KeyBindingsPanel extends JPanel {
|
||||||
public KeyBindingsPanel(PluginTool tool, Options options) {
|
public KeyBindingsPanel(PluginTool tool, Options options) {
|
||||||
this.tool = tool;
|
this.tool = tool;
|
||||||
this.options = options;
|
this.options = options;
|
||||||
actionList = new ArrayList<>();
|
tableActions = new ArrayList<>();
|
||||||
create();
|
create();
|
||||||
createActionMap();
|
createActionMap();
|
||||||
addListeners();
|
addListeners();
|
||||||
|
@ -100,10 +102,10 @@ public class KeyBindingsPanel extends JPanel {
|
||||||
* Apply the changes to the actions.
|
* Apply the changes to the actions.
|
||||||
*/
|
*/
|
||||||
public void apply() {
|
public void apply() {
|
||||||
Iterator<String> iter = actionMap.keySet().iterator();
|
Iterator<String> iter = keyStrokesByFullName.keySet().iterator();
|
||||||
while (iter.hasNext()) {
|
while (iter.hasNext()) {
|
||||||
String actionName = iter.next();
|
String actionName = iter.next();
|
||||||
KeyStroke currentKeyStroke = actionMap.get(actionName);
|
KeyStroke currentKeyStroke = keyStrokesByFullName.get(actionName);
|
||||||
KeyStroke originalKeyStroke = originalValues.get(actionName);
|
KeyStroke originalKeyStroke = originalValues.get(actionName);
|
||||||
updateOptions(actionName, originalKeyStroke, currentKeyStroke);
|
updateOptions(actionName, originalKeyStroke, currentKeyStroke);
|
||||||
}
|
}
|
||||||
|
@ -111,7 +113,7 @@ public class KeyBindingsPanel extends JPanel {
|
||||||
changesMade(false);
|
changesMade(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean updateOptions(String actionName, KeyStroke currentKeyStroke,
|
private boolean updateOptions(String fullActionName, KeyStroke currentKeyStroke,
|
||||||
KeyStroke newKeyStroke) {
|
KeyStroke newKeyStroke) {
|
||||||
if ((currentKeyStroke != null && currentKeyStroke.equals(newKeyStroke)) ||
|
if ((currentKeyStroke != null && currentKeyStroke.equals(newKeyStroke)) ||
|
||||||
(currentKeyStroke == null && newKeyStroke == null)) {
|
(currentKeyStroke == null && newKeyStroke == null)) {
|
||||||
|
@ -119,17 +121,17 @@ public class KeyBindingsPanel extends JPanel {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (newKeyStroke != null) {
|
if (newKeyStroke != null) {
|
||||||
options.setKeyStroke(actionName, newKeyStroke);
|
options.setKeyStroke(fullActionName, newKeyStroke);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
options.removeOption(actionName);
|
options.removeOption(fullActionName);
|
||||||
}
|
}
|
||||||
originalValues.put(actionName, newKeyStroke);
|
originalValues.put(fullActionName, newKeyStroke);
|
||||||
actionMap.put(actionName, newKeyStroke);
|
keyStrokesByFullName.put(fullActionName, newKeyStroke);
|
||||||
|
|
||||||
List<DockingActionIf> actions = tool.getDockingActionsByFullActionName(actionName);
|
Set<DockingActionIf> actions = tool.getAllActions();
|
||||||
for (DockingActionIf action : actions) {
|
for (DockingActionIf action : actions) {
|
||||||
if (action.isKeyBindingManaged()) {
|
if (action.getFullName().equals(fullActionName)) {
|
||||||
action.setUnvalidatedKeyBindingData(new KeyBindingData(newKeyStroke));
|
action.setUnvalidatedKeyBindingData(new KeyBindingData(newKeyStroke));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -145,46 +147,40 @@ public class KeyBindingsPanel extends JPanel {
|
||||||
while (iter.hasNext()) {
|
while (iter.hasNext()) {
|
||||||
String actionName = iter.next();
|
String actionName = iter.next();
|
||||||
KeyStroke originalKS = originalValues.get(actionName);
|
KeyStroke originalKS = originalValues.get(actionName);
|
||||||
KeyStroke modifiedKS = actionMap.get(actionName);
|
KeyStroke modifiedKS = keyStrokesByFullName.get(actionName);
|
||||||
if (modifiedKS != null && !modifiedKS.equals(originalKS)) {
|
if (modifiedKS != null && !modifiedKS.equals(originalKS)) {
|
||||||
actionMap.put(actionName, originalKS);
|
keyStrokesByFullName.put(actionName, originalKS);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
tableModel.fireTableDataChanged();
|
tableModel.fireTableDataChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void reload() {
|
public void reload() {
|
||||||
// run this after the current pending events in the swing
|
Swing.runLater(() -> {
|
||||||
// thread so that the screen will repaint itself
|
// clear the current user key stroke so that it does not appear as though the
|
||||||
SwingUtilities.invokeLater(() -> {
|
// user is editing while restoring
|
||||||
// clear the current user key stroke so that it does not
|
|
||||||
// appear as though the user is editing while restoring
|
|
||||||
actionTable.clearSelection();
|
actionTable.clearSelection();
|
||||||
|
|
||||||
restoreDefaultKeybindings();
|
restoreDefaultKeybindings();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Create the maps for actions and names.
|
|
||||||
*/
|
|
||||||
private void createActionMap() {
|
private void createActionMap() {
|
||||||
actionMap = new HashMap<>();
|
keyStrokesByFullName = new HashMap<>();
|
||||||
keyMap = new HashMap<>();
|
actionNamesByKeyStroke = new HashMap<>();
|
||||||
originalValues = new HashMap<>();
|
originalValues = new HashMap<>();
|
||||||
String longestName = "";
|
String longestName = "";
|
||||||
|
|
||||||
List<DockingActionIf> actions = tool.getAllActions();
|
actionsByFullName = KeyBindingUtils.getAllKeyBindingActions(tool);
|
||||||
for (DockingActionIf action : actions) {
|
Set<Entry<String, DockingActionIf>> entries = actionsByFullName.entrySet();
|
||||||
if (isIgnored(action)) {
|
for (Entry<String, DockingActionIf> entry : entries) {
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
String actionName = action.getFullName();
|
DockingActionIf action = entry.getValue();
|
||||||
actionList.add(action);
|
tableActions.add(action);
|
||||||
|
|
||||||
|
String actionName = entry.getKey();
|
||||||
KeyStroke ks = options.getKeyStroke(actionName, null);
|
KeyStroke ks = options.getKeyStroke(actionName, null);
|
||||||
actionMap.put(actionName, ks);
|
keyStrokesByFullName.put(actionName, ks);
|
||||||
addToKeyMap(ks, actionName);
|
addToKeyMap(ks, actionName);
|
||||||
originalValues.put(actionName, ks);
|
originalValues.put(actionName, ks);
|
||||||
|
|
||||||
|
@ -206,12 +202,6 @@ public class KeyBindingsPanel extends JPanel {
|
||||||
tableModel.fireTableDataChanged();
|
tableModel.fireTableDataChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean isIgnored(DockingActionIf action) {
|
|
||||||
// not keybinding managed; a shared keybinding implies that this action should not be in
|
|
||||||
// the UI, as there will be a single proxy in place of all actions sharing that binding
|
|
||||||
return !action.isKeyBindingManaged() || action.usesSharedKeyBinding();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create the components in this panel.
|
* Create the components in this panel.
|
||||||
*/
|
*/
|
||||||
|
@ -328,11 +318,10 @@ public class KeyBindingsPanel extends JPanel {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// run this after the current pending events in the swing
|
// give Swing a chance to repaint
|
||||||
// thread so that the screen will repaint itself
|
Swing.runLater(() -> {
|
||||||
SwingUtilities.invokeLater(() -> {
|
// clear the current user key stroke so that it does not appear as though the
|
||||||
// clear the current user key stroke so that it does not
|
// user is editing while importing
|
||||||
// appear as though the user is editing while importing
|
|
||||||
actionTable.clearSelection();
|
actionTable.clearSelection();
|
||||||
processKeyBindingsFromOptions(KeyBindingUtils.importKeyBindings());
|
processKeyBindingsFromOptions(KeyBindingUtils.importKeyBindings());
|
||||||
});
|
});
|
||||||
|
@ -349,9 +338,8 @@ public class KeyBindingsPanel extends JPanel {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// run this after the current pending events in the swing
|
// give Swing a chance to repaint
|
||||||
// thread so that the screen will repaint itself
|
Swing.runLater(() -> {
|
||||||
SwingUtilities.invokeLater(() -> {
|
|
||||||
ToolOptions keyBindingOptions = tool.getOptions(DockingToolConstants.KEY_BINDINGS);
|
ToolOptions keyBindingOptions = tool.getOptions(DockingToolConstants.KEY_BINDINGS);
|
||||||
KeyBindingUtils.exportKeyBindings(keyBindingOptions);
|
KeyBindingUtils.exportKeyBindings(keyBindingOptions);
|
||||||
});
|
});
|
||||||
|
@ -421,16 +409,16 @@ public class KeyBindingsPanel extends JPanel {
|
||||||
}
|
}
|
||||||
|
|
||||||
private void restoreDefaultKeybindings() {
|
private void restoreDefaultKeybindings() {
|
||||||
Iterator<String> iter = actionMap.keySet().iterator();
|
Iterator<String> iter = keyStrokesByFullName.keySet().iterator();
|
||||||
while (iter.hasNext()) {
|
while (iter.hasNext()) {
|
||||||
String actionName = iter.next();
|
String actionName = iter.next();
|
||||||
List<DockingActionIf> actions = tool.getDockingActionsByFullActionName(actionName);
|
DockingActionIf action = actionsByFullName.get(actionName);
|
||||||
if (actions.size() == 0) {
|
if (action == null) {
|
||||||
throw new AssertException("No actions defined for " + actionName);
|
throw new AssertException("No actions defined for " + actionName);
|
||||||
}
|
}
|
||||||
|
|
||||||
KeyStroke currentKeyStroke = actionMap.get(actionName);
|
KeyStroke currentKeyStroke = keyStrokesByFullName.get(actionName);
|
||||||
KeyBindingData defaultBinding = actions.get(0).getDefaultKeyBindingData();
|
KeyBindingData defaultBinding = action.getDefaultKeyBindingData();
|
||||||
KeyStroke newKeyStroke =
|
KeyStroke newKeyStroke =
|
||||||
(defaultBinding == null) ? null : defaultBinding.getKeyBinding();
|
(defaultBinding == null) ? null : defaultBinding.getKeyBinding();
|
||||||
|
|
||||||
|
@ -453,7 +441,7 @@ public class KeyBindingsPanel extends JPanel {
|
||||||
String ksName = KeyEntryTextField.parseKeyStroke(keyStroke);
|
String ksName = KeyEntryTextField.parseKeyStroke(keyStroke);
|
||||||
|
|
||||||
// remove old keystroke for action name
|
// remove old keystroke for action name
|
||||||
KeyStroke oldKs = actionMap.get(actionName);
|
KeyStroke oldKs = keyStrokesByFullName.get(actionName);
|
||||||
if (oldKs != null) {
|
if (oldKs != null) {
|
||||||
String oldName = KeyEntryTextField.parseKeyStroke(oldKs);
|
String oldName = KeyEntryTextField.parseKeyStroke(oldKs);
|
||||||
if (oldName.equals(ksName)) {
|
if (oldName.equals(ksName)) {
|
||||||
|
@ -463,7 +451,7 @@ public class KeyBindingsPanel extends JPanel {
|
||||||
}
|
}
|
||||||
addToKeyMap(keyStroke, actionName);
|
addToKeyMap(keyStroke, actionName);
|
||||||
|
|
||||||
actionMap.put(actionName, keyStroke);
|
keyStrokesByFullName.put(actionName, keyStroke);
|
||||||
changesMade(true);
|
changesMade(true);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -486,7 +474,7 @@ public class KeyBindingsPanel extends JPanel {
|
||||||
}
|
}
|
||||||
int selectedRow = actionTable.getSelectedRow();
|
int selectedRow = actionTable.getSelectedRow();
|
||||||
int modelRow = tableFilterPanel.getModelRow(selectedRow);
|
int modelRow = tableFilterPanel.getModelRow(selectedRow);
|
||||||
return actionList.get(modelRow).getFullName();
|
return tableActions.get(modelRow).getFullName();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -497,10 +485,10 @@ public class KeyBindingsPanel extends JPanel {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
String ksName = KeyEntryTextField.parseKeyStroke(ks);
|
String ksName = KeyEntryTextField.parseKeyStroke(ks);
|
||||||
List<String> list = keyMap.get(ksName);
|
List<String> list = actionNamesByKeyStroke.get(ksName);
|
||||||
if (list == null) {
|
if (list == null) {
|
||||||
list = new ArrayList<>();
|
list = new ArrayList<>();
|
||||||
keyMap.put(ksName, list);
|
actionNamesByKeyStroke.put(ksName, list);
|
||||||
}
|
}
|
||||||
if (!list.contains(actionName)) {
|
if (!list.contains(actionName)) {
|
||||||
list.add(actionName);
|
list.add(actionName);
|
||||||
|
@ -515,11 +503,11 @@ public class KeyBindingsPanel extends JPanel {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
String ksName = KeyEntryTextField.parseKeyStroke(ks);
|
String ksName = KeyEntryTextField.parseKeyStroke(ks);
|
||||||
List<String> list = keyMap.get(ksName);
|
List<String> list = actionNamesByKeyStroke.get(ksName);
|
||||||
if (list != null) {
|
if (list != null) {
|
||||||
list.remove(actionName);
|
list.remove(actionName);
|
||||||
if (list.isEmpty()) {
|
if (list.isEmpty()) {
|
||||||
keyMap.remove(ksName);
|
actionNamesByKeyStroke.remove(ksName);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -529,7 +517,7 @@ public class KeyBindingsPanel extends JPanel {
|
||||||
* @param ksName name of Keystroke that has multiple actions mapped
|
* @param ksName name of Keystroke that has multiple actions mapped
|
||||||
*/
|
*/
|
||||||
private void showActionMapped(String ksName) {
|
private void showActionMapped(String ksName) {
|
||||||
List<String> list = keyMap.get(ksName);
|
List<String> list = actionNamesByKeyStroke.get(ksName);
|
||||||
if (list == null) {
|
if (list == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -595,7 +583,7 @@ public class KeyBindingsPanel extends JPanel {
|
||||||
// prevent non-existing keybindings from being added to Ghidra (this can happen
|
// prevent non-existing keybindings from being added to Ghidra (this can happen
|
||||||
// when actions exist in the imported bindings, but have been removed from
|
// when actions exist in the imported bindings, but have been removed from
|
||||||
// Ghidra
|
// Ghidra
|
||||||
if (!actionMap.containsKey(name)) {
|
if (!keyStrokesByFullName.containsKey(name)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -647,12 +635,10 @@ public class KeyBindingsPanel extends JPanel {
|
||||||
char keyChar = keyStroke.getKeyChar();
|
char keyChar = keyStroke.getKeyChar();
|
||||||
if (Character.isWhitespace(keyChar) ||
|
if (Character.isWhitespace(keyChar) ||
|
||||||
Character.getType(keyChar) == Character.DIRECTIONALITY_LEFT_TO_RIGHT_OVERRIDE) {
|
Character.getType(keyChar) == Character.DIRECTIONALITY_LEFT_TO_RIGHT_OVERRIDE) {
|
||||||
// remove keystroke
|
|
||||||
removeKeystroke(actionName);
|
removeKeystroke(actionName);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
// check the action to see if is different than the current
|
// check the action to see if is different than the current value
|
||||||
// value
|
|
||||||
return checkAction(actionName, keyStroke);
|
return checkAction(actionName, keyStroke);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -663,20 +649,24 @@ public class KeyBindingsPanel extends JPanel {
|
||||||
private void removeKeystroke(String selectedActionName) {
|
private void removeKeystroke(String selectedActionName) {
|
||||||
ksField.setText("");
|
ksField.setText("");
|
||||||
|
|
||||||
if (actionMap.containsKey(selectedActionName)) {
|
if (keyStrokesByFullName.containsKey(selectedActionName)) {
|
||||||
KeyStroke stroke = actionMap.get(selectedActionName);
|
KeyStroke stroke = keyStrokesByFullName.get(selectedActionName);
|
||||||
if (stroke == null) {
|
if (stroke == null) {
|
||||||
// nothing to remove; nothing has changed
|
// nothing to remove; nothing has changed
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
removeFromKeyMap(stroke, selectedActionName);
|
removeFromKeyMap(stroke, selectedActionName);
|
||||||
actionMap.put(selectedActionName, null);
|
keyStrokesByFullName.put(selectedActionName, null);
|
||||||
tableModel.fireTableDataChanged();
|
tableModel.fireTableDataChanged();
|
||||||
changesMade(true);
|
changesMade(true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Map<String, KeyStroke> getKeyStrokeMap() {
|
||||||
|
return keyStrokesByFullName;
|
||||||
|
}
|
||||||
|
|
||||||
//==================================================================================================
|
//==================================================================================================
|
||||||
// Inner Classes
|
// Inner Classes
|
||||||
//==================================================================================================
|
//==================================================================================================
|
||||||
|
@ -690,8 +680,12 @@ public class KeyBindingsPanel extends JPanel {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
String selectedAction = getSelectedAction();
|
String fullActionName = getSelectedAction();
|
||||||
KeyStroke ks = actionMap.get(selectedAction);
|
if (fullActionName == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
KeyStroke ks = keyStrokesByFullName.get(fullActionName);
|
||||||
String ksName = "";
|
String ksName = "";
|
||||||
clearInfoPanel();
|
clearInfoPanel();
|
||||||
|
|
||||||
|
@ -705,18 +699,12 @@ public class KeyBindingsPanel extends JPanel {
|
||||||
statusLabel.setPreferredSize(
|
statusLabel.setPreferredSize(
|
||||||
new Dimension(statusLabel.getPreferredSize().width, STATUS_LABEL_HEIGHT));
|
new Dimension(statusLabel.getPreferredSize().width, STATUS_LABEL_HEIGHT));
|
||||||
|
|
||||||
try {
|
DockingActionIf action = actionsByFullName.get(fullActionName);
|
||||||
List<DockingActionIf> actions =
|
String description = action.getDescription();
|
||||||
tool.getDockingActionsByFullActionName(selectedAction);
|
if (description == null || description.trim().isEmpty()) {
|
||||||
String description = actions.get(0).getDescription();
|
description = action.getName();
|
||||||
if (description == null || description.trim().isEmpty()) {
|
|
||||||
description = actions.get(0).getName();
|
|
||||||
}
|
|
||||||
statusLabel.setText("<html>" + HTMLUtilities.escapeHTML(description));
|
|
||||||
}
|
|
||||||
catch (Exception ex) {
|
|
||||||
statusLabel.setText("");
|
|
||||||
}
|
}
|
||||||
|
statusLabel.setText("<html>" + HTMLUtilities.escapeHTML(description));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -740,7 +728,7 @@ public class KeyBindingsPanel extends JPanel {
|
||||||
return action.getName();
|
return action.getName();
|
||||||
|
|
||||||
case KEY_BINDING:
|
case KEY_BINDING:
|
||||||
KeyStroke ks = actionMap.get(action.getFullName());
|
KeyStroke ks = keyStrokesByFullName.get(action.getFullName());
|
||||||
if (ks != null) {
|
if (ks != null) {
|
||||||
return KeyEntryTextField.parseKeyStroke(ks);
|
return KeyEntryTextField.parseKeyStroke(ks);
|
||||||
}
|
}
|
||||||
|
@ -753,7 +741,7 @@ public class KeyBindingsPanel extends JPanel {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<DockingActionIf> getModelData() {
|
public List<DockingActionIf> getModelData() {
|
||||||
return actionList;
|
return tableActions;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -773,7 +761,7 @@ public class KeyBindingsPanel extends JPanel {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int getRowCount() {
|
public int getRowCount() {
|
||||||
return actionList.size();
|
return tableActions.size();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,8 +17,7 @@ package ghidra.framework.plugintool.dialog;
|
||||||
|
|
||||||
import java.awt.Color;
|
import java.awt.Color;
|
||||||
import java.awt.Point;
|
import java.awt.Point;
|
||||||
import java.util.Collections;
|
import java.util.*;
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import javax.swing.KeyStroke;
|
import javax.swing.KeyStroke;
|
||||||
import javax.swing.text.SimpleAttributeSet;
|
import javax.swing.text.SimpleAttributeSet;
|
||||||
|
@ -35,9 +34,9 @@ import ghidra.framework.plugintool.util.PluginStatus;
|
||||||
* Panel that contains a JTextPane to show plugin description information.
|
* Panel that contains a JTextPane to show plugin description information.
|
||||||
*/
|
*/
|
||||||
class PluginDetailsPanel extends AbstractDetailsPanel {
|
class PluginDetailsPanel extends AbstractDetailsPanel {
|
||||||
|
|
||||||
private static SimpleAttributeSet nameAttrSet;
|
private static SimpleAttributeSet nameAttrSet;
|
||||||
private static SimpleAttributeSet depNameAttrSet;
|
private static SimpleAttributeSet depNameAttrSet;
|
||||||
private static SimpleAttributeSet descrAttrSet;
|
private static SimpleAttributeSet descrAttrSet;
|
||||||
private static SimpleAttributeSet categoriesAttrSet;
|
private static SimpleAttributeSet categoriesAttrSet;
|
||||||
private static SimpleAttributeSet classAttrSet;
|
private static SimpleAttributeSet classAttrSet;
|
||||||
|
@ -47,84 +46,62 @@ class PluginDetailsPanel extends AbstractDetailsPanel {
|
||||||
private static SimpleAttributeSet noValueAttrSet;
|
private static SimpleAttributeSet noValueAttrSet;
|
||||||
|
|
||||||
private final PluginConfigurationModel model;
|
private final PluginConfigurationModel model;
|
||||||
|
|
||||||
PluginDetailsPanel(PluginConfigurationModel model) {
|
PluginDetailsPanel(PluginConfigurationModel model) {
|
||||||
super();
|
super();
|
||||||
this.model = model;
|
this.model = model;
|
||||||
createFieldAttributes();
|
createFieldAttributes();
|
||||||
createMainPanel();
|
createMainPanel();
|
||||||
}
|
}
|
||||||
|
|
||||||
void setPluginDescription(PluginDescription pluginDescription) {
|
void setPluginDescription(PluginDescription pluginDescription) {
|
||||||
|
|
||||||
textLabel.setText("");
|
textLabel.setText("");
|
||||||
if (pluginDescription == null) {
|
if (pluginDescription == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
List<PluginDescription> dependencies = model.getDependencies(pluginDescription);
|
List<PluginDescription> dependencies = model.getDependencies(pluginDescription);
|
||||||
Collections.sort(dependencies, (pd1, pd2) -> pd1.getName().compareTo(pd2.getName()));
|
Collections.sort(dependencies, (pd1, pd2) -> pd1.getName().compareTo(pd2.getName()));
|
||||||
|
|
||||||
StringBuilder buffer = new StringBuilder("<HTML>");
|
StringBuilder buffer = new StringBuilder("<HTML>");
|
||||||
|
|
||||||
buffer.append( "<TABLE cellpadding=2>" );
|
buffer.append("<TABLE cellpadding=2>");
|
||||||
|
|
||||||
insertRowTitle(buffer, "Name");
|
insertRowTitle(buffer, "Name");
|
||||||
insertRowValue(buffer, pluginDescription.getName(),
|
insertRowValue(buffer, pluginDescription.getName(),
|
||||||
!dependencies.isEmpty() ? depNameAttrSet : nameAttrSet);
|
!dependencies.isEmpty() ? depNameAttrSet : nameAttrSet);
|
||||||
|
|
||||||
insertRowTitle(buffer, "Description");
|
insertRowTitle(buffer, "Description");
|
||||||
insertRowValue(buffer, formatDescription(pluginDescription.getDescription()), descrAttrSet);
|
insertRowValue(buffer, formatDescription(pluginDescription.getDescription()), descrAttrSet);
|
||||||
|
|
||||||
insertRowTitle(buffer, "Status");
|
insertRowTitle(buffer, "Status");
|
||||||
insertRowValue(buffer,
|
insertRowValue(buffer, pluginDescription.getStatus().getDescription(),
|
||||||
pluginDescription.getStatus().getDescription(),
|
(pluginDescription.getStatus() == PluginStatus.RELEASED) ? titleAttrSet
|
||||||
(pluginDescription.getStatus() == PluginStatus.RELEASED) ?
|
: developerAttrSet);
|
||||||
titleAttrSet :developerAttrSet);
|
|
||||||
|
|
||||||
insertRowTitle(buffer, "Package");
|
insertRowTitle(buffer, "Package");
|
||||||
insertRowValue(buffer, pluginDescription.getPluginPackage().getName(), categoriesAttrSet);
|
insertRowValue(buffer, pluginDescription.getPluginPackage().getName(), categoriesAttrSet);
|
||||||
|
|
||||||
insertRowTitle(buffer, "Category");
|
insertRowTitle(buffer, "Category");
|
||||||
insertRowValue(buffer, pluginDescription.getCategory(), categoriesAttrSet);
|
insertRowValue(buffer, pluginDescription.getCategory(), categoriesAttrSet);
|
||||||
|
|
||||||
insertRowTitle(buffer, "Plugin Class");
|
insertRowTitle(buffer, "Plugin Class");
|
||||||
insertRowValue(buffer, pluginDescription.getPluginClass().getName(), classAttrSet);
|
insertRowValue(buffer, pluginDescription.getPluginClass().getName(), classAttrSet);
|
||||||
|
|
||||||
insertRowTitle(buffer, "Class Location");
|
insertRowTitle(buffer, "Class Location");
|
||||||
insertRowValue(buffer, pluginDescription.getSourceLocation(), locAttrSet);
|
insertRowValue(buffer, pluginDescription.getSourceLocation(), locAttrSet);
|
||||||
|
|
||||||
insertRowTitle(buffer, "Used By");
|
insertRowTitle(buffer, "Used By");
|
||||||
|
|
||||||
buffer.append( "<TD VALIGN=\"TOP\">" );
|
|
||||||
|
|
||||||
if (dependencies.isEmpty()) {
|
|
||||||
insertHTMLLine("None", titleAttrSet, buffer);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
for (int i = 0; i < dependencies.size(); i++) {
|
|
||||||
insertHTMLString(dependencies.get(i).getPluginClass().getName(), dependencyAttrSet,
|
|
||||||
buffer);
|
|
||||||
if (i < dependencies.size() - 1) {
|
|
||||||
insertHTMLString("<BR>", dependencyAttrSet, buffer);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
insertHTMLLine("", titleAttrSet, buffer); // add a newline
|
|
||||||
}
|
|
||||||
buffer.append( "</TD>" );
|
|
||||||
buffer.append( "</TR>" );
|
|
||||||
|
|
||||||
insertRowTitle(buffer, "Services Required");
|
|
||||||
|
|
||||||
buffer.append("<TD VALIGN=\"TOP\">");
|
buffer.append("<TD VALIGN=\"TOP\">");
|
||||||
|
|
||||||
List<Class<?>> servicesRequired = pluginDescription.getServicesRequired();
|
if (dependencies.isEmpty()) {
|
||||||
if (servicesRequired.isEmpty()) {
|
|
||||||
insertHTMLLine("None", titleAttrSet, buffer);
|
insertHTMLLine("None", titleAttrSet, buffer);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
for (int i = 0; i < servicesRequired.size(); i++) {
|
for (int i = 0; i < dependencies.size(); i++) {
|
||||||
insertHTMLString(servicesRequired.get(i).getName(), dependencyAttrSet,
|
insertHTMLString(dependencies.get(i).getPluginClass().getName(), dependencyAttrSet,
|
||||||
buffer);
|
buffer);
|
||||||
if (i < dependencies.size() - 1) {
|
if (i < dependencies.size() - 1) {
|
||||||
insertHTMLString("<BR>", dependencyAttrSet, buffer);
|
insertHTMLString("<BR>", dependencyAttrSet, buffer);
|
||||||
|
@ -135,165 +112,185 @@ class PluginDetailsPanel extends AbstractDetailsPanel {
|
||||||
buffer.append("</TD>");
|
buffer.append("</TD>");
|
||||||
buffer.append("</TR>");
|
buffer.append("</TR>");
|
||||||
|
|
||||||
//
|
insertRowTitle(buffer, "Services Required");
|
||||||
// Developer
|
|
||||||
//
|
|
||||||
//
|
|
||||||
// Optional: Actions loaded by this plugin
|
|
||||||
//
|
|
||||||
addLoadedActionsContent( buffer, pluginDescription );
|
|
||||||
|
|
||||||
buffer.append( "</TABLE>" );
|
|
||||||
|
|
||||||
textLabel.setText( buffer.toString() );
|
buffer.append("<TD VALIGN=\"TOP\">");
|
||||||
sp.getViewport().setViewPosition(new Point(0,0));
|
|
||||||
}
|
List<Class<?>> servicesRequired = pluginDescription.getServicesRequired();
|
||||||
|
if (servicesRequired.isEmpty()) {
|
||||||
|
insertHTMLLine("None", titleAttrSet, buffer);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
for (int i = 0; i < servicesRequired.size(); i++) {
|
||||||
|
insertHTMLString(servicesRequired.get(i).getName(), dependencyAttrSet, buffer);
|
||||||
|
if (i < dependencies.size() - 1) {
|
||||||
|
insertHTMLString("<BR>", dependencyAttrSet, buffer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
insertHTMLLine("", titleAttrSet, buffer); // add a newline
|
||||||
|
}
|
||||||
|
buffer.append("</TD>");
|
||||||
|
buffer.append("</TR>");
|
||||||
|
|
||||||
|
//
|
||||||
|
// Developer
|
||||||
|
//
|
||||||
|
//
|
||||||
|
// Optional: Actions loaded by this plugin
|
||||||
|
//
|
||||||
|
addLoadedActionsContent(buffer, pluginDescription);
|
||||||
|
|
||||||
|
buffer.append("</TABLE>");
|
||||||
|
|
||||||
|
textLabel.setText(buffer.toString());
|
||||||
|
sp.getViewport().setViewPosition(new Point(0, 0));
|
||||||
|
}
|
||||||
|
|
||||||
// creates an HTML table to display actions loaded by the plugin
|
// creates an HTML table to display actions loaded by the plugin
|
||||||
private void addLoadedActionsContent(StringBuilder buffer,
|
private void addLoadedActionsContent(StringBuilder buffer,
|
||||||
PluginDescription pluginDescription) {
|
PluginDescription pluginDescription) {
|
||||||
if ( !model.isLoaded( pluginDescription ) ) {
|
if (!model.isLoaded(pluginDescription)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
buffer.append( "<TR>" );
|
|
||||||
buffer.append( "<TD VALIGN=\"TOP\">" );
|
|
||||||
insertHTMLLine("Loaded Actions:", titleAttrSet, buffer);
|
|
||||||
buffer.append( "</TD>" );
|
|
||||||
|
|
||||||
List<DockingActionIf> actionList = model.getActionsForPlugin( pluginDescription );
|
buffer.append("<TR>");
|
||||||
if ( actionList.size() == 0 ) {
|
buffer.append("<TD VALIGN=\"TOP\">");
|
||||||
buffer.append( "<TD VALIGN=\"TOP\">" );
|
insertHTMLLine("Loaded Actions:", titleAttrSet, buffer);
|
||||||
insertHTMLLine("No actions for plugin", noValueAttrSet, buffer);
|
buffer.append("</TD>");
|
||||||
buffer.append( "</TD>" );
|
|
||||||
buffer.append( "</TR>" );
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
buffer.append( "<TD VALIGN=\"TOP\">" );
|
|
||||||
|
|
||||||
buffer.append( "<TABLE BORDER=1><TR><TH>Action Name</TH><TH>Menu Path</TH><TH>Keybinding</TH></TR>" );
|
|
||||||
|
|
||||||
for ( DockingActionIf dockableAction : actionList ) {
|
|
||||||
buffer.append( "<TR><TD WIDTH=\"200\">" );
|
|
||||||
insertHTMLString( dockableAction.getName(), locAttrSet, buffer );
|
|
||||||
buffer.append( "</TD>" );
|
|
||||||
|
|
||||||
buffer.append( "<TD WIDTH=\"300\">" );
|
|
||||||
MenuData menuBarData = dockableAction.getMenuBarData();
|
|
||||||
String[] menuPath = menuBarData == null ? null : menuBarData.getMenuPath();
|
|
||||||
String menuPathString = createStringForMenuPath( menuPath );
|
|
||||||
if ( menuPathString != null ) {
|
|
||||||
insertHTMLString( menuPathString, locAttrSet, buffer );
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
MenuData popupMenuData = dockableAction.getPopupMenuData();
|
|
||||||
String[] popupPath = popupMenuData == null ? null : popupMenuData.getMenuPath();
|
|
||||||
|
|
||||||
if ( popupPath != null ) {
|
Set<DockingActionIf> actions = model.getActionsForPlugin(pluginDescription);
|
||||||
insertHTMLString( "(in a context popup menu)", noValueAttrSet, buffer );
|
if (actions.size() == 0) {
|
||||||
}
|
buffer.append("<TD VALIGN=\"TOP\">");
|
||||||
else {
|
insertHTMLLine("No actions for plugin", noValueAttrSet, buffer);
|
||||||
insertHTMLString( "Not in a menu", noValueAttrSet, buffer );
|
buffer.append("</TD>");
|
||||||
}
|
buffer.append("</TR>");
|
||||||
}
|
return;
|
||||||
|
}
|
||||||
buffer.append( "</TD>" );
|
|
||||||
|
buffer.append("<TD VALIGN=\"TOP\">");
|
||||||
buffer.append( "<TD WIDTH=\"100\">" );
|
|
||||||
KeyStroke keyBinding = dockableAction.getKeyBinding();
|
buffer.append(
|
||||||
if ( keyBinding != null ) {
|
"<TABLE BORDER=1><TR><TH>Action Name</TH><TH>Menu Path</TH><TH>Keybinding</TH></TR>");
|
||||||
String keyStrokeString = DockingKeyBindingAction.parseKeyStroke( keyBinding );
|
|
||||||
insertHTMLString( keyStrokeString, locAttrSet, buffer );
|
for (DockingActionIf dockableAction : actions) {
|
||||||
}
|
buffer.append("<TR><TD WIDTH=\"200\">");
|
||||||
else {
|
insertHTMLString(dockableAction.getName(), locAttrSet, buffer);
|
||||||
insertHTMLString( "No keybinding", noValueAttrSet, buffer );
|
buffer.append("</TD>");
|
||||||
}
|
|
||||||
|
buffer.append("<TD WIDTH=\"300\">");
|
||||||
buffer.append( "</TD></TR>" );
|
MenuData menuBarData = dockableAction.getMenuBarData();
|
||||||
}
|
String[] menuPath = menuBarData == null ? null : menuBarData.getMenuPath();
|
||||||
|
String menuPathString = createStringForMenuPath(menuPath);
|
||||||
buffer.append( "</TABLE>" );
|
if (menuPathString != null) {
|
||||||
buffer.append( "</TD>" );
|
insertHTMLString(menuPathString, locAttrSet, buffer);
|
||||||
buffer.append( "</TR>" );
|
}
|
||||||
|
else {
|
||||||
|
MenuData popupMenuData = dockableAction.getPopupMenuData();
|
||||||
|
String[] popupPath = popupMenuData == null ? null : popupMenuData.getMenuPath();
|
||||||
|
|
||||||
|
if (popupPath != null) {
|
||||||
|
insertHTMLString("(in a context popup menu)", noValueAttrSet, buffer);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
insertHTMLString("Not in a menu", noValueAttrSet, buffer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
buffer.append("</TD>");
|
||||||
|
|
||||||
|
buffer.append("<TD WIDTH=\"100\">");
|
||||||
|
KeyStroke keyBinding = dockableAction.getKeyBinding();
|
||||||
|
if (keyBinding != null) {
|
||||||
|
String keyStrokeString = DockingKeyBindingAction.parseKeyStroke(keyBinding);
|
||||||
|
insertHTMLString(keyStrokeString, locAttrSet, buffer);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
insertHTMLString("No keybinding", noValueAttrSet, buffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
buffer.append("</TD></TR>");
|
||||||
|
}
|
||||||
|
|
||||||
|
buffer.append("</TABLE>");
|
||||||
|
buffer.append("</TD>");
|
||||||
|
buffer.append("</TR>");
|
||||||
}
|
}
|
||||||
|
|
||||||
private String createStringForMenuPath( String[] path ) {
|
private String createStringForMenuPath(String[] path) {
|
||||||
if ( path == null ) {
|
if (path == null) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
StringBuffer buffy = new StringBuffer();
|
StringBuffer buffy = new StringBuffer();
|
||||||
for ( int i = 0; i < path.length; i++ ) {
|
for (int i = 0; i < path.length; i++) {
|
||||||
buffy.append( path[i].replaceAll( "\\&", "" ) ); // strip off the mnemonic identifier '&'
|
buffy.append(path[i].replaceAll("\\&", "")); // strip off the mnemonic identifier '&'
|
||||||
if ( i != path.length-1 ) {
|
if (i != path.length - 1) {
|
||||||
buffy.append( "->" );
|
buffy.append("->");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return buffy.toString();
|
return buffy.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void createFieldAttributes() {
|
protected void createFieldAttributes() {
|
||||||
titleAttrSet = new SimpleAttributeSet();
|
titleAttrSet = new SimpleAttributeSet();
|
||||||
titleAttrSet.addAttribute(StyleConstants.FontFamily, "Tahoma");
|
titleAttrSet.addAttribute(StyleConstants.FontFamily, "Tahoma");
|
||||||
titleAttrSet.addAttribute(StyleConstants.FontSize, new Integer(11));
|
titleAttrSet.addAttribute(StyleConstants.FontSize, Integer.valueOf(11));
|
||||||
titleAttrSet.addAttribute(StyleConstants.Bold, Boolean.TRUE);
|
titleAttrSet.addAttribute(StyleConstants.Bold, Boolean.TRUE);
|
||||||
titleAttrSet.addAttribute(StyleConstants.Foreground, new Color(140, 0, 0));
|
titleAttrSet.addAttribute(StyleConstants.Foreground, new Color(140, 0, 0));
|
||||||
|
|
||||||
nameAttrSet = new SimpleAttributeSet();
|
nameAttrSet = new SimpleAttributeSet();
|
||||||
nameAttrSet.addAttribute(StyleConstants.FontFamily, "Tahoma");
|
nameAttrSet.addAttribute(StyleConstants.FontFamily, "Tahoma");
|
||||||
nameAttrSet.addAttribute(StyleConstants.FontSize, new Integer(11));
|
nameAttrSet.addAttribute(StyleConstants.FontSize, Integer.valueOf(11));
|
||||||
nameAttrSet.addAttribute(StyleConstants.Bold, Boolean.TRUE);
|
nameAttrSet.addAttribute(StyleConstants.Bold, Boolean.TRUE);
|
||||||
nameAttrSet.addAttribute(StyleConstants.Foreground, new Color(0, 204, 51));
|
nameAttrSet.addAttribute(StyleConstants.Foreground, new Color(0, 204, 51));
|
||||||
|
|
||||||
depNameAttrSet = new SimpleAttributeSet();
|
depNameAttrSet = new SimpleAttributeSet();
|
||||||
depNameAttrSet.addAttribute(StyleConstants.FontFamily, "Tahoma");
|
depNameAttrSet.addAttribute(StyleConstants.FontFamily, "Tahoma");
|
||||||
depNameAttrSet.addAttribute(StyleConstants.FontSize, new Integer(11));
|
depNameAttrSet.addAttribute(StyleConstants.FontSize, Integer.valueOf(11));
|
||||||
depNameAttrSet.addAttribute(StyleConstants.Bold, Boolean.TRUE);
|
depNameAttrSet.addAttribute(StyleConstants.Bold, Boolean.TRUE);
|
||||||
depNameAttrSet.addAttribute(StyleConstants.Foreground, Color.RED);
|
depNameAttrSet.addAttribute(StyleConstants.Foreground, Color.RED);
|
||||||
|
|
||||||
descrAttrSet = new SimpleAttributeSet();
|
descrAttrSet = new SimpleAttributeSet();
|
||||||
descrAttrSet.addAttribute(StyleConstants.FontFamily, "Tahoma");
|
descrAttrSet.addAttribute(StyleConstants.FontFamily, "Tahoma");
|
||||||
descrAttrSet.addAttribute(StyleConstants.FontSize, new Integer(11));
|
descrAttrSet.addAttribute(StyleConstants.FontSize, Integer.valueOf(11));
|
||||||
descrAttrSet.addAttribute(StyleConstants.Bold, Boolean.TRUE);
|
descrAttrSet.addAttribute(StyleConstants.Bold, Boolean.TRUE);
|
||||||
descrAttrSet.addAttribute(StyleConstants.Foreground, Color.BLUE);
|
descrAttrSet.addAttribute(StyleConstants.Foreground, Color.BLUE);
|
||||||
|
|
||||||
categoriesAttrSet = new SimpleAttributeSet();
|
categoriesAttrSet = new SimpleAttributeSet();
|
||||||
categoriesAttrSet.addAttribute(StyleConstants.FontFamily, "Tahoma");
|
categoriesAttrSet.addAttribute(StyleConstants.FontFamily, "Tahoma");
|
||||||
categoriesAttrSet.addAttribute(StyleConstants.FontSize, new Integer(11));
|
categoriesAttrSet.addAttribute(StyleConstants.FontSize, Integer.valueOf(11));
|
||||||
categoriesAttrSet.addAttribute(StyleConstants.Bold, Boolean.TRUE);
|
categoriesAttrSet.addAttribute(StyleConstants.Bold, Boolean.TRUE);
|
||||||
categoriesAttrSet.addAttribute(StyleConstants.Foreground, new Color(204, 0, 204));
|
categoriesAttrSet.addAttribute(StyleConstants.Foreground, new Color(204, 0, 204));
|
||||||
|
|
||||||
classAttrSet = new SimpleAttributeSet();
|
classAttrSet = new SimpleAttributeSet();
|
||||||
classAttrSet.addAttribute(StyleConstants.FontFamily, "monospaced");
|
classAttrSet.addAttribute(StyleConstants.FontFamily, "monospaced");
|
||||||
classAttrSet.addAttribute(StyleConstants.FontSize, new Integer(11));
|
classAttrSet.addAttribute(StyleConstants.FontSize, Integer.valueOf(11));
|
||||||
classAttrSet.addAttribute(StyleConstants.Bold, Boolean.TRUE);
|
classAttrSet.addAttribute(StyleConstants.Bold, Boolean.TRUE);
|
||||||
classAttrSet.addAttribute(StyleConstants.Foreground, Color.BLACK);
|
classAttrSet.addAttribute(StyleConstants.Foreground, Color.BLACK);
|
||||||
|
|
||||||
locAttrSet = new SimpleAttributeSet();
|
locAttrSet = new SimpleAttributeSet();
|
||||||
locAttrSet.addAttribute(StyleConstants.FontFamily, "Tahoma");
|
locAttrSet.addAttribute(StyleConstants.FontFamily, "Tahoma");
|
||||||
locAttrSet.addAttribute(StyleConstants.FontSize, new Integer(11));
|
locAttrSet.addAttribute(StyleConstants.FontSize, Integer.valueOf(11));
|
||||||
locAttrSet.addAttribute(StyleConstants.Bold, Boolean.TRUE);
|
locAttrSet.addAttribute(StyleConstants.Bold, Boolean.TRUE);
|
||||||
locAttrSet.addAttribute(StyleConstants.Foreground, Color.DARK_GRAY);
|
locAttrSet.addAttribute(StyleConstants.Foreground, Color.DARK_GRAY);
|
||||||
|
|
||||||
developerAttrSet = new SimpleAttributeSet();
|
developerAttrSet = new SimpleAttributeSet();
|
||||||
developerAttrSet.addAttribute(StyleConstants.FontFamily, "Tahoma");
|
developerAttrSet.addAttribute(StyleConstants.FontFamily, "Tahoma");
|
||||||
developerAttrSet.addAttribute(StyleConstants.FontSize, new Integer(11));
|
developerAttrSet.addAttribute(StyleConstants.FontSize, Integer.valueOf(11));
|
||||||
developerAttrSet.addAttribute(StyleConstants.Bold, Boolean.TRUE);
|
developerAttrSet.addAttribute(StyleConstants.Bold, Boolean.TRUE);
|
||||||
developerAttrSet.addAttribute(StyleConstants.Foreground, new Color(230, 15, 85));
|
developerAttrSet.addAttribute(StyleConstants.Foreground, new Color(230, 15, 85));
|
||||||
|
|
||||||
dependencyAttrSet = new SimpleAttributeSet();
|
dependencyAttrSet = new SimpleAttributeSet();
|
||||||
dependencyAttrSet.addAttribute(StyleConstants.FontFamily, "monospaced");
|
dependencyAttrSet.addAttribute(StyleConstants.FontFamily, "monospaced");
|
||||||
dependencyAttrSet.addAttribute(StyleConstants.FontSize, new Integer(11));
|
dependencyAttrSet.addAttribute(StyleConstants.FontSize, Integer.valueOf(11));
|
||||||
dependencyAttrSet.addAttribute(StyleConstants.Bold, Boolean.TRUE);
|
dependencyAttrSet.addAttribute(StyleConstants.Bold, Boolean.TRUE);
|
||||||
dependencyAttrSet.addAttribute(StyleConstants.Foreground, new Color(23, 100, 30));
|
dependencyAttrSet.addAttribute(StyleConstants.Foreground, new Color(23, 100, 30));
|
||||||
|
|
||||||
noValueAttrSet = new SimpleAttributeSet();
|
noValueAttrSet = new SimpleAttributeSet();
|
||||||
noValueAttrSet.addAttribute(StyleConstants.FontFamily, "Tahoma");
|
noValueAttrSet.addAttribute(StyleConstants.FontFamily, "Tahoma");
|
||||||
noValueAttrSet.addAttribute(StyleConstants.FontSize, new Integer(11));
|
noValueAttrSet.addAttribute(StyleConstants.FontSize, Integer.valueOf(11));
|
||||||
noValueAttrSet.addAttribute(StyleConstants.Italic, Boolean.TRUE);
|
noValueAttrSet.addAttribute(StyleConstants.Italic, Boolean.TRUE);
|
||||||
noValueAttrSet.addAttribute(StyleConstants.Foreground, new Color(192, 192, 192));
|
noValueAttrSet.addAttribute(StyleConstants.Foreground, new Color(192, 192, 192));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -21,26 +21,33 @@ import java.util.*;
|
||||||
|
|
||||||
import javax.swing.KeyStroke;
|
import javax.swing.KeyStroke;
|
||||||
|
|
||||||
import docking.ComponentProvider;
|
import docking.*;
|
||||||
import docking.DockingWindowManager;
|
|
||||||
import docking.action.*;
|
import docking.action.*;
|
||||||
|
import docking.tool.util.DockingToolConstants;
|
||||||
import ghidra.framework.options.OptionType;
|
import ghidra.framework.options.OptionType;
|
||||||
import ghidra.framework.options.Options;
|
import ghidra.framework.options.Options;
|
||||||
import ghidra.framework.plugintool.PluginTool;
|
import ghidra.framework.plugintool.PluginTool;
|
||||||
import ghidra.framework.plugintool.util.ToolConstants;
|
|
||||||
import ghidra.util.exception.AssertException;
|
import ghidra.util.exception.AssertException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Helper class to manage plugin actions for the tool.
|
* Helper class to manage plugin actions for the tool.
|
||||||
*/
|
*/
|
||||||
public class ProjectActionManager implements PropertyChangeListener {
|
public class ProjectActionManager implements PropertyChangeListener {
|
||||||
|
|
||||||
private DockingWindowManager winMgr;
|
private DockingWindowManager winMgr;
|
||||||
|
private DockingWindowManagerActionUpdater winMgrActionUpdater;
|
||||||
|
|
||||||
|
// TODO
|
||||||
|
// TODO
|
||||||
|
// TODO does this class need the shared action concept (probably not)
|
||||||
|
// TODO
|
||||||
|
// TODO
|
||||||
private Map<String, List<DockingActionIf>> actionMap;
|
private Map<String, List<DockingActionIf>> actionMap;
|
||||||
private Options keyBindingOptions;
|
private Options keyBindingOptions;
|
||||||
private PluginTool tool;
|
private PluginTool tool;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Construct an ActionManager.
|
* Construct an ActionManager
|
||||||
* @param tool plugin tool using this ActionManager
|
* @param tool plugin tool using this ActionManager
|
||||||
* @param winMgr manager of the "Docking" arrangement
|
* @param winMgr manager of the "Docking" arrangement
|
||||||
* of a set of components and actions in the tool
|
* of a set of components and actions in the tool
|
||||||
|
@ -48,8 +55,9 @@ public class ProjectActionManager implements PropertyChangeListener {
|
||||||
public ProjectActionManager(PluginTool tool, DockingWindowManager winMgr) {
|
public ProjectActionManager(PluginTool tool, DockingWindowManager winMgr) {
|
||||||
this.tool = tool;
|
this.tool = tool;
|
||||||
this.winMgr = winMgr;
|
this.winMgr = winMgr;
|
||||||
|
this.winMgrActionUpdater = new DockingWindowManagerActionUpdater(winMgr);
|
||||||
actionMap = new HashMap<>();
|
actionMap = new HashMap<>();
|
||||||
keyBindingOptions = tool.getOptions(ToolConstants.KEY_BINDINGS);
|
keyBindingOptions = tool.getOptions(DockingToolConstants.KEY_BINDINGS);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void dispose() {
|
public void dispose() {
|
||||||
|
@ -97,7 +105,8 @@ public class ProjectActionManager implements PropertyChangeListener {
|
||||||
action.setUnvalidatedKeyBindingData(new KeyBindingData(newKs));
|
action.setUnvalidatedKeyBindingData(new KeyBindingData(newKs));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
winMgr.addToolAction(action);
|
|
||||||
|
winMgrActionUpdater.addToolAction(action);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -107,7 +116,7 @@ public class ProjectActionManager implements PropertyChangeListener {
|
||||||
public synchronized void removeToolAction(DockingActionIf action) {
|
public synchronized void removeToolAction(DockingActionIf action) {
|
||||||
action.removePropertyChangeListener(this);
|
action.removePropertyChangeListener(this);
|
||||||
removeActionFromMap(action);
|
removeActionFromMap(action);
|
||||||
winMgr.removeToolAction(action);
|
winMgrActionUpdater.removeToolAction(action);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -140,7 +149,7 @@ public class ProjectActionManager implements PropertyChangeListener {
|
||||||
action.setUnvalidatedKeyBindingData(new KeyBindingData(newKs));
|
action.setUnvalidatedKeyBindingData(new KeyBindingData(newKs));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
winMgr.addLocalAction(provider, action);
|
winMgrActionUpdater.addLocalAction(provider, action);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void checkForAlreadyAddedAction(ComponentProvider provider, DockingActionIf action) {
|
private void checkForAlreadyAddedAction(ComponentProvider provider, DockingActionIf action) {
|
||||||
|
@ -167,14 +176,15 @@ public class ProjectActionManager implements PropertyChangeListener {
|
||||||
winMgr.removeProviderAction(provider, action);
|
winMgr.removeProviderAction(provider, action);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO delete me
|
||||||
/**
|
/**
|
||||||
* Get all actions that have the action name which includes the action owner's name.
|
* Get all actions that have the action name which includes the action owner's name.
|
||||||
*
|
*
|
||||||
* @param fullName full name for the action, e.g., "My Action (My Plugin)"
|
* @param fullName full name for the action, e.g., "My Action (My Plugin)"
|
||||||
* @return list of actions; empty if no action exists with the given name
|
* @return list of actions; empty if no action exists with the given name
|
||||||
*/
|
*/
|
||||||
public List<DockingActionIf> getDockingActionsByFullActionName(String fullActionName) {
|
public List<DockingActionIf> getDockingActionsByFullActionName(String fullName) {
|
||||||
List<DockingActionIf> list = actionMap.get(fullActionName);
|
List<DockingActionIf> list = actionMap.get(fullName);
|
||||||
if (list == null) {
|
if (list == null) {
|
||||||
return new ArrayList<>();
|
return new ArrayList<>();
|
||||||
}
|
}
|
||||||
|
@ -233,7 +243,7 @@ public class ProjectActionManager implements PropertyChangeListener {
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
public synchronized void restoreKeyBindings() {
|
public synchronized void restoreKeyBindings() {
|
||||||
keyBindingOptions = tool.getOptions(ToolConstants.KEY_BINDINGS);
|
keyBindingOptions = tool.getOptions(DockingToolConstants.KEY_BINDINGS);
|
||||||
List<DockingActionIf> actions = getAllActions();
|
List<DockingActionIf> actions = getAllActions();
|
||||||
for (DockingActionIf action : actions) {
|
for (DockingActionIf action : actions) {
|
||||||
if (!action.isKeyBindingManaged()) {
|
if (!action.isKeyBindingManaged()) {
|
||||||
|
@ -275,7 +285,7 @@ public class ProjectActionManager implements PropertyChangeListener {
|
||||||
}
|
}
|
||||||
KeyBindingData keyBindingData = (KeyBindingData) evt.getNewValue();
|
KeyBindingData keyBindingData = (KeyBindingData) evt.getNewValue();
|
||||||
KeyStroke newKeyStroke = keyBindingData.getKeyBinding();
|
KeyStroke newKeyStroke = keyBindingData.getKeyBinding();
|
||||||
Options opt = tool.getOptions(ToolConstants.KEY_BINDINGS);
|
Options opt = tool.getOptions(DockingToolConstants.KEY_BINDINGS);
|
||||||
KeyStroke optKeyStroke = opt.getKeyStroke(action.getFullName(), null);
|
KeyStroke optKeyStroke = opt.getKeyStroke(action.getFullName(), null);
|
||||||
if (newKeyStroke == null) {
|
if (newKeyStroke == null) {
|
||||||
opt.removeOption(action.getFullName());
|
opt.removeOption(action.getFullName());
|
||||||
|
|
|
@ -18,12 +18,10 @@ package help.screenshot;
|
||||||
import java.awt.AWTException;
|
import java.awt.AWTException;
|
||||||
import java.awt.Robot;
|
import java.awt.Robot;
|
||||||
import java.awt.event.KeyEvent;
|
import java.awt.event.KeyEvent;
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
|
||||||
import docking.action.DockingActionIf;
|
import docking.action.DockingActionIf;
|
||||||
import ghidra.app.plugin.core.assembler.AssembleDockingAction;
|
|
||||||
import ghidra.app.plugin.core.assembler.AssemblerPlugin;
|
import ghidra.app.plugin.core.assembler.AssemblerPlugin;
|
||||||
import ghidra.app.plugin.core.codebrowser.CodeViewerProvider;
|
import ghidra.app.plugin.core.codebrowser.CodeViewerProvider;
|
||||||
import ghidra.framework.plugintool.util.PluginException;
|
import ghidra.framework.plugintool.util.PluginException;
|
||||||
|
@ -37,9 +35,7 @@ public class AssemblerPluginScreenShots extends GhidraScreenShotGenerator {
|
||||||
positionCursor(0x0040512e);
|
positionCursor(0x0040512e);
|
||||||
tool.addPlugin(AssemblerPlugin.class.getName());
|
tool.addPlugin(AssemblerPlugin.class.getName());
|
||||||
|
|
||||||
String fullActionName = "Assemble (AssemblerPlugin)";
|
DockingActionIf action = getAction(tool, "AssemblerPlugin", "Assemble");
|
||||||
List<DockingActionIf> actions = tool.getDockingActionsByFullActionName(fullActionName);
|
|
||||||
AssembleDockingAction action = (AssembleDockingAction) actions.get(0);
|
|
||||||
|
|
||||||
performAction(action, true);
|
performAction(action, true);
|
||||||
|
|
||||||
|
|
|
@ -156,10 +156,10 @@ public class DataTypeManagerPluginScreenShots extends GhidraScreenShotGenerator
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testPreviewWindow() {
|
public void testPreviewWindow() {
|
||||||
String fullActionName = "Show Preview Window (DataTypeManagerPlugin)";
|
|
||||||
List<DockingActionIf> action = tool.getDockingActionsByFullActionName(fullActionName);
|
DockingActionIf action = getAction(tool, "DataTypeManagerPlugin", "Show Preview Window");
|
||||||
performAction(action.get(0));
|
performAction(action);
|
||||||
// performAction("Show Preview Window", "DataTypeManagerPlugin", false);
|
|
||||||
DataTypesProvider provider = getProvider(DataTypesProvider.class);
|
DataTypesProvider provider = getProvider(DataTypesProvider.class);
|
||||||
GTree tree = (GTree) getInstanceField("archiveGTree", provider);
|
GTree tree = (GTree) getInstanceField("archiveGTree", provider);
|
||||||
GTreeRootNode rootNode = tree.getRootNode();
|
GTreeRootNode rootNode = tree.getRootNode();
|
||||||
|
|
|
@ -283,10 +283,9 @@ public class ToolScreenShots extends GhidraScreenShotGenerator {
|
||||||
DockingWindowManager windowManager = tool.getWindowManager();
|
DockingWindowManager windowManager = tool.getWindowManager();
|
||||||
DockingActionManager actionMgr =
|
DockingActionManager actionMgr =
|
||||||
(DockingActionManager) getInstanceField("actionManager", windowManager);
|
(DockingActionManager) getInstanceField("actionManager", windowManager);
|
||||||
String fullActionName = "Delete Function" + " (" + "FunctionPlugin" + ")";
|
|
||||||
List<DockingActionIf> actions = tool.getDockingActionsByFullActionName(fullActionName);
|
|
||||||
|
|
||||||
final KeyEntryDialog keyEntryDialog = new KeyEntryDialog(actions.get(0), actionMgr);
|
DockingActionIf action = getAction(tool, "FunctionPlugin", "Delete Function");
|
||||||
|
final KeyEntryDialog keyEntryDialog = new KeyEntryDialog(action, actionMgr);
|
||||||
|
|
||||||
runSwing(() -> tool.showDialog(keyEntryDialog), false);
|
runSwing(() -> tool.showDialog(keyEntryDialog), false);
|
||||||
captureDialog();
|
captureDialog();
|
||||||
|
|
|
@ -18,14 +18,12 @@
|
||||||
*/
|
*/
|
||||||
package ghidra.framework.main;
|
package ghidra.framework.main;
|
||||||
|
|
||||||
import static org.junit.Assert.assertEquals;
|
|
||||||
import static org.junit.Assert.fail;
|
import static org.junit.Assert.fail;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.net.InetAddress;
|
import java.net.InetAddress;
|
||||||
import java.net.UnknownHostException;
|
import java.net.UnknownHostException;
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import javax.swing.*;
|
import javax.swing.*;
|
||||||
|
|
||||||
|
@ -239,10 +237,10 @@ public class SharedProjectUtil {
|
||||||
}
|
}
|
||||||
|
|
||||||
private static DockingActionIf getAction(FrontEndTool frontEndTool, String actionName) {
|
private static DockingActionIf getAction(FrontEndTool frontEndTool, String actionName) {
|
||||||
List<DockingActionIf> actions =
|
|
||||||
frontEndTool.getDockingActionsByFullActionName(actionName + " (FrontEndPlugin)");
|
DockingActionIf action =
|
||||||
assertEquals(1, actions.size());
|
AbstractDockingTest.getAction(frontEndTool, "FrontEndPlugin", actionName);
|
||||||
return actions.get(0);
|
return action;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static class UtilProjectListener implements ProjectListener {
|
private static class UtilProjectListener implements ProjectListener {
|
||||||
|
|
|
@ -23,8 +23,6 @@ import java.util.*;
|
||||||
import javax.swing.*;
|
import javax.swing.*;
|
||||||
import javax.swing.tree.TreePath;
|
import javax.swing.tree.TreePath;
|
||||||
|
|
||||||
import org.junit.Assert;
|
|
||||||
|
|
||||||
import docking.*;
|
import docking.*;
|
||||||
import docking.action.DockingActionIf;
|
import docking.action.DockingActionIf;
|
||||||
import docking.test.AbstractDockingTest;
|
import docking.test.AbstractDockingTest;
|
||||||
|
@ -341,15 +339,10 @@ public class FrontEndTestEnv {
|
||||||
return new ArrayList<>(Arrays.asList(tools));
|
return new ArrayList<>(Arrays.asList(tools));
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<DockingActionIf> getFrontEndActions() {
|
|
||||||
return frontEndTool.getDockingActionsByOwnerName("FrontEndPlugin");
|
|
||||||
}
|
|
||||||
|
|
||||||
public DockingActionIf getAction(String actionName) {
|
public DockingActionIf getAction(String actionName) {
|
||||||
List<DockingActionIf> a =
|
DockingActionIf action =
|
||||||
frontEndTool.getDockingActionsByFullActionName(actionName + " (FrontEndPlugin)");
|
AbstractDockingTest.getAction(frontEndTool, "FrontEndPlugin", actionName);
|
||||||
Assert.assertEquals(1, a.size());
|
return action;
|
||||||
return a.get(0);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void performFrontEndAction(DockingActionIf action) {
|
public void performFrontEndAction(DockingActionIf action) {
|
||||||
|
|
Loading…
Reference in a new issue