diff --git a/Ghidra/Features/Base/ghidra_scripts/CreateHelpTemplateScript.java b/Ghidra/Features/Base/ghidra_scripts/CreateHelpTemplateScript.java index 83543933fb..906ceeee28 100644 --- a/Ghidra/Features/Base/ghidra_scripts/CreateHelpTemplateScript.java +++ b/Ghidra/Features/Base/ghidra_scripts/CreateHelpTemplateScript.java @@ -20,6 +20,7 @@ import java.io.*; import java.util.*; import docking.action.DockingActionIf; +import docking.actions.KeyBindingUtils; import ghidra.app.script.GhidraScript; import ghidra.framework.plugintool.Plugin; import ghidra.framework.plugintool.PluginTool; @@ -30,9 +31,9 @@ public class CreateHelpTemplateScript extends GhidraScript { @Override protected void run() throws Exception { PluginTool tool = state.getTool(); - Plugin[] plugins = getSortedPlugins(tool); + List plugins = getSortedPlugins(tool); 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) { printerr("no plugin selected, no help template created."); return; @@ -101,7 +102,8 @@ public class CreateHelpTemplateScript extends GhidraScript { } private List getActions(PluginTool tool, Plugin plugin) { - List actions = tool.getDockingActionsByOwnerName(plugin.getName()); + Set actions = KeyBindingUtils.getKeyBindingActions(tool, plugin.getName()); + List list = new ArrayList<>(actions); Comparator comparator = (action1, action2) -> { try { return action1.getName().compareTo(action2.getName()); @@ -110,14 +112,12 @@ public class CreateHelpTemplateScript extends GhidraScript { return 0; } }; - Collections.sort(actions, comparator); - return actions; + Collections.sort(list, comparator); + return list; } - private Plugin[] getSortedPlugins(PluginTool tool) { + private List getSortedPlugins(PluginTool tool) { List list = tool.getManagedPlugins(); - Plugin[] plugins = new Plugin[list.size()]; - list.toArray(plugins); Comparator comparator = (plugin1, plugin2) -> { try { return plugin1.getName().compareTo(plugin2.getName()); @@ -126,8 +126,9 @@ public class CreateHelpTemplateScript extends GhidraScript { return 0; } }; - Arrays.sort(plugins, comparator); - return plugins; + + Collections.sort(list, comparator); + return list; } } diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/compositeeditor/CompositeEditorPanel.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/compositeeditor/CompositeEditorPanel.java index ac36db02f2..381a661b98 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/compositeeditor/CompositeEditorPanel.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/compositeeditor/CompositeEditorPanel.java @@ -21,9 +21,7 @@ import java.awt.datatransfer.Transferable; import java.awt.dnd.*; import java.awt.event.*; import java.math.BigInteger; -import java.util.Arrays; -import java.util.EventObject; -import java.util.List; +import java.util.*; import javax.swing.*; import javax.swing.border.Border; @@ -33,10 +31,10 @@ import javax.swing.table.*; import javax.swing.text.JTextComponent; import docking.action.DockingActionIf; +import docking.actions.KeyBindingUtils; import docking.dnd.*; import docking.help.Help; import docking.help.HelpService; -import docking.util.KeyBindingUtils; import docking.widgets.DropDownSelectionTextField; import docking.widgets.OptionDialog; import docking.widgets.fieldpanel.support.FieldRange; @@ -1519,17 +1517,18 @@ public abstract class CompositeEditorPanel extends JPanel @Override public boolean isKeyConsumed(KeyStroke keyStroke) { if (isEditing()) { + // don't let actions through when editing our table return true; } - // don't let actions through when editing our table + // TODO this should no longer be needed return !hasLocalActionForKeyStroke(keyStroke); } private boolean hasLocalActionForKeyStroke(KeyStroke keyStroke) { Plugin plugin = provider.getPlugin(); PluginTool tool = plugin.getTool(); - List actions = tool.getDockingActionsByOwnerName(plugin.getName()); + Set actions = tool.getDockingActionsByOwnerName(plugin.getName()); for (DockingActionIf action : actions) { if (!(action instanceof CompositeEditorTableAction)) { continue; diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/editor/TextEditorComponentProvider.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/editor/TextEditorComponentProvider.java index d13d865347..c5d706fa3a 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/editor/TextEditorComponentProvider.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/editor/TextEditorComponentProvider.java @@ -32,8 +32,8 @@ import javax.swing.undo.UndoableEdit; import docking.ActionContext; import docking.ComponentProvider; import docking.action.*; +import docking.actions.KeyBindingUtils; import docking.options.editor.FontPropertyEditor; -import docking.util.KeyBindingUtils; import docking.widgets.OptionDialog; import docking.widgets.filechooser.GhidraFileChooser; import ghidra.framework.options.SaveState; diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/function/editor/FunctionSignatureTextField.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/function/editor/FunctionSignatureTextField.java index 48a11725e9..f2b0f271ac 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/function/editor/FunctionSignatureTextField.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/function/editor/FunctionSignatureTextField.java @@ -1,6 +1,5 @@ /* ### * IP: GHIDRA - * REVIEWED: YES * * Licensed under the Apache License, Version 2.0 (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.text.*; -import docking.util.KeyBindingUtils; +import docking.actions.KeyBindingUtils; class FunctionSignatureTextField extends JTextPane { private static final String ENTER_ACTION_NAME = "ENTER"; diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/progmgr/MultiTabPanel.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/progmgr/MultiTabPanel.java index 2cfdbbcde9..db848d0af6 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/progmgr/MultiTabPanel.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/progmgr/MultiTabPanel.java @@ -24,7 +24,7 @@ import java.util.Map.Entry; import javax.swing.*; import javax.swing.border.*; -import docking.util.KeyBindingUtils; +import docking.actions.KeyBindingUtils; import docking.widgets.label.GDLabel; import docking.widgets.label.GIconLabel; import generic.util.WindowUtilities; diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/programtree/DragNDropTree.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/programtree/DragNDropTree.java index 8f719016f8..f8e19a219f 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/programtree/DragNDropTree.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/programtree/DragNDropTree.java @@ -26,8 +26,8 @@ import javax.swing.*; import javax.swing.tree.*; import docking.DockingUtils; +import docking.actions.KeyBindingUtils; import docking.dnd.*; -import docking.util.KeyBindingUtils; import docking.widgets.table.AutoscrollAdapter; /** diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/programtree/ProgramDnDTree.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/programtree/ProgramDnDTree.java index f3576565a2..2da9e4d094 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/programtree/ProgramDnDTree.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/programtree/ProgramDnDTree.java @@ -30,8 +30,8 @@ import javax.swing.tree.*; import docking.DockingUtils; import docking.action.DockingAction; +import docking.actions.KeyBindingUtils; import docking.dnd.DropTgtAdapter; -import docking.util.KeyBindingUtils; import docking.widgets.JTreeMouseListenerDelegate; import ghidra.app.util.SelectionTransferData; import ghidra.app.util.SelectionTransferable; diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/references/InstructionPanel.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/references/InstructionPanel.java index a49a831d84..7b76ffc81f 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/references/InstructionPanel.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/references/InstructionPanel.java @@ -28,9 +28,9 @@ import javax.swing.event.ChangeEvent; import javax.swing.event.ChangeListener; import docking.action.DockingAction; +import docking.actions.KeyBindingUtils; import docking.dnd.DropTgtAdapter; import docking.dnd.Droppable; -import docking.util.KeyBindingUtils; import docking.widgets.label.GDLabel; import ghidra.app.util.*; import ghidra.app.util.viewer.field.BrowserCodeUnitFormat; diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/script/GhidraScriptActionManager.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/script/GhidraScriptActionManager.java index 62c0e87205..feaf7615f9 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/script/GhidraScriptActionManager.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/script/GhidraScriptActionManager.java @@ -43,7 +43,6 @@ import utilities.util.FileUtilities; class GhidraScriptActionManager { 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( KeyEvent.VK_R, DockingUtils.CONTROL_KEY_MODIFIER_MASK | InputEvent.SHIFT_DOWN_MASK); private static final String SCRIPT_ACTIONS_KEY = "Scripts_Actions_Key"; diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/script/GhidraScriptEditorComponentProvider.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/script/GhidraScriptEditorComponentProvider.java index 966f0e3b47..acc70b91eb 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/script/GhidraScriptEditorComponentProvider.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/script/GhidraScriptEditorComponentProvider.java @@ -29,8 +29,8 @@ import javax.swing.undo.UndoableEdit; import docking.*; import docking.action.*; +import docking.actions.KeyBindingUtils; import docking.options.editor.FontPropertyEditor; -import docking.util.KeyBindingUtils; import docking.widgets.OptionDialog; import generic.jar.ResourceFile; import ghidra.app.script.GhidraScriptUtil; diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/viewer/util/TitledPanel.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/viewer/util/TitledPanel.java index d99bccbf48..1b2e2b928d 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/viewer/util/TitledPanel.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/viewer/util/TitledPanel.java @@ -28,7 +28,7 @@ import docking.widgets.label.GDLabel; * components (usually icon buttons) */ public class TitledPanel extends JPanel { - private JLabel title; + private JLabel title; // GDLabel or GHtmlLabel private JPanel titlePanel; private JPanel iconPanel; private JComponent bottomComp; @@ -37,16 +37,27 @@ public class TitledPanel extends JPanel { /** * Creates a new TitlePanel * @param name the name of the panel - * @param panel the component to wrap. - * @param margin the size of the margin to use. + * @param panel the component to wrap + * @param margin the size of the margin to use */ 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()); titlePanel = new JPanel(new BorderLayout()); iconPanel = new JPanel(new FlowLayout(FlowLayout.CENTER, 4, 1)); iconPanel.setBorder(BorderFactory.createEmptyBorder(0, 0, 0, 0)); - title = new GDLabel(name); - title.setToolTipText(name); + title = titleLabel; JLabel filler = new GDLabel(); filler.setPreferredSize(new Dimension(margin, filler.getPreferredSize().height)); titlePanel.add(filler, BorderLayout.WEST); diff --git a/Ghidra/Features/Base/src/main/java/help/screenshot/AbstractScreenShotGenerator.java b/Ghidra/Features/Base/src/main/java/help/screenshot/AbstractScreenShotGenerator.java index 5ef6b41bd5..6cb4822128 100644 --- a/Ghidra/Features/Base/src/main/java/help/screenshot/AbstractScreenShotGenerator.java +++ b/Ghidra/Features/Base/src/main/java/help/screenshot/AbstractScreenShotGenerator.java @@ -212,9 +212,8 @@ public abstract class AbstractScreenShotGenerator extends AbstractGhidraHeadedIn public void performAction(String actionName, String owner, ComponentProvider contextProvider, boolean wait) { - String fullActionName = actionName + " (" + owner + ")"; - List action = tool.getDockingActionsByFullActionName(fullActionName); - performAction(action.get(0), contextProvider, wait); + DockingActionIf action = getAction(tool, owner, actionName); + performAction(action, contextProvider, wait); } public void showOptions(final String optionsCategoryName) { diff --git a/Ghidra/Features/Base/src/main/java/help/screenshot/GhidraScreenShotGenerator.java b/Ghidra/Features/Base/src/main/java/help/screenshot/GhidraScreenShotGenerator.java index 0c37a470a5..f384c050c2 100644 --- a/Ghidra/Features/Base/src/main/java/help/screenshot/GhidraScreenShotGenerator.java +++ b/Ghidra/Features/Base/src/main/java/help/screenshot/GhidraScreenShotGenerator.java @@ -359,12 +359,11 @@ public abstract class GhidraScreenShotGenerator extends AbstractScreenShotGenera } public void performFrontEndAction(String actionName, String owner, boolean wait) { - String fullActionName = actionName + " (" + owner + ")"; FrontEndTool frontEnd = getFrontEndTool(); - List action = frontEnd.getDockingActionsByFullActionName(fullActionName); + + DockingActionIf action = getAction(frontEnd, owner, actionName); ComponentProvider compProvider = (ComponentProvider) getInstanceField("compProvider", frontEnd); - performAction(action.get(0), compProvider, wait); + performAction(action, compProvider, wait); } - } diff --git a/Ghidra/Features/Base/src/test.slow/java/ghidra/app/plugin/core/algorithmtree/ModuleAlgorithmPluginTest.java b/Ghidra/Features/Base/src/test.slow/java/ghidra/app/plugin/core/algorithmtree/ModuleAlgorithmPluginTest.java index 7f70fda78e..cb9e2dab9b 100644 --- a/Ghidra/Features/Base/src/test.slow/java/ghidra/app/plugin/core/algorithmtree/ModuleAlgorithmPluginTest.java +++ b/Ghidra/Features/Base/src/test.slow/java/ghidra/app/plugin/core/algorithmtree/ModuleAlgorithmPluginTest.java @@ -18,7 +18,7 @@ package ghidra.app.plugin.core.algorithmtree; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertTrue; -import java.util.List; +import java.util.Set; import org.junit.*; @@ -33,6 +33,7 @@ import ghidra.program.model.listing.Program; import ghidra.program.model.listing.ProgramModule; import ghidra.program.util.GroupPath; import ghidra.test.*; +import util.CollectionUtils; /** * Test the module algorithm plugin gui elements. @@ -43,7 +44,7 @@ public class ModuleAlgorithmPluginTest extends AbstractGhidraHeadedIntegrationTe private PluginTool tool; private Program program; private ModuleAlgorithmPlugin plugin; - private List actions; + private Set actions; private ProgramTreeService service; private Object context; @@ -58,7 +59,7 @@ public class ModuleAlgorithmPluginTest extends AbstractGhidraHeadedIntegrationTe tool.addPlugin(ProgramTreePlugin.class.getName()); tool.addPlugin(ModuleAlgorithmPlugin.class.getName()); plugin = env.getPlugin(ModuleAlgorithmPlugin.class); - actions = tool.getDockingActionsByOwnerName(plugin.getName()); + actions = getActionsByOwner(tool, plugin.getName()); service = tool.getService(ProgramTreeService.class); } @@ -98,7 +99,7 @@ public class ModuleAlgorithmPluginTest extends AbstractGhidraHeadedIntegrationTe getContextObject(vps); - performAction(actions.get(0), new ActionContext(null, context), true); + performAction(CollectionUtils.any(actions), new ActionContext(null, context), true); waitForTasks(); program.flushEvents(); diff --git a/Ghidra/Features/Base/src/test.slow/java/ghidra/app/plugin/core/calltree/CallTreePluginTest.java b/Ghidra/Features/Base/src/test.slow/java/ghidra/app/plugin/core/calltree/CallTreePluginTest.java index ece63c3b39..a5e2a57ea3 100644 --- a/Ghidra/Features/Base/src/test.slow/java/ghidra/app/plugin/core/calltree/CallTreePluginTest.java +++ b/Ghidra/Features/Base/src/test.slow/java/ghidra/app/plugin/core/calltree/CallTreePluginTest.java @@ -1090,10 +1090,9 @@ public class CallTreePluginTest extends AbstractGhidraHeadedIntegrationTest { private DockingActionIf getAction(String actionName) { // make sure there is a provider from which to get actions getProvider(); - String fullActionName = actionName + " (CallTreePlugin)"; - List actions = tool.getDockingActionsByFullActionName(fullActionName); - Assert.assertTrue("Could not find action: " + fullActionName, actions.size() > 0); - return actions.get(0); + + DockingActionIf action = getAction(tool, "CallTreePlugin", actionName); + return action; } private void myWaitForTree(GTree gTree, CallTreeProvider treeProvider) { diff --git a/Ghidra/Features/Base/src/test.slow/java/ghidra/app/plugin/core/data/AbstractDataActionTest.java b/Ghidra/Features/Base/src/test.slow/java/ghidra/app/plugin/core/data/AbstractDataActionTest.java index a7784f42ac..53b97d2587 100644 --- a/Ghidra/Features/Base/src/test.slow/java/ghidra/app/plugin/core/data/AbstractDataActionTest.java +++ b/Ghidra/Features/Base/src/test.slow/java/ghidra/app/plugin/core/data/AbstractDataActionTest.java @@ -165,7 +165,7 @@ public abstract class AbstractDataActionTest extends AbstractGhidraHeadedIntegra builtInDataTypesManager.setFavorite(root.getDataType("word"), true); } - protected void checkActions(List actions, boolean enabled, String caseStr) { + protected void checkActions(Set actions, boolean enabled, String caseStr) { checkAction(actions, CREATE_STRUCTURE, enabled, caseStr); checkAction(actions, EDIT_DATA_TYPE, enabled, caseStr); checkAction(actions, CREATE_ARRAY, enabled, caseStr); @@ -1063,7 +1063,7 @@ public abstract class AbstractDataActionTest extends AbstractGhidraHeadedIntegra ProgramSelection sel = getCurrentSelection(); boolean useSelection = (sel != null && !sel.isEmpty()); - List actions = tool.getDockingActionsByOwnerName(plugin.getName()); + Set actions = getActionsByOwner(tool, plugin.getName()); for (DockingActionIf element : actions) { 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) { DataType dt = data.getDataType(); @@ -1184,10 +1159,10 @@ public abstract class AbstractDataActionTest extends AbstractGhidraHeadedIntegra } - protected void checkOnUndefined(List actions) { + protected void checkOnUndefined(Set actions) { if (actions == null) { - actions = tool.getDockingActionsByOwnerName(plugin.getName()); + actions = getActionsByOwner(tool, plugin.getName()); } Data data = getContextData(); @@ -1223,10 +1198,10 @@ public abstract class AbstractDataActionTest extends AbstractGhidraHeadedIntegra } - protected void checkOnDefined(List actions, Class expectedDataType) { + protected void checkOnDefined(Set actions, Class expectedDataType) { if (actions == null) { - actions = tool.getDockingActionsByOwnerName(plugin.getName()); + actions = getActionsByOwner(tool, plugin.getName()); } String dtName = expectedDataType.getName(); @@ -1287,10 +1262,10 @@ public abstract class AbstractDataActionTest extends AbstractGhidraHeadedIntegra checkAction(actions, DEFINE_POINTER, true, caseName); } - protected void checkOnArray(List actions, DataType interiorDt, int arraySize) { + protected void checkOnArray(Set actions, DataType interiorDt, int arraySize) { if (actions == null) { - actions = tool.getDockingActionsByOwnerName(plugin.getName()); + actions = getActionsByOwner(tool, plugin.getName()); } Data d = getContextData(); @@ -1356,10 +1331,10 @@ public abstract class AbstractDataActionTest extends AbstractGhidraHeadedIntegra * @param actions * @param structSize structure size or -1 to disable size check */ - protected void checkOnStructure(List actions, int structSize) { + protected void checkOnStructure(Set actions, int structSize) { if (actions == null) { - actions = tool.getDockingActionsByOwnerName(plugin.getName()); + actions = getActionsByOwner(tool, plugin.getName()); } Data d = getContextData(); @@ -1400,7 +1375,7 @@ public abstract class AbstractDataActionTest extends AbstractGhidraHeadedIntegra } protected DockingActionIf getAction(String name) { - List actions = tool.getDockingActionsByOwnerName(plugin.getName()); + Set actions = getActionsByOwner(tool, plugin.getName()); for (DockingActionIf element : actions) { String actionName = element.getName(); int pos = actionName.indexOf(" ("); @@ -1439,7 +1414,7 @@ public abstract class AbstractDataActionTest extends AbstractGhidraHeadedIntegra } - protected void checkAction(List actions, String name, boolean isEnabled, + protected void checkAction(Set actions, String name, boolean isEnabled, String caseName) { for (DockingActionIf element : actions) { String actionName = element.getName(); diff --git a/Ghidra/Features/Base/src/test.slow/java/ghidra/app/plugin/core/data/DataAction4Test.java b/Ghidra/Features/Base/src/test.slow/java/ghidra/app/plugin/core/data/DataAction4Test.java index db6b3712b9..2ea75aed19 100644 --- a/Ghidra/Features/Base/src/test.slow/java/ghidra/app/plugin/core/data/DataAction4Test.java +++ b/Ghidra/Features/Base/src/test.slow/java/ghidra/app/plugin/core/data/DataAction4Test.java @@ -17,7 +17,7 @@ package ghidra.app.plugin.core.data; import static org.junit.Assert.*; -import java.util.List; +import java.util.Set; import org.junit.Test; import org.junit.experimental.categories.Category; @@ -39,13 +39,13 @@ public class DataAction4Test extends AbstractDataActionTest { @Test public void testNotepadLocations() { - List actions; + Set actions; program.addConsumer(this); // allow program to survive close try { closeProgram(); - actions = tool.getDockingActionsByOwnerName(plugin.getName()); + actions = getActionsByOwner(tool, plugin.getName()); assertEquals(ACTION_COUNT, actions.size()); checkActions(actions, false, "Start"); @@ -60,7 +60,7 @@ public class DataAction4Test extends AbstractDataActionTest { closeProgram(); - actions = tool.getDockingActionsByOwnerName(plugin.getName()); + actions = getActionsByOwner(tool, plugin.getName()); assertEquals(ACTION_COUNT, actions.size()); checkActions(actions, false, "Start"); } @@ -73,13 +73,13 @@ public class DataAction4Test extends AbstractDataActionTest { doAction(DEFINE_BYTE, true); - List actions = tool.getDockingActionsByOwnerName(plugin.getName()); + Set actions = getActionsByOwner(tool, plugin.getName()); assertEquals(ACTION_COUNT, actions.size()); checkOnDefined(actions, ByteDataType.class); undo(program); - actions = tool.getDockingActionsByOwnerName(plugin.getName()); + actions = getActionsByOwner(tool, plugin.getName()); checkOnUndefined(actions); gotoLocation(0x010069f2); @@ -107,7 +107,7 @@ public class DataAction4Test extends AbstractDataActionTest { doAction(DEFINE_WORD, true); - List actions = tool.getDockingActionsByOwnerName(plugin.getName()); + Set actions = getActionsByOwner(tool, plugin.getName()); assertEquals(ACTION_COUNT, actions.size()); checkOnDefined(actions, WordDataType.class); @@ -138,7 +138,7 @@ public class DataAction4Test extends AbstractDataActionTest { doAction(DEFINE_DWORD, true); - List actions = tool.getDockingActionsByOwnerName(plugin.getName()); + Set actions = getActionsByOwner(tool, plugin.getName()); assertEquals(ACTION_COUNT, actions.size()); checkOnDefined(actions, DWordDataType.class); @@ -169,7 +169,7 @@ public class DataAction4Test extends AbstractDataActionTest { doAction(DEFINE_QWORD, true); - List actions = tool.getDockingActionsByOwnerName(plugin.getName()); + Set actions = getActionsByOwner(tool, plugin.getName()); assertEquals(ACTION_COUNT, actions.size()); checkOnDefined(actions, QWordDataType.class); @@ -200,7 +200,7 @@ public class DataAction4Test extends AbstractDataActionTest { doAction(DEFINE_FLOAT, true); - List actions = tool.getDockingActionsByOwnerName(plugin.getName()); + Set actions = getActionsByOwner(tool, plugin.getName()); assertEquals(ACTION_COUNT, actions.size()); checkOnDefined(actions, FloatDataType.class); @@ -231,7 +231,7 @@ public class DataAction4Test extends AbstractDataActionTest { doAction(DEFINE_DOUBLE, true); - List actions = tool.getDockingActionsByOwnerName(plugin.getName()); + Set actions = getActionsByOwner(tool, plugin.getName()); assertEquals(ACTION_COUNT, actions.size()); checkOnDefined(actions, DoubleDataType.class); @@ -264,7 +264,7 @@ public class DataAction4Test extends AbstractDataActionTest { doAction(CYCLE_CHAR_STRING_UNICODE, true); - List actions = tool.getDockingActionsByOwnerName(plugin.getName()); + Set actions = getActionsByOwner(tool, plugin.getName()); assertEquals(ACTION_COUNT, actions.size()); checkOnDefined(actions, CharDataType.class); @@ -283,15 +283,15 @@ public class DataAction4Test extends AbstractDataActionTest { checkOnDefined(actions, CharDataType.class); doAction(CYCLE_CHAR_STRING_UNICODE, true); - actions = tool.getDockingActionsByOwnerName(plugin.getName()); + actions = getActionsByOwner(tool, plugin.getName()); checkOnDefined(actions, StringDataType.class); doAction(CYCLE_CHAR_STRING_UNICODE, true); - actions = tool.getDockingActionsByOwnerName(plugin.getName()); + actions = getActionsByOwner(tool, plugin.getName()); checkOnDefined(actions, UnicodeDataType.class); doAction(CYCLE_CHAR_STRING_UNICODE, true); - actions = tool.getDockingActionsByOwnerName(plugin.getName()); + actions = getActionsByOwner(tool, plugin.getName()); checkOnDefined(actions, CharDataType.class); clearLocation(0x01006a00); @@ -326,7 +326,7 @@ public class DataAction4Test extends AbstractDataActionTest { doAction(CYCLE_BYTE_WORD_DWORD_QWORD, true); - List actions = tool.getDockingActionsByOwnerName(plugin.getName()); + Set actions = getActionsByOwner(tool, plugin.getName()); assertEquals(ACTION_COUNT, actions.size()); checkOnDefined(actions, ByteDataType.class); @@ -345,19 +345,19 @@ public class DataAction4Test extends AbstractDataActionTest { checkOnDefined(actions, ByteDataType.class); doAction(CYCLE_BYTE_WORD_DWORD_QWORD, true); - actions = tool.getDockingActionsByOwnerName(plugin.getName()); + actions = getActionsByOwner(tool, plugin.getName()); checkOnDefined(actions, WordDataType.class); doAction(CYCLE_BYTE_WORD_DWORD_QWORD, true); - actions = tool.getDockingActionsByOwnerName(plugin.getName()); + actions = getActionsByOwner(tool, plugin.getName()); checkOnDefined(actions, DWordDataType.class); doAction(CYCLE_BYTE_WORD_DWORD_QWORD, true); - actions = tool.getDockingActionsByOwnerName(plugin.getName()); + actions = getActionsByOwner(tool, plugin.getName()); checkOnDefined(actions, QWordDataType.class); doAction(CYCLE_BYTE_WORD_DWORD_QWORD, true); - actions = tool.getDockingActionsByOwnerName(plugin.getName()); + actions = getActionsByOwner(tool, plugin.getName()); checkOnDefined(actions, ByteDataType.class); clearLocation(0x01006a00); @@ -387,19 +387,19 @@ public class DataAction4Test extends AbstractDataActionTest { // Test cycle when it does not fit gotoLocation(0x010069f0); - actions = tool.getDockingActionsByOwnerName(plugin.getName()); + actions = getActionsByOwner(tool, plugin.getName()); checkOnUndefined(actions); doAction(CYCLE_BYTE_WORD_DWORD_QWORD, true); - actions = tool.getDockingActionsByOwnerName(plugin.getName()); + actions = getActionsByOwner(tool, plugin.getName()); checkOnDefined(actions, ByteDataType.class); doAction(CYCLE_BYTE_WORD_DWORD_QWORD, true); - actions = tool.getDockingActionsByOwnerName(plugin.getName()); + actions = getActionsByOwner(tool, plugin.getName()); checkOnDefined(actions, WordDataType.class); doAction(CYCLE_BYTE_WORD_DWORD_QWORD, true); - actions = tool.getDockingActionsByOwnerName(plugin.getName()); + actions = getActionsByOwner(tool, plugin.getName()); checkOnUndefined(actions); } @@ -414,7 +414,7 @@ public class DataAction4Test extends AbstractDataActionTest { doAction(CYCLE_FLOAT_DOUBLE, true); - List actions = tool.getDockingActionsByOwnerName(plugin.getName()); + Set actions = getActionsByOwner(tool, plugin.getName()); assertEquals(ACTION_COUNT, actions.size()); checkOnDefined(actions, FloatDataType.class); @@ -433,11 +433,11 @@ public class DataAction4Test extends AbstractDataActionTest { checkOnDefined(actions, FloatDataType.class); doAction(CYCLE_FLOAT_DOUBLE, true); - actions = tool.getDockingActionsByOwnerName(plugin.getName()); + actions = getActionsByOwner(tool, plugin.getName()); checkOnDefined(actions, DoubleDataType.class); doAction(CYCLE_FLOAT_DOUBLE, true); - actions = tool.getDockingActionsByOwnerName(plugin.getName()); + actions = getActionsByOwner(tool, plugin.getName()); checkOnDefined(actions, FloatDataType.class); clearLocation(0x01006a00); @@ -461,15 +461,15 @@ public class DataAction4Test extends AbstractDataActionTest { // Test cycle when it does not fit gotoLocation(0x010069ee); - actions = tool.getDockingActionsByOwnerName(plugin.getName()); + actions = getActionsByOwner(tool, plugin.getName()); checkOnUndefined(actions); doAction(CYCLE_FLOAT_DOUBLE, true); - actions = tool.getDockingActionsByOwnerName(plugin.getName()); + actions = getActionsByOwner(tool, plugin.getName()); checkOnDefined(actions, FloatDataType.class); doAction(CYCLE_FLOAT_DOUBLE, true); - actions = tool.getDockingActionsByOwnerName(plugin.getName()); + actions = getActionsByOwner(tool, plugin.getName()); checkOnUndefined(actions); } @@ -495,7 +495,7 @@ public class DataAction4Test extends AbstractDataActionTest { waitForPostedSwingRunnables(); - List actions = tool.getDockingActionsByOwnerName(plugin.getName()); + Set actions = getActionsByOwner(tool, plugin.getName()); checkOnArray(actions, null, 0x20); // Test action disablement on array element location @@ -524,7 +524,7 @@ public class DataAction4Test extends AbstractDataActionTest { waitForPostedSwingRunnables(); - actions = tool.getDockingActionsByOwnerName(plugin.getName()); + actions = getActionsByOwner(tool, plugin.getName()); checkOnArray(actions, new ByteDataType(), 0x10); } @@ -541,7 +541,7 @@ public class DataAction4Test extends AbstractDataActionTest { clearSelection();// Remove selection to allow array check to work - List actions = tool.getDockingActionsByOwnerName(plugin.getName()); + Set actions = getActionsByOwner(tool, plugin.getName()); checkOnArray(actions, null, 0x20); // Create Byte[0x10] array @@ -555,7 +555,7 @@ public class DataAction4Test extends AbstractDataActionTest { clearSelection();// Remove selection to allow array check to work - actions = tool.getDockingActionsByOwnerName(plugin.getName()); + actions = getActionsByOwner(tool, plugin.getName()); checkOnArray(actions, new ByteDataType(), 0x10); } @@ -565,10 +565,7 @@ public class DataAction4Test extends AbstractDataActionTest { gotoLocation(0x01006c00); - List actions = - tool.getDockingActionsByFullActionName(RECENTLY_USED + " (" + plugin.getName() + ")"); - assertEquals(1, actions.size()); - DockingActionIf recentlyUsedAction = actions.get(0); + DockingActionIf recentlyUsedAction = getAction(tool, plugin.getName(), RECENTLY_USED); String caseName = "On Structure at: " + getCurrentLocation(); checkAction(recentlyUsedAction, false, caseName); @@ -591,7 +588,7 @@ public class DataAction4Test extends AbstractDataActionTest { clearSelection(); - List actions = tool.getDockingActionsByOwnerName(plugin.getName()); + Set actions = getActionsByOwner(tool, plugin.getName()); checkOnStructure(actions, 0x20); gotoLocation(0x01006c00); @@ -708,14 +705,14 @@ public class DataAction4Test extends AbstractDataActionTest { doAction(DEFINE_BYTE, true); - List actions = tool.getDockingActionsByOwnerName(plugin.getName()); + Set actions = getActionsByOwner(tool, plugin.getName()); checkOnDefined(actions, ByteDataType.class); gotoLocation(0x01006a01, new int[] { 1 }); doAction(DEFINE_FLOAT, true); - actions = tool.getDockingActionsByOwnerName(plugin.getName()); + actions = getActionsByOwner(tool, plugin.getName()); checkOnDefined(actions, FloatDataType.class); Data pdata = getContextData().getParent(); @@ -757,7 +754,7 @@ public class DataAction4Test extends AbstractDataActionTest { waitForPostedSwingRunnables(); - List actions = tool.getDockingActionsByOwnerName(plugin.getName()); + Set actions = getActionsByOwner(tool, plugin.getName()); checkOnArray(actions, structDt, 5); // Expand structure @@ -772,14 +769,14 @@ public class DataAction4Test extends AbstractDataActionTest { doAction(DEFINE_BYTE, true); - actions = tool.getDockingActionsByOwnerName(plugin.getName()); + actions = getActionsByOwner(tool, plugin.getName()); checkOnDefined(actions, ByteDataType.class); gotoLocation(0x01006a01, new int[] { 0, 1 }); doAction(DEFINE_FLOAT, true); - actions = tool.getDockingActionsByOwnerName(plugin.getName()); + actions = getActionsByOwner(tool, plugin.getName()); checkOnDefined(actions, FloatDataType.class); Data pdata = getContextData().getParent(); diff --git a/Ghidra/Features/Base/src/test.slow/java/ghidra/app/plugin/core/datamgr/DataTypeManagerPluginTest.java b/Ghidra/Features/Base/src/test.slow/java/ghidra/app/plugin/core/datamgr/DataTypeManagerPluginTest.java index 6a146a50e6..a4f2965880 100644 --- a/Ghidra/Features/Base/src/test.slow/java/ghidra/app/plugin/core/datamgr/DataTypeManagerPluginTest.java +++ b/Ghidra/Features/Base/src/test.slow/java/ghidra/app/plugin/core/datamgr/DataTypeManagerPluginTest.java @@ -37,7 +37,7 @@ import org.junit.*; import docking.DockingUtils; import docking.action.DockingActionIf; import docking.action.ToggleDockingActionIf; -import docking.util.KeyBindingUtils; +import docking.actions.KeyBindingUtils; import docking.widgets.OptionDialog; import docking.widgets.combobox.GhidraComboBox; import docking.widgets.dialogs.InputWithChoicesDialog; diff --git a/Ghidra/Features/Base/src/test.slow/java/ghidra/app/plugin/core/equate/AbstractEquatePluginTest.java b/Ghidra/Features/Base/src/test.slow/java/ghidra/app/plugin/core/equate/AbstractEquatePluginTest.java index 9a93e48da1..4379ea6433 100644 --- a/Ghidra/Features/Base/src/test.slow/java/ghidra/app/plugin/core/equate/AbstractEquatePluginTest.java +++ b/Ghidra/Features/Base/src/test.slow/java/ghidra/app/plugin/core/equate/AbstractEquatePluginTest.java @@ -17,7 +17,7 @@ package ghidra.app.plugin.core.equate; import static org.junit.Assert.*; -import java.util.List; +import java.util.Set; import javax.swing.JTextField; @@ -115,11 +115,10 @@ public abstract class AbstractEquatePluginTest extends AbstractProgramBasedTest // for selection containing a function stack address builder.setBytes("0x01004bbd", "c2 08 00"); // return of previous function - builder.setBytes("0x01004bc0", - "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 " + - "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"); + builder.setBytes("0x01004bc0", "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 " + + "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"); builder.disassemble(new AddressSet(builder.getProgram(), builder.addr("0x01004bc0"), builder.addr("0x01004c1a")), true); builder.createFunction("0x01004bc0"); @@ -203,8 +202,6 @@ public abstract class AbstractEquatePluginTest extends AbstractProgramBasedTest env.dispose(); } - - //================================================================================================= // Private Methods //================================================================================================= @@ -218,8 +215,7 @@ public abstract class AbstractEquatePluginTest extends AbstractProgramBasedTest ComponentProvider provider = tool.getComponentProvider(PluginConstants.CODE_BROWSER); DockingActionIf action = getAction(equatePlugin, "Apply Enum"); performAction(action, provider, false); - ApplyEnumDialog d = - waitForDialogComponent(tool.getToolFrame(), ApplyEnumDialog.class, DEFAULT_WAIT_DELAY); + ApplyEnumDialog d = waitForDialogComponent(ApplyEnumDialog.class); return d; } @@ -231,7 +227,7 @@ public abstract class AbstractEquatePluginTest extends AbstractProgramBasedTest } protected void assertConvertActionsInPopup(boolean inPopup) { - List actions = tool.getDockingActionsByOwnerName("EquatePlugin"); + Set actions = getActionsByOwner(tool, "EquatePlugin"); for (DockingActionIf action : actions) { String actionName = action.getName(); if (actionName.startsWith("Convert")) { @@ -242,7 +238,7 @@ public abstract class AbstractEquatePluginTest extends AbstractProgramBasedTest } protected void assertNonFloatConvertActionsInPopup() { - List actions = tool.getDockingActionsByOwnerName("EquatePlugin"); + Set actions = getActionsByOwner(tool, "EquatePlugin"); for (DockingActionIf action : actions) { String actionName = action.getName(); if (actionName.startsWith("Convert")) { @@ -255,7 +251,7 @@ public abstract class AbstractEquatePluginTest extends AbstractProgramBasedTest } protected void assertConvertNonCharNonSignedActionsInPopup() { - List actions = tool.getDockingActionsByOwnerName("EquatePlugin"); + Set actions = getActionsByOwner(tool, "EquatePlugin"); for (DockingActionIf element : actions) { String name = element.getName(); if (name.startsWith("Convert") && @@ -266,7 +262,7 @@ public abstract class AbstractEquatePluginTest extends AbstractProgramBasedTest } protected void assertConvertNonSignedActionsInPopup() { - List actions = tool.getDockingActionsByOwnerName("EquatePlugin"); + Set actions = getActionsByOwner(tool, "EquatePlugin"); for (DockingActionIf action : actions) { String name = action.getName(); if (name.startsWith("Convert") && name.indexOf("Signed") < 0) { diff --git a/Ghidra/Features/Base/src/test.slow/java/ghidra/app/plugin/core/equate/EquatePlugin1Test.java b/Ghidra/Features/Base/src/test.slow/java/ghidra/app/plugin/core/equate/EquatePlugin1Test.java index 97721e9604..d727512cca 100644 --- a/Ghidra/Features/Base/src/test.slow/java/ghidra/app/plugin/core/equate/EquatePlugin1Test.java +++ b/Ghidra/Features/Base/src/test.slow/java/ghidra/app/plugin/core/equate/EquatePlugin1Test.java @@ -19,6 +19,7 @@ import static org.junit.Assert.*; import java.lang.reflect.InvocationTargetException; import java.util.List; +import java.util.Set; import javax.swing.*; import javax.swing.table.TableModel; @@ -841,7 +842,7 @@ public class EquatePlugin1Test extends AbstractEquatePluginTest { putCursorOnOperand(0x010064ae, 1); - List actions = tool.getDockingActionsByOwnerName("EquatePlugin"); + Set actions = getActionsByOwner(tool, "EquatePlugin"); int found = 0; for (DockingActionIf action : actions) { String name = action.getName(); @@ -892,7 +893,7 @@ public class EquatePlugin1Test extends AbstractEquatePluginTest { putCursorOnOperand(0x010064a3, 0); int found = 0; - List actions = tool.getDockingActionsByOwnerName("EquatePlugin"); + Set actions = getActionsByOwner(tool, "EquatePlugin"); for (DockingActionIf action : actions) { String name = action.getName(); if (!name.startsWith("Convert") || !action.isAddToPopup(getListingContext())) { @@ -944,7 +945,7 @@ public class EquatePlugin1Test extends AbstractEquatePluginTest { putCursorOnOperand(0x01003a94, 0); int found = 0; - List actions = tool.getDockingActionsByOwnerName("EquatePlugin"); + Set actions = getActionsByOwner(tool, "EquatePlugin"); for (DockingActionIf action : actions) { String name = action.getName(); if (!name.startsWith("Convert") || !action.isAddToPopup(getListingContext())) { diff --git a/Ghidra/Features/Base/src/test.slow/java/ghidra/app/plugin/core/fallthrough/FallThroughActionTest.java b/Ghidra/Features/Base/src/test.slow/java/ghidra/app/plugin/core/fallthrough/FallThroughActionTest.java index 29127c215f..dd861b4cfc 100644 --- a/Ghidra/Features/Base/src/test.slow/java/ghidra/app/plugin/core/fallthrough/FallThroughActionTest.java +++ b/Ghidra/Features/Base/src/test.slow/java/ghidra/app/plugin/core/fallthrough/FallThroughActionTest.java @@ -17,7 +17,7 @@ package ghidra.app.plugin.core.fallthrough; import static org.junit.Assert.assertEquals; -import java.util.List; +import java.util.Set; import org.junit.*; @@ -37,7 +37,8 @@ import ghidra.program.util.ProgramLocation; import ghidra.program.util.ProgramSelection; import ghidra.test.*; -public class FallThroughActionTest extends AbstractGhidraHeadedIntegrationTest implements LocationCallback { +public class FallThroughActionTest extends AbstractGhidraHeadedIntegrationTest + implements LocationCallback { private Program program; private TestEnv env; private PluginTool tool; @@ -70,7 +71,7 @@ public class FallThroughActionTest extends AbstractGhidraHeadedIntegrationTest i @Test public void testNotepadLocations() { - List actions = tool.getDockingActionsByOwnerName(plugin.getName()); + Set actions = getActionsByOwner(tool, plugin.getName()); checkAction(actions, AUTO_OVERRIDE, false, "Start"); checkAction(actions, CLEAR_FALLTHROUGH, false, "Start"); @@ -96,7 +97,7 @@ public class FallThroughActionTest extends AbstractGhidraHeadedIntegrationTest i new ProgramSelectionPluginEvent("Test", selection, program); tool.firePluginEvent(ev); - List actions = tool.getDockingActionsByOwnerName(plugin.getName()); + Set actions = getActionsByOwner(tool, plugin.getName()); checkAction(actions, AUTO_OVERRIDE, true, "selection"); checkAction(actions, CLEAR_FALLTHROUGH, true, "selection"); @@ -110,7 +111,7 @@ public class FallThroughActionTest extends AbstractGhidraHeadedIntegrationTest i @Override public void locationGenerated(ProgramLocation loc) { tool.firePluginEvent(new ProgramLocationPluginEvent("test", loc, program)); - List actions = tool.getDockingActionsByOwnerName(plugin.getName()); + Set actions = getActionsByOwner(tool, plugin.getName()); ListingActionContext actionContext = (ListingActionContext) cb.getProvider().getActionContext(null); @@ -126,7 +127,7 @@ public class FallThroughActionTest extends AbstractGhidraHeadedIntegrationTest i } - private void checkAction(List actions, String name, boolean isValidContext, + private void checkAction(Set actions, String name, boolean isValidContext, String caseName) { for (DockingActionIf action : actions) { String actionName = action.getName(); diff --git a/Ghidra/Features/Base/src/test.slow/java/ghidra/app/plugin/core/memory/MemoryMapPluginTest.java b/Ghidra/Features/Base/src/test.slow/java/ghidra/app/plugin/core/memory/MemoryMapPluginTest.java index cb867b88a4..e0b69ccf3f 100644 --- a/Ghidra/Features/Base/src/test.slow/java/ghidra/app/plugin/core/memory/MemoryMapPluginTest.java +++ b/Ghidra/Features/Base/src/test.slow/java/ghidra/app/plugin/core/memory/MemoryMapPluginTest.java @@ -19,7 +19,7 @@ import static org.junit.Assert.*; import java.awt.*; import java.awt.event.MouseEvent; -import java.util.List; +import java.util.Set; import javax.swing.JTable; import javax.swing.JTextField; @@ -96,7 +96,7 @@ public class MemoryMapPluginTest extends AbstractGhidraHeadedIntegrationTest { env.close(program); program = buildProgram("sdk"); env.open(program); - List actions = tool.getDockingActionsByOwnerName(plugin.getName()); + Set actions = getActionsByOwner(tool, plugin.getName()); for (DockingActionIf action : actions) { if (action.getName().equals("Add Block") || action.getName().equals("Set Image Base") || action.getName().equals("View Memory Map")) { @@ -114,7 +114,7 @@ public class MemoryMapPluginTest extends AbstractGhidraHeadedIntegrationTest { env.close(program); JTable table = provider.getTable(); assertEquals(0, table.getModel().getRowCount()); - List actions = tool.getDockingActionsByOwnerName(plugin.getName()); + Set actions = getActionsByOwner(tool, plugin.getName()); for (DockingActionIf action : actions) { if (!action.getName().equals("View Memory Map")) { assertTrue(!action.isEnabledForContext(provider.getActionContext(null))); diff --git a/Ghidra/Features/Base/src/test.slow/java/ghidra/app/plugin/core/memory/MemoryMapProvider1Test.java b/Ghidra/Features/Base/src/test.slow/java/ghidra/app/plugin/core/memory/MemoryMapProvider1Test.java index 1b69fdfea0..528773a745 100644 --- a/Ghidra/Features/Base/src/test.slow/java/ghidra/app/plugin/core/memory/MemoryMapProvider1Test.java +++ b/Ghidra/Features/Base/src/test.slow/java/ghidra/app/plugin/core/memory/MemoryMapProvider1Test.java @@ -19,7 +19,6 @@ import static org.junit.Assert.*; import java.awt.*; import java.util.*; -import java.util.List; import javax.swing.*; import javax.swing.table.JTableHeader; @@ -117,7 +116,7 @@ public class MemoryMapProvider1Test extends AbstractGhidraHeadedIntegrationTest // select first row // all actions except "merge" should be enabled table.addRowSelectionInterval(0, 0); - List actions = tool.getDockingActionsByOwnerName(plugin.getName()); + Set actions = getActionsByOwner(tool, plugin.getName()); for (DockingActionIf action : actions) { if (action.getName().equals("Merge Blocks")) { assertTrue(!action.isEnabled()); @@ -133,7 +132,7 @@ public class MemoryMapProvider1Test extends AbstractGhidraHeadedIntegrationTest table.addRowSelectionInterval(0, 1); assertEquals(2, table.getSelectedRowCount()); - List actions = tool.getDockingActionsByOwnerName(plugin.getName()); + Set actions = getActionsByOwner(tool, plugin.getName()); for (DockingActionIf action : actions) { String name = action.getName(); if (name.equals("Add Block") || name.equals("Merge Blocks") || diff --git a/Ghidra/Features/Base/src/test.slow/java/ghidra/app/plugin/core/module/ModuleSortPluginTest.java b/Ghidra/Features/Base/src/test.slow/java/ghidra/app/plugin/core/module/ModuleSortPluginTest.java index 8a96da08f4..e96f571807 100644 --- a/Ghidra/Features/Base/src/test.slow/java/ghidra/app/plugin/core/module/ModuleSortPluginTest.java +++ b/Ghidra/Features/Base/src/test.slow/java/ghidra/app/plugin/core/module/ModuleSortPluginTest.java @@ -18,8 +18,7 @@ package ghidra.app.plugin.core.module; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; -import java.util.Arrays; -import java.util.List; +import java.util.*; import org.junit.*; @@ -42,7 +41,7 @@ public class ModuleSortPluginTest extends AbstractGhidraHeadedIntegrationTest { private PluginTool tool; private Program program; private ModuleSortPlugin plugin; - private List actions; + private Set actions; private ProgramTreeService service; public ModuleSortPluginTest() { @@ -63,7 +62,7 @@ public class ModuleSortPluginTest extends AbstractGhidraHeadedIntegrationTest { break; } } - actions = tool.getDockingActionsByOwnerName(plugin.getName()); + actions = getActionsByOwner(tool, plugin.getName()); service = tool.getService(ProgramTreeService.class); ProgramBuilder builder = new ProgramBuilder("notepad", ProgramBuilder._TOY); diff --git a/Ghidra/Features/Base/src/test.slow/java/ghidra/app/plugin/core/navigation/GoToPluginTest.java b/Ghidra/Features/Base/src/test.slow/java/ghidra/app/plugin/core/navigation/GoToPluginTest.java index ff85005e95..1002e1a333 100644 --- a/Ghidra/Features/Base/src/test.slow/java/ghidra/app/plugin/core/navigation/GoToPluginTest.java +++ b/Ghidra/Features/Base/src/test.slow/java/ghidra/app/plugin/core/navigation/GoToPluginTest.java @@ -17,8 +17,7 @@ package ghidra.app.plugin.core.navigation; import static org.junit.Assert.*; -import java.util.ArrayList; -import java.util.List; +import java.util.*; import javax.swing.*; @@ -65,7 +64,7 @@ import ghidra.util.Msg; import ghidra.util.table.GhidraProgramTableModel; import ghidra.util.table.field.LabelTableColumn; import ghidra.util.task.TaskMonitor; -import ghidra.util.task.TaskMonitorAdapter; +import util.CollectionUtils; public class GoToPluginTest extends AbstractGhidraHeadedIntegrationTest { private TestEnv env; @@ -104,20 +103,20 @@ public class GoToPluginTest extends AbstractGhidraHeadedIntegrationTest { @Test public void testActionEnablement() throws Exception { - List actions = tool.getDockingActionsByOwnerName(plugin.getName()); + Set actions = getActionsByOwner(tool, plugin.getName()); 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(); - assertTrue(!actions.get(0).isEnabledForContext(actionContext)); + assertTrue(!CollectionUtils.any(actions).isEnabledForContext(actionContext)); loadProgram("x86"); actionContext = getActionContext(); - assertTrue(actions.get(0).isEnabledForContext(actionContext)); + assertTrue(CollectionUtils.any(actions).isEnabledForContext(actionContext)); final ProgramManager pm = tool.getService(ProgramManager.class); - SwingUtilities.invokeAndWait(() -> pm.closeProgram(program, true)); + runSwing(() -> pm.closeProgram(program, true)); actionContext = getActionContext(); - assertTrue(!actions.get(0).isEnabledForContext(actionContext)); + assertTrue(!CollectionUtils.any(actions).isEnabledForContext(actionContext)); } @Test @@ -476,7 +475,7 @@ public class GoToPluginTest extends AbstractGhidraHeadedIntegrationTest { performOkCallback(); assertEquals("No results for xyzabc*", dialog.getStatusText()); - SwingUtilities.invokeAndWait(() -> dialog.close()); + runSwing(() -> dialog.close()); } @Test @@ -561,7 +560,7 @@ public class GoToPluginTest extends AbstractGhidraHeadedIntegrationTest { program.endTransaction(transactionID, true); final JCheckBox cb = findComponent(dialog, JCheckBox.class); - SwingUtilities.invokeAndWait(() -> { + runSwing(() -> { cb.setSelected(false); dialog.setText("COm*"); @@ -831,7 +830,7 @@ public class GoToPluginTest extends AbstractGhidraHeadedIntegrationTest { Assert.assertNotNull(program); final ProgramManager pm = tool.getService(ProgramManager.class); - SwingUtilities.invokeAndWait(() -> pm.openProgram(program.getDomainFile())); + runSwing(() -> pm.openProgram(program.getDomainFile())); program.release(this); addrFactory = program.getAddressFactory(); } @@ -965,7 +964,7 @@ public class GoToPluginTest extends AbstractGhidraHeadedIntegrationTest { try { Memory memory = program.getMemory(); return memory.createInitializedBlock(name, addr(address), size, (byte) 0, - TaskMonitorAdapter.DUMMY_MONITOR, true); + TaskMonitor.DUMMY, true); } finally { program.endTransaction(transactionID, true); @@ -1023,7 +1022,7 @@ public class GoToPluginTest extends AbstractGhidraHeadedIntegrationTest { } private void setText(final String text) throws Exception { - SwingUtilities.invokeAndWait(() -> dialog.setText(text)); + runSwing(() -> dialog.setText(text)); } private void performOkCallback() throws Exception { @@ -1035,17 +1034,7 @@ public class GoToPluginTest extends AbstractGhidraHeadedIntegrationTest { } private void waitForOKCallback() { - int numWaits = 0; - 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); + waitForCondition(() -> runSwing(() -> okButton.isEnabled())); } private void assumeCurrentAddressSpace(boolean b) { diff --git a/Ghidra/Features/Base/src/test.slow/java/ghidra/app/plugin/core/script/AbstractGhidraScriptMgrPluginTest.java b/Ghidra/Features/Base/src/test.slow/java/ghidra/app/plugin/core/script/AbstractGhidraScriptMgrPluginTest.java index e53faacc07..cdaedf7e2c 100644 --- a/Ghidra/Features/Base/src/test.slow/java/ghidra/app/plugin/core/script/AbstractGhidraScriptMgrPluginTest.java +++ b/Ghidra/Features/Base/src/test.slow/java/ghidra/app/plugin/core/script/AbstractGhidraScriptMgrPluginTest.java @@ -20,8 +20,7 @@ import static org.junit.Assert.*; import java.awt.Window; import java.io.*; import java.lang.reflect.InvocationTargetException; -import java.util.List; -import java.util.Map; +import java.util.*; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicInteger; @@ -60,6 +59,7 @@ import ghidra.util.exception.CancelledException; import ghidra.util.table.GhidraTable; import ghidra.util.table.GhidraTableFilterPanel; import ghidra.util.task.*; +import util.CollectionUtils; import utilities.util.FileUtilities; public abstract class AbstractGhidraScriptMgrPluginTest @@ -272,10 +272,18 @@ public abstract class AbstractGhidraScriptMgrPluginTest assertTrue(message, fullText.contains(piece)); } - protected void assertRunLastActionEnabled(boolean enabled) { - final DockingActionIf runLastAction = getAction(plugin, "Rerun Last Script"); - assertNotNull(runLastAction); + private DockingActionIf getRunLastScriptAction() { + // note: this provider adds 2 versions of the same action--pick either + Set 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 ref = new AtomicReference<>(); runSwing(() -> ref.set(runLastAction.isEnabledForContext(new ActionContext()))); assertEquals("Run Last Action not enabled as expected", enabled, ref.get()); @@ -557,17 +565,15 @@ public abstract class AbstractGhidraScriptMgrPluginTest } protected void pressRunLastScriptButton() { - DockingActionIf action = - getAction(plugin, GhidraScriptActionManager.RERUN_LAST_SHARED_ACTION_NAME); - performAction(action, false); + DockingActionIf runLastAction = getRunLastScriptAction(); + performAction(runLastAction, false); waitForSwing(); } protected void performGlobalRunLastScriptAction() { - DockingActionIf action = - getAction(plugin, GhidraScriptActionManager.GLOBAL_RERUN_LAST_SHARED_ACTION_NAME); - performAction(action, false); - waitForSwing(); + // note: this action used to be different from the 'run last script'; currently they are + // the same + pressRunLastScriptButton(); } protected KeyBindingInputDialog pressKeyBindingAction() { @@ -1293,7 +1299,7 @@ public abstract class AbstractGhidraScriptMgrPluginTest protected void assertToolKeyBinding(KeyStroke ks) { String actionOwner = GhidraScriptMgrPlugin.class.getSimpleName(); PluginTool tool = env.getTool(); - List actions = tool.getDockingActionsByOwnerName(actionOwner); + Set actions = getActionsByOwner(tool, actionOwner); for (DockingActionIf action : actions) { KeyStroke keyBinding = action.getKeyBinding(); if (keyBinding == null) { diff --git a/Ghidra/Features/Base/src/test.slow/java/ghidra/app/plugin/core/searchtext/SearchTextPlugin1Test.java b/Ghidra/Features/Base/src/test.slow/java/ghidra/app/plugin/core/searchtext/SearchTextPlugin1Test.java index c3b8abb6e8..45bf465340 100644 --- a/Ghidra/Features/Base/src/test.slow/java/ghidra/app/plugin/core/searchtext/SearchTextPlugin1Test.java +++ b/Ghidra/Features/Base/src/test.slow/java/ghidra/app/plugin/core/searchtext/SearchTextPlugin1Test.java @@ -684,8 +684,8 @@ public class SearchTextPlugin1Test extends AbstractGhidraHeadedIntegrationTest { final GTable table = threadedTablePanel.getTable(); Random random = new Random(); 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); runSwing(() -> table.setRowSelectionInterval(randomRow, randomRow)); performAction(deleteRowAction, true); diff --git a/Ghidra/Features/Base/src/test.slow/java/ghidra/app/plugin/core/symtable/SymbolTablePluginTest.java b/Ghidra/Features/Base/src/test.slow/java/ghidra/app/plugin/core/symtable/SymbolTablePluginTest.java index aeaf9066ab..785139cd12 100644 --- a/Ghidra/Features/Base/src/test.slow/java/ghidra/app/plugin/core/symtable/SymbolTablePluginTest.java +++ b/Ghidra/Features/Base/src/test.slow/java/ghidra/app/plugin/core/symtable/SymbolTablePluginTest.java @@ -1306,11 +1306,8 @@ public class SymbolTablePluginTest extends AbstractGhidraHeadedIntegrationTest { private void setupSymbolTableFilterToShowParameters() throws Exception { // get the filter action - "Set Filter" - List actions = - tool.getDockingActionsByFullActionName("Set Filter (SymbolTablePlugin)"); - assertNotNull(actions); - assertTrue(actions.size() > 0); - DockingActionIf filterAction = actions.get(0); + + DockingActionIf filterAction = getAction(tool, "SymbolTablePlugin", "Set Filter"); // execute performAction(filterAction, false); diff --git a/Ghidra/Features/Base/src/test.slow/java/ghidra/framework/main/datatree/ActionManager1Test.java b/Ghidra/Features/Base/src/test.slow/java/ghidra/framework/main/datatree/ActionManager1Test.java index c51c53f157..b28418ace8 100644 --- a/Ghidra/Features/Base/src/test.slow/java/ghidra/framework/main/datatree/ActionManager1Test.java +++ b/Ghidra/Features/Base/src/test.slow/java/ghidra/framework/main/datatree/ActionManager1Test.java @@ -30,6 +30,7 @@ import org.junit.*; import docking.ActionContext; import docking.action.DockingActionIf; +import docking.test.AbstractDockingTest; import docking.widgets.OptionDialog; import docking.widgets.tree.GTreeNode; import docking.widgets.tree.GTreeRootNode; @@ -596,10 +597,9 @@ public class ActionManager1Test extends AbstractGhidraHeadedIntegrationTest { } private DockingActionIf getAction(String actionName) { - List a = - frontEndTool.getDockingActionsByFullActionName(actionName + " (FrontEndPlugin)"); - Assert.assertEquals(1, a.size()); - return a.get(0); + DockingActionIf action = + AbstractDockingTest.getAction(frontEndTool, "FrontEndPlugin", actionName); + return action; } private void expandTreePath(TreePath path) { diff --git a/Ghidra/Features/Base/src/test.slow/java/ghidra/framework/main/datatree/ActionManager2Test.java b/Ghidra/Features/Base/src/test.slow/java/ghidra/framework/main/datatree/ActionManager2Test.java index aadb59fa26..2a47bd67fe 100644 --- a/Ghidra/Features/Base/src/test.slow/java/ghidra/framework/main/datatree/ActionManager2Test.java +++ b/Ghidra/Features/Base/src/test.slow/java/ghidra/framework/main/datatree/ActionManager2Test.java @@ -30,6 +30,7 @@ import org.junit.*; import docking.ActionContext; import docking.action.DockingActionIf; import docking.action.ToggleDockingAction; +import docking.test.AbstractDockingTest; import docking.widgets.OptionDialog; import docking.widgets.tree.GTreeNode; import docking.widgets.tree.GTreeRootNode; @@ -60,10 +61,6 @@ public class ActionManager2Test extends AbstractGhidraHeadedIntegrationTest { private DomainFolder rootFolder; private GTreeRootNode rootNode; - public ActionManager2Test() { - super(); - } - @Before public void setUp() throws Exception { env = new TestEnv(); @@ -363,10 +360,9 @@ public class ActionManager2Test extends AbstractGhidraHeadedIntegrationTest { } private DockingActionIf getAction(String actionName) { - List a = - frontEndTool.getDockingActionsByFullActionName(actionName + " (FrontEndPlugin)"); - assertEquals(1, a.size()); - return a.get(0); + DockingActionIf action = + AbstractDockingTest.getAction(frontEndTool, "FrontEndPlugin", actionName); + return action; } private void setSelectionPath(final TreePath path) throws Exception { diff --git a/Ghidra/Features/Base/src/test.slow/java/ghidra/framework/plugintool/dialog/KeyBindingUtilsTest.java b/Ghidra/Features/Base/src/test.slow/java/ghidra/framework/plugintool/dialog/KeyBindingUtilsTest.java index 87d1bc4b5a..a8e580c61d 100644 --- a/Ghidra/Features/Base/src/test.slow/java/ghidra/framework/plugintool/dialog/KeyBindingUtilsTest.java +++ b/Ghidra/Features/Base/src/test.slow/java/ghidra/framework/plugintool/dialog/KeyBindingUtilsTest.java @@ -30,10 +30,10 @@ import javax.swing.tree.TreePath; import org.junit.*; import docking.action.DockingActionIf; +import docking.actions.KeyBindingUtils; import docking.options.editor.OptionsDialog; import docking.options.editor.OptionsPanel; import docking.tool.util.DockingToolConstants; -import docking.util.KeyBindingUtils; import docking.widgets.filechooser.GhidraFileChooser; import docking.widgets.tree.GTree; import generic.io.NullWriter; @@ -228,13 +228,13 @@ public class KeyBindingUtilsTest extends AbstractGhidraHeadedIntegrationTest { // import the original values file through the tool importOptionsWithGUI(saveFile, true); // get the updated values that have not been applied - Map optionsMap = (Map) getInstanceField("actionMap", panel); + Map keyStrokeMap = panel.getKeyStrokeMap(); debug("f"); // verify the data is the same as it was before the changes - boolean same = compareOptionsWithKeyStrokeMap(originalOptions, optionsMap); - assertTrue("The Options object contains different data than was " + "imported.", same); + boolean same = compareOptionsWithKeyStrokeMap(originalOptions, keyStrokeMap); + assertTrue("The Options object contains different data than was imported.", same); debug("g"); @@ -405,26 +405,26 @@ public class KeyBindingUtilsTest extends AbstractGhidraHeadedIntegrationTest { } private void setKeyBinding(String keyText, int keyCode) throws Exception { - List list = tool.getAllActions(); - DockingActionIf action = null; - for (int i = 0; i < list.size(); i++) { - action = list.get(i); + Set list = tool.getAllActions(); + DockingActionIf arbitraryAction = null; + for (DockingActionIf action : list) { if (action.isKeyBindingManaged() && action.getKeyBinding() == null) { + arbitraryAction = action; break; } } - if (action == null) { + if (arbitraryAction == null) { Assert.fail("Unable to find an action for which to set a key binding."); } - selectRowForAction(action); + selectRowForAction(arbitraryAction); triggerText(keyField, keyText); assertEquals(keyText.toUpperCase(), keyField.getText()); runSwing(() -> panel.apply()); - assertEquals(KeyStroke.getKeyStroke(keyCode, 0), action.getKeyBinding()); + assertEquals(KeyStroke.getKeyStroke(keyCode, 0), arbitraryAction.getKeyBinding()); } 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 // keystrokes (the map is obtained from the key bindings panel after an // import is done). - private boolean compareOptionsWithKeyStrokeMap(Options options, Map optionsMap) { + private boolean compareOptionsWithKeyStrokeMap(Options options, + Map panelKeyStrokeMap) { List propertyNames = options.getOptionNames(); for (String element : propertyNames) { - boolean match = optionsMap.containsKey(element); + boolean match = panelKeyStrokeMap.containsKey(element); - Object value = invokeInstanceMethod("getKeyStroke", options, - new Class[] { String.class, KeyStroke.class }, new Object[] { element, null }); - Object value2 = optionsMap.get(element); + KeyStroke optionsKs = options.getKeyStroke(element, null); + KeyStroke panelKs = panelKeyStrokeMap.get(element); - // if the value is null, then it would not have been placed into the - // options map in the key bindings panel, so we only care about - // non-null values - if (value != null) { - match &= (value.equals(value2)); + // if the value is null, then it would not have been placed into the options map + // in the key bindings panel, so we only care about non-null values + if (optionsKs != null) { + match &= (optionsKs.equals(panelKs)); } else { match = true; diff --git a/Ghidra/Features/Base/src/test.slow/java/ghidra/framework/plugintool/dialog/KeyBindingsTest.java b/Ghidra/Features/Base/src/test.slow/java/ghidra/framework/plugintool/dialog/KeyBindingsTest.java index 3fb37ac4ea..480722bdb5 100644 --- a/Ghidra/Features/Base/src/test.slow/java/ghidra/framework/plugintool/dialog/KeyBindingsTest.java +++ b/Ghidra/Features/Base/src/test.slow/java/ghidra/framework/plugintool/dialog/KeyBindingsTest.java @@ -20,7 +20,7 @@ import static org.junit.Assert.*; import java.awt.Rectangle; import java.awt.event.InputEvent; import java.awt.event.KeyEvent; -import java.util.List; +import java.util.Set; import javax.swing.*; import javax.swing.table.*; @@ -29,10 +29,10 @@ import org.junit.*; import docking.KeyEntryTextField; import docking.action.DockingActionIf; +import docking.tool.util.DockingToolConstants; import docking.widgets.MultiLineLabel; import ghidra.app.plugin.core.codebrowser.CodeBrowserPlugin; import ghidra.framework.plugintool.PluginTool; -import ghidra.framework.plugintool.util.ToolConstants; import ghidra.test.AbstractGhidraHeadedIntegrationTest; import ghidra.test.TestEnv; import ghidra.util.Msg; @@ -102,9 +102,8 @@ public class KeyBindingsTest extends AbstractGhidraHeadedIntegrationTest { @Test public void testManagedKeyBindings() { - List list = tool.getAllActions(); - for (int i = 0; i < list.size(); i++) { - DockingActionIf action = list.get(i); + Set list = tool.getAllActions(); + for (DockingActionIf action : list) { if (action.isKeyBindingManaged()) { assertTrue(actionInTable(action)); } @@ -128,10 +127,8 @@ public class KeyBindingsTest extends AbstractGhidraHeadedIntegrationTest { @Test public void testActionNotSelected() throws Exception { table.clearSelection(); - List list = tool.getAllActions(); - DockingActionIf action = null; - for (int i = 0; i < list.size(); i++) { - action = list.get(i); + Set list = tool.getAllActions(); + for (DockingActionIf action : list) { KeyStroke ks = getKeyStroke(action); if (isKeyBindingManaged(action) && ks != KeyStroke.getKeyStroke(KeyEvent.VK_Z, 0)) { break; @@ -318,10 +315,8 @@ public class KeyBindingsTest extends AbstractGhidraHeadedIntegrationTest { } private DockingActionIf getKeyBindingPluginAction() { - List list = tool.getAllActions(); - DockingActionIf action = null; - for (int i = 0; i < list.size(); i++) { - action = list.get(i); + Set list = tool.getAllActions(); + for (DockingActionIf action : list) { KeyStroke ks = action.getKeyBinding(); if (action.isKeyBindingManaged() && ks != null && ks != KeyStroke.getKeyStroke(KeyEvent.VK_Z, 0)) { @@ -372,7 +367,7 @@ public class KeyBindingsTest extends AbstractGhidraHeadedIntegrationTest { private void setUpDialog() throws Exception { 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.getContentPane().add(panel); @@ -391,10 +386,8 @@ public class KeyBindingsTest extends AbstractGhidraHeadedIntegrationTest { } private void grabActionsWithoutKeybinding() { - List list = tool.getAllActions(); - DockingActionIf action = null; - for (int i = 0; i < list.size(); i++) { - action = list.get(i); + Set list = tool.getAllActions(); + for (DockingActionIf action : list) { if (!action.isKeyBindingManaged()) { continue; } diff --git a/Ghidra/Features/Base/src/test.slow/java/ghidra/framework/plugintool/dialog/ManageFrontEndToolTest.java b/Ghidra/Features/Base/src/test.slow/java/ghidra/framework/plugintool/dialog/ManageFrontEndToolTest.java index 72f606afe8..a402ec00e6 100644 --- a/Ghidra/Features/Base/src/test.slow/java/ghidra/framework/plugintool/dialog/ManageFrontEndToolTest.java +++ b/Ghidra/Features/Base/src/test.slow/java/ghidra/framework/plugintool/dialog/ManageFrontEndToolTest.java @@ -20,8 +20,6 @@ import static org.junit.Assert.*; import java.util.List; import java.util.Set; -import javax.swing.SwingUtilities; - import org.junit.*; import docking.action.DockingActionIf; @@ -74,7 +72,7 @@ public class ManageFrontEndToolTest extends AbstractGhidraHeadedIntegrationTest @After public void tearDown() throws Exception { - SwingUtilities.invokeAndWait(() -> { + runSwing(() -> { tool.setConfigChanged(false); provider.close(); }); @@ -99,33 +97,27 @@ public class ManageFrontEndToolTest extends AbstractGhidraHeadedIntegrationTest final Plugin p = getPlugin(tool, ArchivePlugin.class); assertNotNull(p); - SwingUtilities.invokeAndWait(() -> { + runSwing(() -> { provider.close(); tool.removePlugins(new Plugin[] { p }); }); showProvider(); - List actions = - tool.getDockingActionsByFullActionName("Save Project (" + plugin.getName() + ")"); - assertEquals(1, actions.size()); - performAction(actions.get(0), true); + DockingActionIf action = getAction(tool, plugin.getName(), "Save Project"); + performAction(action, true); - actions = - tool.getDockingActionsByFullActionName("Close Project (" + plugin.getName() + ")"); - assertEquals(1, actions.size()); - performAction(actions.get(0), true); + action = getAction(tool, plugin.getName(), "Close Project"); + performAction(action, true); assertTrue(!provider.isVisible()); } private void showProvider() throws Exception { - List 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(); - SwingUtilities.invokeAndWait(() -> tool.showConfig(false, false)); + runSwing(() -> tool.showConfig(false, false)); provider = tool.getManagePluginsDialog(); pluginManagerComponent = (PluginManagerComponent) getInstanceField("comp", provider); diff --git a/Ghidra/Features/Base/src/test.slow/java/ghidra/framework/plugintool/dialog/ManagePluginsTest.java b/Ghidra/Features/Base/src/test.slow/java/ghidra/framework/plugintool/dialog/ManagePluginsTest.java index bc498e4ac0..c4936a1f68 100644 --- a/Ghidra/Features/Base/src/test.slow/java/ghidra/framework/plugintool/dialog/ManagePluginsTest.java +++ b/Ghidra/Features/Base/src/test.slow/java/ghidra/framework/plugintool/dialog/ManagePluginsTest.java @@ -254,11 +254,9 @@ public class ManagePluginsTest extends AbstractGhidraHeadedIntegrationTest { } private void showProvider() { - List 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(); provider = tool.getManagePluginsDialog(); pluginManagerComponent = (PluginManagerComponent) getInstanceField("comp", provider); diff --git a/Ghidra/Features/Base/src/test.slow/java/ghidra/framework/project/tool/CloseToolTest.java b/Ghidra/Features/Base/src/test.slow/java/ghidra/framework/project/tool/CloseToolTest.java index 7fa2850852..f278ebe5cd 100644 --- a/Ghidra/Features/Base/src/test.slow/java/ghidra/framework/project/tool/CloseToolTest.java +++ b/Ghidra/Features/Base/src/test.slow/java/ghidra/framework/project/tool/CloseToolTest.java @@ -18,7 +18,6 @@ package ghidra.framework.project.tool; import static org.junit.Assert.*; import java.awt.Window; -import java.util.List; import org.junit.*; @@ -56,7 +55,7 @@ public class CloseToolTest extends AbstractGhidraHeadedIntegrationTest { public void tearDown() throws Exception { executeOnSwingWithoutBlocking(() -> env.dispose()); - closeAllWindowsAndFrames(); + closeAllWindows(); } @@ -138,7 +137,7 @@ public class CloseToolTest extends AbstractGhidraHeadedIntegrationTest { closeTool(tool); // 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); closeWindow(window); @@ -146,7 +145,7 @@ public class CloseToolTest extends AbstractGhidraHeadedIntegrationTest { closeProgram(tool, program); // 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); closeWindow(window); @@ -169,11 +168,9 @@ public class CloseToolTest extends AbstractGhidraHeadedIntegrationTest { } private void closeProgram(final PluginTool tool, final ProgramDB program) { - List 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(); } diff --git a/Ghidra/Features/Base/src/test.slow/java/ghidra/util/bean/opteditor/DateEditorTest.java b/Ghidra/Features/Base/src/test.slow/java/ghidra/util/bean/opteditor/DateEditorTest.java index db0b77e019..5a1f35b9c6 100644 --- a/Ghidra/Features/Base/src/test.slow/java/ghidra/util/bean/opteditor/DateEditorTest.java +++ b/Ghidra/Features/Base/src/test.slow/java/ghidra/util/bean/opteditor/DateEditorTest.java @@ -201,10 +201,9 @@ public class DateEditorTest extends AbstractGhidraHeadedIntegrationTest { } private void showProgramOptions() { - List list = tool.getAllActions(); - for (int i = 0; i < list.size(); i++) { - - DockingActionIf action = list.get(i); + // TODO change to getAction("Program Options") + Set list = tool.getAllActions(); + for (DockingActionIf action : list) { if (action.getName().equals("Program Options")) { performAction(action, plugin.getProvider(), false); break; diff --git a/Ghidra/Features/Base/src/test.slow/java/ghidra/util/bean/opteditor/OptionsDialogTest.java b/Ghidra/Features/Base/src/test.slow/java/ghidra/util/bean/opteditor/OptionsDialogTest.java index b030baa382..9bc6c20a0a 100644 --- a/Ghidra/Features/Base/src/test.slow/java/ghidra/util/bean/opteditor/OptionsDialogTest.java +++ b/Ghidra/Features/Base/src/test.slow/java/ghidra/util/bean/opteditor/OptionsDialogTest.java @@ -988,10 +988,9 @@ public class OptionsDialogTest extends AbstractGhidraHeadedIntegrationTest { } private void showOptionsDialog(PluginTool pluginTool) throws Exception { - List list = pluginTool.getAllActions(); - for (int i = 0; i < list.size(); i++) { - - DockingActionIf action = list.get(i); + // TODO change to getAction("Edit Options") + Set list = pluginTool.getAllActions(); + for (DockingActionIf action : list) { if (action.getName().equals("Edit Options")) { performAction(action, false); break; diff --git a/Ghidra/Features/Base/src/test/java/ghidra/test/DummyTool.java b/Ghidra/Features/Base/src/test/java/ghidra/test/DummyTool.java index e9ae76ed6c..20b92f2c59 100644 --- a/Ghidra/Features/Base/src/test/java/ghidra/test/DummyTool.java +++ b/Ghidra/Features/Base/src/test/java/ghidra/test/DummyTool.java @@ -19,7 +19,7 @@ import java.awt.Window; import java.beans.PropertyChangeListener; import java.beans.PropertyVetoException; import java.util.Collections; -import java.util.List; +import java.util.Set; import javax.swing.ImageIcon; import javax.swing.event.ChangeListener; @@ -438,18 +438,13 @@ public class DummyTool implements Tool { } @Override - public List getAllActions() { - return Collections.emptyList(); + public Set getAllActions() { + return Collections.emptySet(); } @Override - public List getDockingActionsByOwnerName(String owner) { - return Collections.emptyList(); - } - - @Override - public List getDockingActionsByFullActionName(String fullActionName) { - return Collections.emptyList(); + public Set getDockingActionsByOwnerName(String owner) { + return Collections.emptySet(); } @Override diff --git a/Ghidra/Features/ByteViewer/src/test.slow/java/ghidra/framework/plugintool/dialog/SaveToolConfigDialogTest.java b/Ghidra/Features/ByteViewer/src/test.slow/java/ghidra/framework/plugintool/dialog/SaveToolConfigDialogTest.java index a087a958ef..e76f632d8c 100644 --- a/Ghidra/Features/ByteViewer/src/test.slow/java/ghidra/framework/plugintool/dialog/SaveToolConfigDialogTest.java +++ b/Ghidra/Features/ByteViewer/src/test.slow/java/ghidra/framework/plugintool/dialog/SaveToolConfigDialogTest.java @@ -21,7 +21,6 @@ import java.awt.event.ActionListener; import java.io.File; import java.io.InputStream; import java.net.URL; -import java.util.List; import javax.swing.*; @@ -97,9 +96,9 @@ public class SaveToolConfigDialogTest extends AbstractGhidraHeadedIntegrationTes tc.remove("MyTestTool"); tc.remove("TestTool"); - waitForPostedSwingRunnables(); + waitForSwing(); tool.setConfigChanged(false); - SwingUtilities.invokeAndWait(() -> saveDialog.close()); + runSwing(() -> saveDialog.close()); env.dispose(); } @@ -125,7 +124,7 @@ public class SaveToolConfigDialogTest extends AbstractGhidraHeadedIntegrationTes pressButtonByText(saveDialog, "Save"); assertTrue(!tool.hasConfigChanged()); - waitForPostedSwingRunnables(); + waitForSwing(); assertTrue(!saveDialog.isVisible()); ToolChest tc = tool.getProject().getLocalToolChest(); ToolTemplate config = tc.getToolTemplate("MyTestTool"); @@ -142,7 +141,7 @@ public class SaveToolConfigDialogTest extends AbstractGhidraHeadedIntegrationTes while (saveDialog.isVisible()) { Thread.sleep(5); } - waitForPostedSwingRunnables(); + waitForSwing(); assertEquals("Name cannot have spaces.", msg); } @@ -156,7 +155,7 @@ public class SaveToolConfigDialogTest extends AbstractGhidraHeadedIntegrationTes pressButtonByText(saveDialog, "Save"); assertTrue(!tool.hasConfigChanged()); - waitForPostedSwingRunnables(); + waitForSwing(); assertTrue(!saveDialog.isVisible()); ToolChest tc = tool.getProject().getLocalToolChest(); ToolTemplate template = tc.getToolTemplate("MyTestTool"); @@ -180,7 +179,7 @@ public class SaveToolConfigDialogTest extends AbstractGhidraHeadedIntegrationTes while (saveDialog.isVisible()) { Thread.sleep(5); } - waitForPostedSwingRunnables(); + waitForSwing(); } @Test @@ -208,8 +207,7 @@ public class SaveToolConfigDialogTest extends AbstractGhidraHeadedIntegrationTes final JButton browseButton = (JButton) findComponentByName(saveDialog, "BrowseButton"); pressButton(browseButton, false); - final GhidraFileChooser chooser = - waitForDialogComponent(GhidraFileChooser.class); + final GhidraFileChooser chooser = waitForDialogComponent(GhidraFileChooser.class); assertNotNull(chooser); runSwing(() -> chooser.setSelectedFile(destFile)); @@ -240,7 +238,7 @@ public class SaveToolConfigDialogTest extends AbstractGhidraHeadedIntegrationTes while (tc.getToolTemplate("MyTestTool") == null) { Thread.sleep(10); } - waitForPostedSwingRunnables(); + waitForSwing(); setText(toolNameField, "MyTestTool", false); @@ -256,10 +254,9 @@ public class SaveToolConfigDialogTest extends AbstractGhidraHeadedIntegrationTes JButton saveButton = findButtonByText(saveDialog, "Save"); saveButton.getActionListeners()[0].actionPerformed(null); }); - waitForPostedSwingRunnables(); + waitForSwing(); - final OptionDialog d = - waitForDialogComponent(tool.getToolFrame(), OptionDialog.class, 2000); + final OptionDialog d = waitForDialogComponent(OptionDialog.class); assertNotNull(d); assertEquals("Overwrite Tool?", d.getTitle()); pressButtonByText(d.getComponent(), "Overwrite"); @@ -267,7 +264,7 @@ public class SaveToolConfigDialogTest extends AbstractGhidraHeadedIntegrationTes while (d.isVisible()) { Thread.sleep(10); } - waitForPostedSwingRunnables(); + waitForSwing(); assertTrue(!tool.hasConfigChanged()); } @@ -282,11 +279,11 @@ public class SaveToolConfigDialogTest extends AbstractGhidraHeadedIntegrationTes while (tc.getToolTemplate("MyTestTool") == null) { Thread.sleep(10); } - waitForPostedSwingRunnables(); + waitForSwing(); setText(toolNameField, "MyTestTool", false); - SwingUtilities.invokeAndWait(() -> { + runSwing(() -> { // force a change to the tool config try { tool.addPlugin(ByteViewerPlugin.class.getName()); @@ -301,10 +298,9 @@ public class SaveToolConfigDialogTest extends AbstractGhidraHeadedIntegrationTes JButton saveButton = findButtonByText(saveDialog, "Save"); saveButton.getActionListeners()[0].actionPerformed(null); }); - waitForPostedSwingRunnables(); + waitForSwing(); - final OptionDialog d = - waitForDialogComponent(OptionDialog.class); + final OptionDialog d = waitForDialogComponent(OptionDialog.class); assertNotNull(d); assertEquals("Overwrite Tool?", d.getTitle()); pressButtonByText(d.getComponent(), "Cancel"); @@ -312,17 +308,16 @@ public class SaveToolConfigDialogTest extends AbstractGhidraHeadedIntegrationTes while (d.isVisible()) { Thread.sleep(10); } - waitForPostedSwingRunnables(); + waitForSwing(); assertTrue(tool.hasConfigChanged()); } - ///////////////////////////////////////////////////////////////////// private void showDialogs() throws Exception { - List actions = - tool.getDockingActionsByFullActionName("Save Tool As (Tool)"); - performAction(actions.get(0), false); - waitForPostedSwingRunnables(); + + DockingActionIf action = getAction(tool, "Tool", "Save Tool As"); + performAction(action, false); + waitForSwing(); 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) throws Exception { - SwingUtilities.invokeAndWait(() -> { + runSwing(() -> { field.setText(text); if (doAction) { ActionListener[] listeners = field.getActionListeners(); @@ -344,6 +339,6 @@ public class SaveToolConfigDialogTest extends AbstractGhidraHeadedIntegrationTes } } }); - waitForPostedSwingRunnables(); + waitForSwing(); } } diff --git a/Ghidra/Features/Decompiler/src/main/java/ghidra/app/decompiler/component/DecompilerCodeComparisonPanel.java b/Ghidra/Features/Decompiler/src/main/java/ghidra/app/decompiler/component/DecompilerCodeComparisonPanel.java index 2dc61af896..6daad2cb23 100644 --- a/Ghidra/Features/Decompiler/src/main/java/ghidra/app/decompiler/component/DecompilerCodeComparisonPanel.java +++ b/Ghidra/Features/Decompiler/src/main/java/ghidra/app/decompiler/component/DecompilerCodeComparisonPanel.java @@ -27,6 +27,7 @@ import docking.action.DockingAction; import docking.widgets.fieldpanel.FieldPanel; import docking.widgets.fieldpanel.internal.FieldPanelCoordinator; import docking.widgets.fieldpanel.support.FieldLocation; +import docking.widgets.label.GDHtmlLabel; import ghidra.app.decompiler.DecompileOptions; import ghidra.app.util.viewer.listingpanel.ProgramLocationListener; import ghidra.app.util.viewer.util.CodeComparisonPanel; @@ -255,8 +256,13 @@ public abstract class DecompilerCodeComparisonPanel 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(); - performAction(actions.get(0), false); + performAction(action, false); Window window = waitForWindow("Reset Graph?"); pressButtonByText(window, "Yes"); @@ -917,20 +916,16 @@ public abstract class AbstractFunctionGraphTest extends AbstractGhidraHeadedInte private void toggleSatellite() { String name = "Display Satellite View"; - List 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; performAction(dockAction, true); } protected void undockSatellite() { String name = "Dock Satellite View"; - List 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()); performAction(dockAction, true); @@ -938,11 +933,9 @@ public abstract class AbstractFunctionGraphTest extends AbstractGhidraHeadedInte protected void redockSatellite() { String name = "Dock Satellite View"; - List 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()); performAction(dockAction, true); @@ -1210,10 +1203,8 @@ public abstract class AbstractFunctionGraphTest extends AbstractGhidraHeadedInte protected FGController cloneGraph() { - List actions = tool.getDockingActionsByFullActionName( - "Function Graph Clone (" + graphPlugin.getName() + ")"); - assertEquals(1, actions.size()); - DockingActionIf snapshotAction = actions.get(0); + DockingActionIf snapshotAction = + AbstractDockingTest.getAction(tool, graphPlugin.getName(), "Function Graph Clone"); performAction(snapshotAction, true); @SuppressWarnings("unchecked") @@ -1429,6 +1420,7 @@ public abstract class AbstractFunctionGraphTest extends AbstractGhidraHeadedInte assertSelected(ungroupedVertices); } + // @formatter:on 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 // it here. // - + // // 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 @@ -1457,7 +1449,7 @@ public abstract class AbstractFunctionGraphTest extends AbstractGhidraHeadedInte // // The fix is mentioned in the Desired Behavior section. // - + /* 0) Initial Graph @@ -1468,26 +1460,26 @@ public abstract class AbstractFunctionGraphTest extends AbstractGhidraHeadedInte 5 */ - + create12345Graph(); - + // // Our graph maps from number to address like so: // - + FGVertex v1 = vertex("100415a"); FGVertex v2 = vertex("1004178"); FGVertex v3 = vertex("1004192"); FGVertex v4 = vertex("1004196"); FGVertex v5 = vertex("100419c"); - + // verify initial graph verifyEdge(v1, v2); verifyEdge(v2, v3); verifyEdge(v3, v4); verifyEdge(v3, v5); verifyEdgeCount(4); - + /* 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 */ - + GroupedFunctionGraphVertex groupA = group("A", v1, v2); GroupedFunctionGraphVertex groupB = group("B", v3, v4); - + verifyEdge(groupA, groupB); verifyEdge(groupB, v5); verifyEdgeCount(2);// no other edges - + /* 2) Create a third group vertex (Z) that contains a non-grouped vertex *and* one of the other groups (B). @@ -1515,12 +1507,12 @@ public abstract class AbstractFunctionGraphTest extends AbstractGhidraHeadedInte ) */ - + GroupedFunctionGraphVertex groupZ = group("Z", groupB, v5); - + verifyEdge(groupA, groupZ); verifyEdgeCount(1); - + /* 3) Now, ungroup the 1 remaining originally grouped vertex (A). @@ -1530,13 +1522,13 @@ public abstract class AbstractFunctionGraphTest extends AbstractGhidraHeadedInte ) */ - + ungroup(groupA); - + verifyEdge(v1, v2); verifyEdge(v2, groupZ); verifyEdgeCount(2); - + /* 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 */ - + ungroup(groupZ); - + verifyEdge(v1, v2); verifyEdge(v2, groupB); verifyEdge(groupB, v5); verifyEdgeCount(3); - + /* 5) Finally, ungroup the last group and make sure the graph is restored @@ -1564,15 +1556,15 @@ public abstract class AbstractFunctionGraphTest extends AbstractGhidraHeadedInte 5 */ - + ungroup(groupB); - + verifyEdge(v1, v2); verifyEdge(v2, v3); verifyEdge(v3, v4); verifyEdge(v3, v5); verifyEdgeCount(4); - + } 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 // if at least two vertices cannot be found. // - + // // Pick a function and group some nodes. // FGData graphData = graphFunction("01002cf5"); FunctionGraph functionGraph = graphData.getFunctionGraph(); - + Set ungroupedVertices = selectVertices(functionGraph, "01002d11" /* LAB_01002d11 */, "01002cf5" /* ghidra */); - + group(ungroupedVertices); - + // 5 edges expected: // -01002cf5: 2 out // -01002cf5: 2 in, 1 out int expectedGroupedEdgeCount = 5; GroupedFunctionGraphVertex groupedVertex = validateNewGroupedVertexFromVertices( functionGraph, ungroupedVertices, expectedGroupedEdgeCount); - + AddressSetView addresses = groupedVertex.getAddresses(); Address minAddress = addresses.getMinAddress(); - + // // 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 @@ -1618,12 +1610,12 @@ public abstract class AbstractFunctionGraphTest extends AbstractGhidraHeadedInte // graphFunction("0100415a"); clearCache(); - + // // Add a label to trigger a code block change // createLabel("01002d18");// in the middle of the LAB_01002d11 code block - + // // 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 // take place, as at least two vertices cannot be found. // - + // // Pick a function and group some nodes. // FGData graphData = graphFunction("01002cf5"); FunctionGraph functionGraph = graphData.getFunctionGraph(); - + Set ungroupedVertices = selectVertices(functionGraph, "01002d11" /* LAB_01002d11 */, "01002cf5" /* ghidra */, "01002d1f" /* MyLocal */); - + group(ungroupedVertices); - + // 5 edges expected: // -01002cf5: 2 out // -01002d11: 2 in, (1 out that was removed) @@ -1665,11 +1657,11 @@ public abstract class AbstractFunctionGraphTest extends AbstractGhidraHeadedInte int expectedGroupedEdgeCount = 6; GroupedFunctionGraphVertex groupedVertex = validateNewGroupedVertexFromVertices( functionGraph, ungroupedVertices, expectedGroupedEdgeCount); - + AddressSetView addresses = groupedVertex.getAddresses(); Address minAddress = addresses.getMinAddress(); Address maxAddress = addresses.getMaxAddress(); - + // // 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 @@ -1679,12 +1671,12 @@ public abstract class AbstractFunctionGraphTest extends AbstractGhidraHeadedInte // graphFunction("0100415a"); clearCache(); - + // // Add a label to trigger a code block change // Address labelAddress = createLabel("01002d18");// in the middle of the LAB_01002d11 code block - + // // 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); assertTrue(expectedGroupVertex instanceof GroupedFunctionGraphVertex); assertEquals(maxAddress, expectedGroupVertex.getAddresses().getMaxAddress()); - + // ...we expect that the two original grouped vertices have again been grouped... FGVertex splitVertex = functionGraph.getVertexForAddress(getAddress("01002d11") /* LAB_01002d11 */); assertTrue("The split vertex should not have been regrouped", !(splitVertex instanceof GroupedFunctionGraphVertex)); - + FGVertex unchangedVertex = functionGraph.getVertexForAddress(getAddress("01002cf5") /* ghidra */); assertTrue("An unchanged vertex should have been regrouped: " + unchangedVertex, (unchangedVertex instanceof GroupedFunctionGraphVertex)); - + unchangedVertex = functionGraph.getVertexForAddress(getAddress("01002d1f") /* MyLocal */); assertTrue("An unchanged vertex should have been regrouped: " + unchangedVertex, (unchangedVertex instanceof GroupedFunctionGraphVertex)); - + // ...but the newly created code block has not FGVertex newlyCreatedVertex = functionGraph.getVertexForAddress(labelAddress); 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 // should still show the 'stale' indicator. // - + // // Pick a function and group some nodes. // FGData graphData = graphFunction("01002cf5"); FunctionGraph functionGraph = graphData.getFunctionGraph(); - + Set ungroupedVertices = selectVertices(functionGraph, "01002d11" /* LAB_01002d11 */, "01002cf5" /* ghidra */); - + group(ungroupedVertices); - + // 5 edges expected: // -01002cf5: 2 out // -01002cf5: 2 in, 1 out int expectedGroupedEdgeCount = 5; GroupedFunctionGraphVertex groupedVertex = validateNewGroupedVertexFromVertices( functionGraph, ungroupedVertices, expectedGroupedEdgeCount); - + // // Add a label to trigger a code block change // 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 // @@ -1792,7 +1784,7 @@ public abstract class AbstractFunctionGraphTest extends AbstractGhidraHeadedInte Msg.debug(this, "\t" + v); } } - + Assert.fail("Did not find group vertex at " + address + ". Instead found " + vertex); } return (GroupedFunctionGraphVertex) vertex; @@ -1819,7 +1811,7 @@ public abstract class AbstractFunctionGraphTest extends AbstractGhidraHeadedInte protected FGData graphFunction(String functionAddress) { // Find a good test function. goToAddress(functionAddress); - + FGData graphData = getFunctionGraphData(); assertNotNull(graphData); 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); performAction(action, graphProvider, false); waitForAnimation(); - + MultiLineInputDialog dialog = waitForDialogComponent(MultiLineInputDialog.class); if (groupVertexText != null) { final JTextArea inputTextArea = (JTextArea) getInstanceField("inputTextArea", dialog); runSwing(() -> inputTextArea.setText(groupVertexText)); } - + pressButtonByText(dialog.getComponent(), "OK"); - + if (groupVertexText != null) { String value = dialog.getValue(); assertEquals("Group vertex text was not set in the dialog", groupVertexText, value); } - + waitForAnimation(); - + FGController controller = getFunctionGraphController(); FGData data = controller.getFunctionGraphData(); FunctionGraph fg = data.getFunctionGraph(); @@ -1861,19 +1853,19 @@ public abstract class AbstractFunctionGraphTest extends AbstractGhidraHeadedInte } protected GroupedFunctionGraphVertex group(String groupName, FGVertex... vertices) { - + HashSet set = new HashSet<>(); for (FGVertex v : vertices) { set.add(v); } - + pickVertices(set); GroupedFunctionGraphVertex groupVertex = group(set, groupName); - + // for debugging Object componentPanel = getComponent(groupVertex); setInstanceField("title", componentPanel, groupName); - + return groupVertex; } @@ -1887,23 +1879,22 @@ public abstract class AbstractFunctionGraphTest extends AbstractGhidraHeadedInte runSwing(() -> { PickedState pickedState = getPickedState(); pickedState.clear(); - + for (FGVertex vertex : vertices) { pickedState.pick(vertex, true); } }); } - protected GroupedFunctionGraphVertex regroup(FGVertex vertex) { - + DockingActionIf regroupAction = getRegroupAction(vertex); if (regroupAction == null) { Assert.fail("Did not find the regroup action on vertex: " + vertex.getTitle()); } performAction(regroupAction, false); waitForBusyGraph(); - + FGController controller = getFunctionGraphController(); FGData data = controller.getFunctionGraphData(); FunctionGraph fg = data.getFunctionGraph(); @@ -1912,12 +1903,12 @@ public abstract class AbstractFunctionGraphTest extends AbstractGhidraHeadedInte private void removeEdge(FunctionGraph functionGraph, Address startAddress, Address destinationAddress) { - + Graph graph = functionGraph; - + FGVertex startVertex = functionGraph.getVertexForAddress(startAddress); FGVertex destinationVertex = functionGraph.getVertexForAddress(destinationAddress); - + FGEdge edge = graph.findEdge(startVertex, destinationVertex); runSwing(() -> graph.removeEdge(edge)); FGController controller = getFunctionGraphController(); @@ -1927,10 +1918,10 @@ public abstract class AbstractFunctionGraphTest extends AbstractGhidraHeadedInte protected void removeFromUncollapsedGroup(FGVertex... vertices) { FunctionGraph functionGraph = getFunctionGraph(); selectVertices(functionGraph, vertices); - + DockingActionIf action = getAction(graphPlugin, "Remove From Group"); assertNotNull(action); - + performAction(action, graphProvider, false); waitForBusyGraph(); } @@ -1944,35 +1935,32 @@ public abstract class AbstractFunctionGraphTest extends AbstractGhidraHeadedInte } protected FGData reset() { - List actions = - tool.getDockingActionsByFullActionName("Reset Graph (FunctionGraphPlugin)"); - assertEquals(1, actions.size()); - DockingActionIf action = actions.get(0); - + + DockingActionIf action = getAction(tool, graphPlugin.getName(), "Reset Graph"); performAction(action, graphProvider, false); - + OptionDialog dialog = waitForDialogComponent(OptionDialog.class); pressButtonByText(dialog, "Yes"); - + // wait for the threaded graph layout code return getFunctionGraphData(); } private Set selectVertices(FunctionGraph functionGraph, FGVertex... vertices) { - + Set set = new HashSet<>(); for (FGVertex vertex : vertices) { set.add(vertex); } - + pickVertices(set); - + waitForSwing(); return set; } protected Set selectVertices(FunctionGraph functionGraph, String... addressString) { - + Set vertices = new HashSet<>(); for (String string : addressString) { Address vertexAddress = getAddress(string); @@ -1980,26 +1968,26 @@ public abstract class AbstractFunctionGraphTest extends AbstractGhidraHeadedInte assertNotNull("No vertex for address: " + vertexAddress, vertex); vertices.add(vertex); } - + pickVertices(vertices); - + waitForSwing(); return vertices; } protected void setGroupText(GroupedFunctionGraphVertex group, final String newText) { - + final GroupedFunctionGraphVertex updatedGroup = update(group); runSwing(() -> updatedGroup.editLabel(null), false); - + Window window = waitForWindow("Enter Group Vertex Text"); assertNotNull(window); - + final JTextArea textArea = findComponent(window, JTextArea.class); runSwing(() -> textArea.setText(newText)); - + pressButtonByText(window, "OK"); - + waitForSwing(); } @@ -2018,9 +2006,9 @@ public abstract class AbstractFunctionGraphTest extends AbstractGhidraHeadedInte action.setCurrentActionState(state); } } - + }); - + } protected FGData triggerPersistence(String functionAddress) { @@ -2033,7 +2021,7 @@ public abstract class AbstractFunctionGraphTest extends AbstractGhidraHeadedInte // graphFunction("0100415a"); clearCache(); - + // // Graph the original function and make sure that the previously grouped nodes is again // 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, // 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 - + groupedVertex = getGroupVertex(getFunctionGraph(), groupedVertex.getVertexAddress()); - + ungroup(groupedVertex); } @@ -2063,45 +2051,42 @@ public abstract class AbstractFunctionGraphTest extends AbstractGhidraHeadedInte } protected void ungroupAll() { - List actions = - tool.getDockingActionsByFullActionName("Ungroup All Vertices (FunctionGraphPlugin)"); - assertEquals(1, actions.size()); - DockingActionIf action = actions.get(0); - + + DockingActionIf action = getAction(tool, "FunctionGraphPlugin", "Ungroup All Vertices"); performAction(action, graphProvider, false); - + OptionDialog dialog = waitForDialogComponent(OptionDialog.class); pressButtonByText(dialog, "Yes"); - + // wait for the threaded graph layout code waitForBusyGraph(); } - //================================================================================================== - // Private Methods - //================================================================================================== - - private GroupedFunctionGraphVertex update(GroupedFunctionGraphVertex group) { - // 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 - // test can get out-of-sync, so we update before we use it - return getGroupVertex(getFunctionGraph(), group.getVertexAddress()); - } +//================================================================================================== +// Private Methods +//================================================================================================== + + private GroupedFunctionGraphVertex update(GroupedFunctionGraphVertex group) { + // 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 + // test can get out-of-sync, so we update before we use it + return getGroupVertex(getFunctionGraph(), group.getVertexAddress()); + } protected GroupedFunctionGraphVertex validateNewGroupedVertexFromVertices( FunctionGraph functionGraph, Set vertices, int expectedGroupedEdgeCount) { - + FGVertex aVertex = vertices.iterator().next(); FGVertex currentVertex = functionGraph.getVertexForAddress(aVertex.getVertexAddress()); assertTrue(currentVertex instanceof GroupedFunctionGraphVertex); GroupedFunctionGraphVertex groupedVertex = (GroupedFunctionGraphVertex) currentVertex; - + // // make sure we have new edges // Graph graph = functionGraph; Collection groupedEdges = graph.getIncidentEdges(groupedVertex); - + assertEquals("Ungrouped edges not replaced with new edges for the grouped vertex", expectedGroupedEdgeCount, groupedEdges.size()); assertSelected(groupedVertex); @@ -2127,7 +2112,7 @@ public abstract class AbstractFunctionGraphTest extends AbstractGhidraHeadedInte FGData data = getFunctionGraphData(); FunctionGraph functionGraph = data.getFunctionGraph(); Graph graph = functionGraph; - + FGEdge edge = graph.findEdge(start, destination); 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); assertUndockedProviderShowing(provider); } - + protected void assertUndockedProviderShowing(ComponentProvider satellite) { assertNotNull("Undocked provider is not installed when it should be", satellite); 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()); int result = Double.compare(scale, 1.0); assertEquals("Graph not fully zoomed-in; scale: " + scale, 0, result); - + FGVertex v = getFocusedVertex(); Rectangle cursorBounds = v.getCursorBounds(); Window graphWindow = windowForComponent(getPrimaryGraphViewer()); @@ -2196,13 +2181,13 @@ public abstract class AbstractFunctionGraphTest extends AbstractGhidraHeadedInte DockingAction action = (DockingAction) TestUtils.getInstanceField("chooseColorAction", setColorAction); performAction(action, graphProvider, false); - + Window chooserWindow = waitForWindow("Please Select Background Color"); Object colorChooserDialog = chooserWindow;// the name is the real type JColorChooser chooser = (JColorChooser) TestUtils.getInstanceField("chooserPane", colorChooserDialog); chooser.setColor(testColor); - + JButton okButton = findButtonByText(chooserWindow, "OK"); runSwing(() -> okButton.doClick()); waitForSwing(); @@ -2216,32 +2201,32 @@ public abstract class AbstractFunctionGraphTest extends AbstractGhidraHeadedInte } protected void debugAction(DockingAction copyAction, ActionContext context) { - + Msg.debug(this, "Copy action not enabled at location " + codeBrowser.getCurrentLocation()); - + FGVertex focusedVertex = getFocusedVertex(); Msg.debug(this, "\tfocused vertex: " + focusedVertex); - + Msg.debug(this, "\tcontext: " + context); - + // Figure out which check in the action failed Object clipboardService = getInstanceField("clipboardService", copyAction); Msg.debug(this, "\tservice: " + clipboardService); - + Boolean result = (Boolean) invokeInstanceMethod("isValidContext", clipboardService, new Class[] { ActionContext.class }, new Object[] { context }); Msg.debug(this, "\tisValidContext()?: " + result); - + result = (Boolean) invokeInstanceMethod("canCopy", clipboardService); Msg.debug(this, "\tcanCopy: " + result); - + Boolean copyFromSelectionEnabled = (Boolean) getInstanceField("copyFromSelectionEnabled", clipboardService); Msg.debug(this, "\tcopyFromSelectionEnabled: " + copyFromSelectionEnabled); - + String stringContent = (String) getInstanceField("stringContent", clipboardService); Msg.debug(this, "\tstringContent: " + stringContent); - + Object location = getInstanceField("currentLocation", clipboardService); Msg.debug(this, "\tservice location: " + location); } @@ -2258,7 +2243,7 @@ public abstract class AbstractFunctionGraphTest extends AbstractGhidraHeadedInte ProgramLocation location = getLocationForAddressString(startAddressString); assertTrue(graphData.containsLocation(location)); FunctionGraph functionGraph = graphData.getFunctionGraph(); - + // locate vertex with cursor FGVertex focusedVertex = getFocusVertex(functionGraph); 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) { // this action is odd in that it is not installed in the tool, but is owned by each // vertex directly - + JComponent internalGraphComponent = vertex.getComponent(); return (SetVertexMostRecentColorAction) getInstanceField("setVertexMostRecentAction", internalGraphComponent); @@ -2284,7 +2269,7 @@ public abstract class AbstractFunctionGraphTest extends AbstractGhidraHeadedInte Address addr = getAddress(address); GoToService goToService = tool.getService(GoToService.class); goToService.goTo(addr); - + waitForBusyGraph(); } @@ -2299,11 +2284,9 @@ public abstract class AbstractFunctionGraphTest extends AbstractGhidraHeadedInte protected void navigateBack() { String name = "Previous in History Buffer"; - List actions = - tool.getDockingActionsByFullActionName(name + " (NextPrevAddressPlugin)"); - assertEquals("Could not find action: " + name, 1, actions.size()); - - performAction(actions.get(0), true); + + DockingActionIf action = getAction(tool, "NextPrevAddressPlugin", name); + performAction(action, true); waitForBusyGraph(); } @@ -2320,18 +2303,16 @@ public abstract class AbstractFunctionGraphTest extends AbstractGhidraHeadedInte } protected void setGraphWindowSize(final int width, final int height) { - + final Window graphWindow = windowForComponent(getPrimaryGraphViewer()); runSwing(() -> graphWindow.setSize(width, height)); } protected void toggleSatalliteVisible(boolean expectedVisible) { String name = "Display Satellite View"; - List actions = - tool.getDockingActionsByFullActionName(name + " (FunctionGraphPlugin)"); - assertEquals("Could not find action: " + name, 1, actions.size()); - - ToggleDockingAction displayAction = (ToggleDockingAction) actions.get(0); + + DockingActionIf action = getAction(tool, "FunctionGraphPlugin", name); + ToggleDockingAction displayAction = (ToggleDockingAction) action; setToggleActionSelected(displayAction, new ActionContext(), expectedVisible); // // // make sure the action is not already in the state we expect diff --git a/Ghidra/Features/FunctionGraph/src/test/java/ghidra/app/plugin/core/functiongraph/FunctionGraphPlugin2Test.java b/Ghidra/Features/FunctionGraph/src/test/java/ghidra/app/plugin/core/functiongraph/FunctionGraphPlugin2Test.java index c41cc8923e..18a8872892 100644 --- a/Ghidra/Features/FunctionGraph/src/test/java/ghidra/app/plugin/core/functiongraph/FunctionGraphPlugin2Test.java +++ b/Ghidra/Features/FunctionGraph/src/test/java/ghidra/app/plugin/core/functiongraph/FunctionGraphPlugin2Test.java @@ -177,10 +177,8 @@ public class FunctionGraphPlugin2Test extends AbstractFunctionGraphTest { GraphPerspectiveInfo primaryPerspective = primaryController.getGraphPerspective(location); - List actions = tool.getDockingActionsByFullActionName( - "Function Graph Clone (" + graphPlugin.getName() + ")"); - assertEquals(1, actions.size()); - DockingActionIf snapshotAction = actions.get(0); + DockingActionIf snapshotAction = + getAction(tool, graphPlugin.getName(), "Function Graph Clone"); performAction(snapshotAction, true); assertEquals(1, disconnectedProviders.size()); diff --git a/Ghidra/Features/ProgramDiff/src/test.slow/java/ghidra/app/plugin/core/diff/DiffTestAdapter.java b/Ghidra/Features/ProgramDiff/src/test.slow/java/ghidra/app/plugin/core/diff/DiffTestAdapter.java index 5beaf398c9..8c5e83da10 100644 --- a/Ghidra/Features/ProgramDiff/src/test.slow/java/ghidra/app/plugin/core/diff/DiffTestAdapter.java +++ b/Ghidra/Features/ProgramDiff/src/test.slow/java/ghidra/app/plugin/core/diff/DiffTestAdapter.java @@ -21,7 +21,7 @@ import java.awt.*; import java.awt.event.ActionListener; import java.io.IOException; import java.util.Date; -import java.util.List; +import java.util.Set; import javax.swing.*; @@ -589,7 +589,7 @@ public class DiffTestAdapter extends AbstractGhidraHeadedIntegrationTest { } public static DockingActionIf getToolAction(PluginTool tool, String name) { - List actions = tool.getDockingActionsByOwnerName("Tool"); + Set actions = getActionsByOwner(tool, "Tool"); for (DockingActionIf action : actions) { if (name.equals(action.getName())) { return action; diff --git a/Ghidra/Features/VersionTracking/src/main/java/ghidra/feature/vt/gui/plugin/VTPlugin.java b/Ghidra/Features/VersionTracking/src/main/java/ghidra/feature/vt/gui/plugin/VTPlugin.java index 3ca1573024..a40c0351e8 100644 --- a/Ghidra/Features/VersionTracking/src/main/java/ghidra/feature/vt/gui/plugin/VTPlugin.java +++ b/Ghidra/Features/VersionTracking/src/main/java/ghidra/feature/vt/gui/plugin/VTPlugin.java @@ -17,9 +17,11 @@ package ghidra.feature.vt.gui.plugin; import java.net.URL; import java.util.List; +import java.util.Set; import javax.swing.*; +import docking.action.DockingActionIf; import docking.help.Help; import docking.help.HelpService; import docking.wizard.WizardManager; @@ -121,14 +123,29 @@ public class VTPlugin extends Plugin { createActions(); registerServiceProvided(VTController.class, controller); 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 ImpliedMatchAssociationHook(controller); initializeOptions(); } + private DockingActionIf getToolAction(String actionName) { + Set 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() { Options options = tool.getOptions(GhidraOptions.CATEGORY_BROWSER_DISPLAY); options.registerOptionsEditor(new ListingDisplayOptionsEditor(this, options)); diff --git a/Ghidra/Features/VersionTracking/src/main/java/ghidra/feature/vt/gui/plugin/VTSubToolManager.java b/Ghidra/Features/VersionTracking/src/main/java/ghidra/feature/vt/gui/plugin/VTSubToolManager.java index 87b9fa5876..2657030f55 100644 --- a/Ghidra/Features/VersionTracking/src/main/java/ghidra/feature/vt/gui/plugin/VTSubToolManager.java +++ b/Ghidra/Features/VersionTracking/src/main/java/ghidra/feature/vt/gui/plugin/VTSubToolManager.java @@ -17,8 +17,7 @@ package ghidra.feature.vt.gui.plugin; import java.awt.Component; import java.io.*; -import java.util.ArrayList; -import java.util.List; +import java.util.*; import javax.swing.KeyStroke; @@ -27,6 +26,7 @@ import org.jdom.output.XMLOutputter; import docking.ActionContext; import docking.action.*; +import docking.tool.util.DockingToolConstants; import docking.widgets.OptionDialog; import docking.widgets.fieldpanel.FieldPanel; import docking.widgets.fieldpanel.support.FieldSelection; @@ -153,17 +153,17 @@ public class VTSubToolManager implements VTControllerListener, OptionsChangeList catch (PluginException e) { Msg.error(this, "Failed to create subordinate tool: " + toolName); } + newTool.setToolName(toolName); - newTool.removeAction(newTool.getDockingActionsByFullActionName("Save Tool (Tool)").get(0)); - newTool.removeAction( - newTool.getDockingActionsByFullActionName("Save Tool As (Tool)").get(0)); - // newTool.removeAction(newTool.getDockableActionsByFullActionName("Export - // Tool (Tool)").get(0)); + + DockingActionIf save = getToolAction(newTool, "Save Tool"); + newTool.removeAction(save); + createMarkupActions(newTool); newTool.setConfigChanged(false); - ToolOptions options = newTool.getOptions(ToolConstants.KEY_BINDINGS); + ToolOptions options = newTool.getOptions(DockingToolConstants.KEY_BINDINGS); options.addOptionsChangeListener(this); // custom VT actions @@ -172,6 +172,16 @@ public class VTSubToolManager implements VTControllerListener, OptionsChangeList return newTool; } + private DockingActionIf getToolAction(Tool tool, String actionName) { + Set 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 public void optionsChanged(ToolOptions options, String optionName, Object oldValue, Object newValue) { diff --git a/Ghidra/Framework/Docking/src/main/java/docking/AbstractDockingTool.java b/Ghidra/Framework/Docking/src/main/java/docking/AbstractDockingTool.java index 89bf204e42..9bef07cdae 100644 --- a/Ghidra/Framework/Docking/src/main/java/docking/AbstractDockingTool.java +++ b/Ghidra/Framework/Docking/src/main/java/docking/AbstractDockingTool.java @@ -17,7 +17,6 @@ package docking; import java.awt.*; import java.util.*; -import java.util.List; import javax.swing.JFrame; @@ -116,22 +115,16 @@ public abstract class AbstractDockingTool implements DockingTool { } @Override - public List getAllActions() { - return actionMgr.getAllActions(); - } - - @Override - public List getDockingActionsByOwnerName(String owner) { - List actions = actionMgr.getActions(owner); + public Set getAllActions() { + Set actions = actionMgr.getAllActions(); + DockingActionManager am = winMgr.getActionManager(); + actions.addAll(am.getAllActions()); return actions; } @Override - public List getDockingActionsByFullActionName(String fullActionName) { - Set set = new HashSet<>(); - set.addAll(actionMgr.getDockingActionsByFullActionName(fullActionName)); - set.addAll(winMgr.getActions(fullActionName)); - return new ArrayList<>(set); + public Set getDockingActionsByOwnerName(String owner) { + return actionMgr.getActions(owner); } @Override diff --git a/Ghidra/Framework/Docking/src/main/java/docking/DialogComponentProvider.java b/Ghidra/Framework/Docking/src/main/java/docking/DialogComponentProvider.java index 70f06fca41..b9f35aa436 100644 --- a/Ghidra/Framework/Docking/src/main/java/docking/DialogComponentProvider.java +++ b/Ghidra/Framework/Docking/src/main/java/docking/DialogComponentProvider.java @@ -28,6 +28,8 @@ import org.jdesktop.animation.timing.TimingTargetAdapter; import docking.action.ActionContextProvider; import docking.action.DockingActionIf; +import docking.actions.ActionAdapter; +import docking.actions.KeyBindingUtils; import docking.event.mouse.GMouseListenerAdapter; import docking.menu.DockingToolbarButton; import docking.util.*; diff --git a/Ghidra/Framework/Docking/src/main/java/docking/DockingActionManager.java b/Ghidra/Framework/Docking/src/main/java/docking/DockingActionManager.java index 2a9f17469a..3450320cb2 100644 --- a/Ghidra/Framework/Docking/src/main/java/docking/DockingActionManager.java +++ b/Ghidra/Framework/Docking/src/main/java/docking/DockingActionManager.java @@ -44,11 +44,6 @@ public class DockingActionManager { private PopupActionManager popupActionManager; 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) { menuGroupMap = new MenuGroupMap(); @@ -90,9 +85,10 @@ public class DockingActionManager { /** * Register a specific Help content location for a component. * 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 helpURL help content URL + * @param helpLocation the help location */ static void setHelpLocation(JComponent c, HelpLocation helpLocation) { DockingWindowManager.getHelpService().registerHelp(c, helpLocation); @@ -149,41 +145,18 @@ public class DockingActionManager { globalActions.remove(action); } - public List getAllDockingActionsByFullActionName(String fullActionName) { + public Set getAllActions() { // 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. - List actions = new ArrayList<>(); + Set actions = new HashSet<>(); SystemUtilities.runSwingNow(() -> { - actions.addAll(getGlobalDockingActionsByFullActionName(fullActionName)); - actions.addAll(getLocalDockingActionsByFullActionName(fullActionName)); + actions.addAll(globalActions); + actions.addAll(keyBindingsManager.getLocalActions()); }); return actions; } - private List getGlobalDockingActionsByFullActionName(String fullActionName) { - List matchingActions = new ArrayList<>(); - ArrayList existingAction = new ArrayList<>(globalActions); - for (DockingActionIf action : existingAction) { - if (fullActionName.equals(action.getFullName())) { - matchingActions.add(action); - } - } - return matchingActions; - } - - private List getLocalDockingActionsByFullActionName(String fullActionName) { - List matchingActions = new ArrayList<>(); - ArrayList existingAction = - new ArrayList<>(keyBindingsManager.getLocalActions()); - for (DockingActionIf action : existingAction) { - if (fullActionName.equals(action.getFullName())) { - matchingActions.add(action); - } - } - return matchingActions; - } - public Action getDockingKeyAction(KeyStroke keyStroke) { return keyBindingsManager.getDockingKeyAction(keyStroke); } diff --git a/Ghidra/Framework/Docking/src/main/java/docking/DockingTool.java b/Ghidra/Framework/Docking/src/main/java/docking/DockingTool.java index bc8d59b66a..23c25fbc2c 100644 --- a/Ghidra/Framework/Docking/src/main/java/docking/DockingTool.java +++ b/Ghidra/Framework/Docking/src/main/java/docking/DockingTool.java @@ -16,13 +16,17 @@ package docking; import java.awt.Window; -import java.util.List; +import java.util.Set; import javax.swing.ImageIcon; import docking.action.DockingActionIf; import ghidra.framework.options.ToolOptions; +/** + * Generic tool interface for managing {@link ComponentProvider}s and + * {@link DockingActionIf actions} + */ public interface DockingTool { /** @@ -125,25 +129,27 @@ public interface DockingTool { public void removeLocalAction(ComponentProvider componentProvider, DockingActionIf action); /** - * Return a list of all actions in the tool. - * @return list of all actions + * Return a set of all actions in the tool. + * + *

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 getAllActions(); + public Set getAllActions(); /** * Returns all actions for the given owner + * + *

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 * @return the actions */ - public List 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 getDockingActionsByFullActionName(String fullActionName); + public Set getDockingActionsByOwnerName(String owner); /** * Shows or hides the component provider in the tool diff --git a/Ghidra/Framework/Docking/src/main/java/docking/DockingWindowManager.java b/Ghidra/Framework/Docking/src/main/java/docking/DockingWindowManager.java index 8b820875a4..9db5066bfa 100644 --- a/Ghidra/Framework/Docking/src/main/java/docking/DockingWindowManager.java +++ b/Ghidra/Framework/Docking/src/main/java/docking/DockingWindowManager.java @@ -666,22 +666,6 @@ public class DockingWindowManager implements PropertyChangeListener, Placeholder 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. * @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 * 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) { + void addToolAction(DockingActionIf action) { actionManager.addToolAction(action); scheduleUpdate(); } @@ -710,15 +714,23 @@ public class DockingWindowManager implements PropertyChangeListener, Placeholder * Removes the given action from the global menu and toolbar. * @param action the action to be removed. */ - public void removeToolAction(DockingActionIf action) { + void removeToolAction(DockingActionIf action) { actionManager.removeToolAction(action); scheduleUpdate(); } - public Collection getActions(String fullActionName) { - return actionManager.getAllDockingActionsByFullActionName(fullActionName); + /** + * Returns all actions registered with this manager + * @return the actions + */ + public Set getAllActions() { + return actionManager.getAllActions(); } +//================================================================================================== +// End Package-level Methods +//================================================================================================== + /** * Hides or shows the component associated with the given provider. *


diff --git a/Ghidra/Framework/Docking/src/main/java/docking/DockingWindowManagerActionUpdater.java b/Ghidra/Framework/Docking/src/main/java/docking/DockingWindowManagerActionUpdater.java new file mode 100644 index 0000000000..917d4469b6 --- /dev/null +++ b/Ghidra/Framework/Docking/src/main/java/docking/DockingWindowManagerActionUpdater.java @@ -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 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); + } + +} diff --git a/Ghidra/Framework/Docking/src/main/java/docking/KeyBindingOverrideKeyEventDispatcher.java b/Ghidra/Framework/Docking/src/main/java/docking/KeyBindingOverrideKeyEventDispatcher.java index 59ff49f7f4..d1f6bffeb3 100644 --- a/Ghidra/Framework/Docking/src/main/java/docking/KeyBindingOverrideKeyEventDispatcher.java +++ b/Ghidra/Framework/Docking/src/main/java/docking/KeyBindingOverrideKeyEventDispatcher.java @@ -25,7 +25,7 @@ import java.awt.event.KeyListener; import javax.swing.*; import javax.swing.text.JTextComponent; -import docking.util.KeyBindingUtils; +import docking.actions.KeyBindingUtils; import ghidra.util.bean.GGlassPane; import ghidra.util.exception.AssertException; diff --git a/Ghidra/Framework/Docking/src/main/java/docking/action/KeyBindingAction.java b/Ghidra/Framework/Docking/src/main/java/docking/action/KeyBindingAction.java index a13e94eae6..66a1518c79 100644 --- a/Ghidra/Framework/Docking/src/main/java/docking/action/KeyBindingAction.java +++ b/Ghidra/Framework/Docking/src/main/java/docking/action/KeyBindingAction.java @@ -16,9 +16,10 @@ package docking.action; import java.awt.Component; -import java.util.List; +import java.util.Set; import docking.*; +import docking.actions.KeyBindingUtils; import ghidra.util.Msg; import ghidra.util.ReservedKeyBindings; @@ -51,20 +52,20 @@ public class KeyBindingAction extends DockingAction { if (!action.isKeyBindingManaged()) { Component parent = windowManager.getActiveComponent(); - Msg.showInfo(getClass(), parent, "Unable to Set Keybinding", "Action \"" + - getActionName(action) + "\" is not keybinding managed and thus a " + - "keybinding cannot be set."); + Msg.showInfo(getClass(), parent, "Unable to Set Keybinding", + "Action \"" + getActionName(action) + "\" is not keybinding managed and thus a " + + "keybinding cannot be set."); return; } 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 * 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 */ private DockingActionIf maybeGetToolLevelAction(DockingActionIf dockingAction) { @@ -72,15 +73,13 @@ public class KeyBindingAction extends DockingAction { return dockingAction; } - // It is not key binding managed, which means that it may have tool-level representation - // that allows for key binding editing (think DummyKeyBindingsOptionsAction). - - // Bad form (code duplication)--code from DockingAction.getFullName() - String actionToolName = dockingAction.getName() + " (Tool)"; - List actions = - dockingActionManager.getAllDockingActionsByFullActionName(actionToolName); - for (DockingActionIf action : actions) { - return action; + // It is not key binding managed, which means that it may be a shared key binding + String actionName = dockingAction.getName(); + Set allActions = dockingActionManager.getAllActions(); + DockingActionIf sharedAction = + KeyBindingUtils.getSharedKeyBindingAction(allActions, actionName); + if (sharedAction != null) { + return sharedAction; } return dockingAction; diff --git a/Ghidra/Framework/Docking/src/main/java/docking/action/KeyEntryDialog.java b/Ghidra/Framework/Docking/src/main/java/docking/action/KeyEntryDialog.java index 717b1a562a..535f6a99f2 100644 --- a/Ghidra/Framework/Docking/src/main/java/docking/action/KeyEntryDialog.java +++ b/Ghidra/Framework/Docking/src/main/java/docking/action/KeyEntryDialog.java @@ -23,6 +23,7 @@ import javax.swing.*; import javax.swing.text.*; import docking.*; +import docking.actions.KeyBindingUtils; import docking.widgets.label.GIconLabel; import ghidra.util.HelpLocation; import ghidra.util.ReservedKeyBindings; @@ -92,12 +93,9 @@ public class KeyEntryDialog extends DialogComponentProvider { labelPanel.add(pane); labelPanel.add(Box.createHorizontalStrut(5)); - keyEntryField = new KeyEntryTextField(20, new KeyEntryListener() { - @Override - public void processEntry(KeyStroke keyStroke) { - okButton.setEnabled(true); - updateCollisionPane(keyStroke); - } + keyEntryField = new KeyEntryTextField(20, keyStroke -> { + okButton.setEnabled(true); + updateCollisionPane(keyStroke); }); defaultPanel.add(labelPanel, BorderLayout.NORTH); @@ -146,8 +144,9 @@ public class KeyEntryDialog extends DialogComponentProvider { clearStatusText(); - List actions = - actionManager.getAllDockingActionsByFullActionName(action.getFullName()); + Set allActions = actionManager.getAllActions(); + Set actions = + KeyBindingUtils.getActions(allActions, action.getOwner(), action.getName()); for (DockingActionIf element : actions) { if (element.isKeyBindingManaged()) { element.setUnvalidatedKeyBindingData(new KeyBindingData(keyStroke)); @@ -160,7 +159,7 @@ public class KeyEntryDialog extends DialogComponentProvider { private void setUpAttributes() { textAttrSet = new SimpleAttributeSet(); 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); tabAttrSet = new SimpleAttributeSet(); @@ -207,7 +206,7 @@ public class KeyEntryDialog extends DialogComponentProvider { Map nameMap = new HashMap<>(list.size()); // the list may have multiple matches for a single owner, which we do not want (see - // DummyKeyBindingsOptionsAction) + // SharedStubKeyBindingAction) for (DockingActionIf dockableAction : list) { if (shouldAddAction(dockableAction)) { // this overwrites same named actions @@ -218,9 +217,6 @@ public class KeyEntryDialog extends DialogComponentProvider { return new ArrayList<>(nameMap.values()); } - /** - * Get the multiple key action for the given keystroke. - */ private MultipleKeyAction getMultipleKeyAction(KeyStroke ks) { Action keyAction = actionManager.getDockingKeyAction(ks); if (keyAction instanceof MultipleKeyAction) { @@ -230,6 +226,11 @@ public class KeyEntryDialog extends DialogComponentProvider { } private boolean shouldAddAction(DockingActionIf dockableAction) { - return dockableAction.isKeyBindingManaged(); + if (dockableAction.isKeyBindingManaged()) { + return true; + } + + // shared key bindings are handled specially + return !dockableAction.usesSharedKeyBinding(); } } diff --git a/Ghidra/Framework/Docking/src/main/java/docking/util/ActionAdapter.java b/Ghidra/Framework/Docking/src/main/java/docking/actions/ActionAdapter.java similarity index 99% rename from Ghidra/Framework/Docking/src/main/java/docking/util/ActionAdapter.java rename to Ghidra/Framework/Docking/src/main/java/docking/actions/ActionAdapter.java index e160687404..e84079cb6f 100644 --- a/Ghidra/Framework/Docking/src/main/java/docking/util/ActionAdapter.java +++ b/Ghidra/Framework/Docking/src/main/java/docking/actions/ActionAdapter.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package docking.util; +package docking.actions; import java.awt.event.ActionEvent; import java.beans.PropertyChangeEvent; diff --git a/Ghidra/Framework/Docking/src/main/java/docking/actions/DockingToolActionManager.java b/Ghidra/Framework/Docking/src/main/java/docking/actions/DockingToolActionManager.java index 4ec6c3d942..e2093027c7 100644 --- a/Ghidra/Framework/Docking/src/main/java/docking/actions/DockingToolActionManager.java +++ b/Ghidra/Framework/Docking/src/main/java/docking/actions/DockingToolActionManager.java @@ -18,9 +18,12 @@ package docking.actions; import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; import java.util.*; +import java.util.function.Predicate; import javax.swing.KeyStroke; +import org.apache.commons.collections4.map.LazyMap; + import docking.*; import docking.action.*; import docking.tool.util.DockingToolConstants; @@ -33,13 +36,16 @@ import ghidra.util.exception.AssertException; public class DockingToolActionManager implements PropertyChangeListener { private DockingWindowManager winMgr; - private Map> actionMap = new HashMap<>(); + private DockingWindowManagerActionUpdater winMgrActionUpdater; + + private Map> actionMap = + LazyMap.lazyMap(new HashMap<>(), () -> new ArrayList<>()); private Map sharedActionMap = new HashMap<>(); private ToolOptions keyBindingOptions; private DockingTool dockingTool; /** - * Construct an ActionManager. + * Construct an ActionManager * * @param tool tool using this ActionManager * @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) { this.dockingTool = tool; this.winMgr = windowManager; + this.winMgrActionUpdater = new DockingWindowManagerActionUpdater(winMgr); keyBindingOptions = tool.getOptions(DockingToolConstants.KEY_BINDINGS); } @@ -58,26 +65,32 @@ public class DockingToolActionManager implements PropertyChangeListener { private void addActionToMap(DockingActionIf action) { String name = action.getFullName(); List actionList = actionMap.get(name); - if (actionList == null) { - List newList = new ArrayList<>(); - newList.add(action); - actionMap.put(name, newList); - } - else { - actionList.add(action); + + List list = actionMap.get(name); + if (!list.isEmpty()) { + KeyBindingUtils.assertSameDefaultKeyBindings(action, actionList); } + + actionList.add(action); } private void removeActionFromMap(DockingActionIf action) { String name = action.getFullName(); - List actionList = actionMap.get(name); - if (actionList == null) { - return; - } + actionMap.get(name).remove(action); + } - 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); addActionToMap(action); setKeyBindingOption(action); - winMgr.addToolAction(action); + winMgrActionUpdater.addToolAction(action); } private void setKeyBindingOption(DockingActionIf action) { @@ -135,7 +148,7 @@ public class DockingToolActionManager implements PropertyChangeListener { public synchronized void removeToolAction(DockingActionIf action) { action.removePropertyChangeListener(this); 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 */ public synchronized void removeToolActions(String owner) { - List actions = getActions(owner); + Predicate ownerMatches = actionOwner -> actionOwner.equals(owner); + Set actions = getActions(ownerMatches); for (DockingActionIf action : actions) { 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) { String name = action.getFullName(); List actionList = actionMap.get(name); - if (actionList == null) { - return; - } if (actionList.contains(action)) { throw new AssertException("Cannot add the same action more than once. Provider " + 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)" * @return list of actions; empty if no action exists with the given name */ - public List getDockingActionsByFullActionName(String fullName) { + public Set getDockingActionsByFullActionName(String fullName) { List list = actionMap.get(fullName); - if (list == null) { - list = new ArrayList<>(); - } - - return new ArrayList<>(list); + return new HashSet<>(list); } /** - * Returns a list of actions whose owner matches the given owner or all actions if the given - * owner is null. - *

- * This method will only return a single instance of any named action, even if multiple - * actions have been registered with the same name. - *

+ * Returns a list of actions whose owner matches the given predicate. + * * 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. */ - private List getUniqueActionList(String owner) { + private Set getActions(Predicate ownerFilter) { - List matchingActionList = new ArrayList<>(); - for (List actionList : actionMap.values()) { - // we only want *one* instance of duplicate actions - DockingActionIf action = actionList.get(0); - if (owner == null || action.getOwner().equals(owner)) { - matchingActionList.add(action); + Set result = new HashSet<>(); + for (List list : actionMap.values()) { + for (DockingActionIf action : list) { + if (ownerFilter.test(action.getOwner())) { + result.addAll(list); + } } } - // these are the 'shared' actions that are needed in order to appear in the options UI for (DockingActionIf action : sharedActionMap.values()) { - if (owner == null || action.getOwner().equals(owner)) { - matchingActionList.add(action); + if (ownerFilter.test(action.getOwner())) { + 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 * action exists with the given name */ - public synchronized List getActions(String owner) { - List list = getUniqueActionList(owner); - return list; + public synchronized Set getActions(String owner) { + Predicate ownerMatches = actionOwner -> actionOwner.equals(owner); + 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 */ - public List getAllActions() { - return getUniqueActionList(null); + public synchronized Set getAllActions() { + Predicate allOwnersMatch = name -> true; + return getActions(allOwnersMatch); } /** @@ -262,7 +252,7 @@ public class DockingToolActionManager implements PropertyChangeListener { */ public synchronized void restoreKeyBindings() { keyBindingOptions = dockingTool.getOptions(DockingToolConstants.KEY_BINDINGS); - List actions = getAllActions(); + Set actions = getAllActions(); for (DockingActionIf action : actions) { if (!action.isKeyBindingManaged()) { continue; @@ -284,10 +274,7 @@ public class DockingToolActionManager implements PropertyChangeListener { while (iterator.hasNext()) { DockingActionIf action = iterator.next(); String name = action.getFullName(); - List actionList = actionMap.get(name); - if (actionList != null && actionList.remove(action) && actionList.isEmpty()) { - actionMap.remove(name); - } + actionMap.get(name).remove(action); } } diff --git a/Ghidra/Framework/Docking/src/main/java/docking/util/KeyBindingUtils.java b/Ghidra/Framework/Docking/src/main/java/docking/actions/KeyBindingUtils.java similarity index 71% rename from Ghidra/Framework/Docking/src/main/java/docking/util/KeyBindingUtils.java rename to Ghidra/Framework/Docking/src/main/java/docking/actions/KeyBindingUtils.java index 0b03560b7c..6939d2375a 100644 --- a/Ghidra/Framework/Docking/src/main/java/docking/util/KeyBindingUtils.java +++ b/Ghidra/Framework/Docking/src/main/java/docking/actions/KeyBindingUtils.java @@ -13,11 +13,12 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package docking.util; +package docking.actions; import java.awt.Component; import java.awt.KeyboardFocusManager; import java.io.*; +import java.util.*; import javax.swing.*; @@ -27,8 +28,10 @@ import org.jdom.*; import org.jdom.input.SAXBuilder; import org.jdom.output.XMLOutputter; -import docking.action.ActionContextProvider; -import docking.action.DockingAction; +import com.google.common.collect.Sets; + +import docking.DockingTool; +import docking.action.*; import docking.widgets.filechooser.GhidraFileChooser; import ghidra.framework.options.ToolOptions; import ghidra.framework.preferences.Preferences; @@ -37,6 +40,8 @@ import ghidra.util.filechooser.GhidraFileChooserModel; import ghidra.util.filechooser.GhidraFileFilter; import ghidra.util.xml.GenericXMLOutputter; 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 @@ -81,6 +86,7 @@ public class KeyBindingUtils { * If there is a problem reading the data then the user will be shown an * 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 * associated keystrokes. */ @@ -232,9 +238,8 @@ public class KeyBindingUtils { * @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 focusCondition the focus condition under which to bind the action - * ({@link JComponent#getInputMap(int)}) - * @param focusCondition see {@link JComponent} for more info; the default - * is usually {@link JComponent#WHEN_FOCUSED} + * ({@link JComponent#getInputMap(int)}). See {@link JComponent} for more info; + * the default is usually {@link JComponent#WHEN_FOCUSED} */ public static void registerAction(JComponent component, KeyStroke keyStroke, Action action, int focusCondition) { @@ -324,6 +329,116 @@ public class KeyBindingUtils { 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 getAllKeyBindingActions(DockingTool tool) { + + Map deduper = new HashMap<>(); + Set 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 getKeyBindingActions(DockingTool tool, String owner) { + + Map deduper = new HashMap<>(); + Set 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 getActions(DockingTool tool, String owner, String name) { + Set 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 getActions(Set allActions, String owner, + String name) { + + Set 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 allActions, + String sharedName) { + + Set 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 * Swing components @@ -341,6 +456,46 @@ public class KeyBindingUtils { return new ActionAdapter(action); } + public static void assertSameDefaultKeyBindings(DockingActionIf newAction, + List 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 //================================================================================================== diff --git a/Ghidra/Framework/Docking/src/main/java/docking/actions/SharedStubKeyBindingAction.java b/Ghidra/Framework/Docking/src/main/java/docking/actions/SharedStubKeyBindingAction.java index 8b6ed12a3f..ce2c3efd2b 100644 --- a/Ghidra/Framework/Docking/src/main/java/docking/actions/SharedStubKeyBindingAction.java +++ b/Ghidra/Framework/Docking/src/main/java/docking/actions/SharedStubKeyBindingAction.java @@ -25,8 +25,6 @@ import docking.DockingWindowManager; import docking.action.*; import ghidra.framework.options.OptionsChangeListener; 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 @@ -95,7 +93,8 @@ public class SharedStubKeyBindingAction extends DockingAction implements Options continue; } - logDifferentKeyBindingsWarnigMessage(newAction, existingAction, existingDefaultKs); + KeyBindingUtils.logDifferentKeyBindingsWarnigMessage(newAction, existingAction, + existingDefaultKs); // // 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; } - 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) { KeyStroke optionsKs = getKeyStrokeFromOptions(defaultKs); diff --git a/Ghidra/Framework/Docking/src/main/java/docking/help/HelpViewSearcher.java b/Ghidra/Framework/Docking/src/main/java/docking/help/HelpViewSearcher.java index d34b964fe2..0287ef964d 100644 --- a/Ghidra/Framework/Docking/src/main/java/docking/help/HelpViewSearcher.java +++ b/Ghidra/Framework/Docking/src/main/java/docking/help/HelpViewSearcher.java @@ -32,7 +32,7 @@ import javax.swing.text.Document; import docking.DockingUtils; import docking.DockingWindowManager; -import docking.util.KeyBindingUtils; +import docking.actions.KeyBindingUtils; import docking.widgets.*; import ghidra.util.Msg; import ghidra.util.exception.AssertException; diff --git a/Ghidra/Framework/Docking/src/main/java/docking/test/AbstractDockingTest.java b/Ghidra/Framework/Docking/src/main/java/docking/test/AbstractDockingTest.java index 47d06cae3e..b9cc998e54 100644 --- a/Ghidra/Framework/Docking/src/main/java/docking/test/AbstractDockingTest.java +++ b/Ghidra/Framework/Docking/src/main/java/docking/test/AbstractDockingTest.java @@ -38,6 +38,8 @@ import org.apache.commons.io.FilenameUtils; import org.apache.commons.lang3.StringUtils; import org.junit.*; +import com.google.common.collect.Sets; + import docking.*; import docking.action.DockingActionIf; import docking.action.ToggleDockingActionIf; @@ -1098,23 +1100,48 @@ public abstract class AbstractDockingTest extends AbstractGenericTest { * @param name the name to match * @return the matching actions; empty list if no matches */ - public static Set getActions(DockingTool tool, String name) { + public static Set getActionsByName(DockingTool tool, String name) { - Set actions = new HashSet<>(); + Set result = new HashSet<>(); - List toolActions = tool.getAllActions(); + Set toolActions = tool.getAllActions(); for (DockingActionIf action : toolActions) { 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 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 getActionsByOwnerAndName(DockingTool tool, String owner, + String name) { + Set 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 * 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. * *

Note: more specific test case subclasses provide other methods for finding actions * 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) { - Set actions = getActions(tool, name); + Set actions = getActionsByName(tool, name); if (actions.isEmpty()) { return null; } @@ -1140,7 +1167,7 @@ public abstract class AbstractDockingTest extends AbstractGenericTest { /** * Finds the action by the given owner name and action name. * If you do not know the owner name, then use - * the call {@link #getActions(DockingTool, String)} instead. + * the call {@link #getActionsByName(DockingTool, String)} instead. * *

Note: more specific test case subclasses provide other methods for finding actions * 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 */ public static DockingActionIf getAction(DockingTool tool, String owner, String name) { - String fullName = name + " (" + owner + ")"; - List actions = tool.getDockingActionsByFullActionName(fullName); + Set actions = getActionsByOwnerAndName(tool, owner, name); if (actions.isEmpty()) { return null; } @@ -1160,7 +1186,7 @@ public abstract class AbstractDockingTest extends AbstractGenericTest { if (actions.size() > 1) { // This shouldn't happen throw new AssertionFailedError( - "Found more than one action for name '" + fullName + "'"); + "Found more than one action for name '" + name + " (" + owner + ")'"); } return CollectionUtils.any(actions); diff --git a/Ghidra/Framework/Docking/src/main/java/docking/widgets/table/AbstractSortedTableModel.java b/Ghidra/Framework/Docking/src/main/java/docking/widgets/table/AbstractSortedTableModel.java index 61efa594e9..2421f5d1d8 100644 --- a/Ghidra/Framework/Docking/src/main/java/docking/widgets/table/AbstractSortedTableModel.java +++ b/Ghidra/Framework/Docking/src/main/java/docking/widgets/table/AbstractSortedTableModel.java @@ -442,7 +442,9 @@ public abstract class AbstractSortedTableModel extends AbstractGTableModel public int compare(T t1, T t2) { // 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); } diff --git a/Ghidra/Framework/Docking/src/main/java/docking/widgets/table/GTable.java b/Ghidra/Framework/Docking/src/main/java/docking/widgets/table/GTable.java index 3d31f624b7..ec812ca7f8 100644 --- a/Ghidra/Framework/Docking/src/main/java/docking/widgets/table/GTable.java +++ b/Ghidra/Framework/Docking/src/main/java/docking/widgets/table/GTable.java @@ -31,7 +31,7 @@ import javax.swing.table.*; import docking.*; import docking.action.*; -import docking.util.KeyBindingUtils; +import docking.actions.KeyBindingUtils; import docking.widgets.OptionDialog; import docking.widgets.dialogs.SettingsDialog; import docking.widgets.filechooser.GhidraFileChooser; diff --git a/Ghidra/Framework/Docking/src/test.slow/java/docking/actions/SharedKeybindingDockingActionTest.java b/Ghidra/Framework/Docking/src/test.slow/java/docking/actions/SharedKeyBindingDockingActionTest.java similarity index 81% rename from Ghidra/Framework/Docking/src/test.slow/java/docking/actions/SharedKeybindingDockingActionTest.java rename to Ghidra/Framework/Docking/src/test.slow/java/docking/actions/SharedKeyBindingDockingActionTest.java index a79bf1d4b0..7e7385c514 100644 --- a/Ghidra/Framework/Docking/src/test.slow/java/docking/actions/SharedKeybindingDockingActionTest.java +++ b/Ghidra/Framework/Docking/src/test.slow/java/docking/actions/SharedKeyBindingDockingActionTest.java @@ -36,7 +36,7 @@ import ghidra.framework.options.ToolOptions; import ghidra.util.Msg; 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_OWNER = SharedStubKeyBindingAction.SHARED_OWNER; @@ -158,8 +158,7 @@ public class SharedKeybindingDockingActionTest extends AbstractDockingTest { tool.removeAction(action2); assertActionNotInTool(action2); - String sharedName = action1.getFullName(); - assertNoSharedKeyBindingStubInstalled(sharedName); + assertNoSharedKeyBindingStubInstalled(action1); } @Test @@ -271,8 +270,7 @@ public class SharedKeybindingDockingActionTest extends AbstractDockingTest { tool.removeLocalAction(provider, action2); assertActionNotInTool(action2); - String sharedName = action1.getFullName(); - assertNoSharedKeyBindingStubInstalled(sharedName); + assertNoSharedKeyBindingStubInstalled(action1); } @Test @@ -293,7 +291,65 @@ public class SharedKeybindingDockingActionTest extends AbstractDockingTest { assertActionNotInTool(action2); 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) { - Set actions = getActions(tool, action.getName()); + Set actions = getActionsByName(tool, action.getName()); for (DockingActionIf toolAction : actions) { if (toolAction == action) { return; @@ -328,16 +384,19 @@ public class SharedKeybindingDockingActionTest extends AbstractDockingTest { } private void assertActionNotInTool(TestAction action) { - Set actions = getActions(tool, action.getName()); + Set actions = getActionsByName(tool, action.getName()); for (DockingActionIf toolAction : actions) { assertNotSame(toolAction, action); } } - private void assertNoSharedKeyBindingStubInstalled(String sharedName) { - List actions = tool.getDockingActionsByFullActionName(sharedName); - assertTrue("There should be no actions registered for '" + sharedName + "'", - actions.isEmpty()); + private void assertNoSharedKeyBindingStubInstalled(DockingActionIf action) { + + String name = action.getName(); + 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) { @@ -355,7 +414,7 @@ public class SharedKeybindingDockingActionTest extends AbstractDockingTest { } 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) { diff --git a/Ghidra/Framework/Docking/src/test/java/docking/DockingActionKeybindingTest.java b/Ghidra/Framework/Docking/src/test/java/docking/DockingActionKeyBindingTest.java similarity index 97% rename from Ghidra/Framework/Docking/src/test/java/docking/DockingActionKeybindingTest.java rename to Ghidra/Framework/Docking/src/test/java/docking/DockingActionKeyBindingTest.java index e9b2436ccb..afe8d22ca8 100644 --- a/Ghidra/Framework/Docking/src/test/java/docking/DockingActionKeybindingTest.java +++ b/Ghidra/Framework/Docking/src/test/java/docking/DockingActionKeyBindingTest.java @@ -26,7 +26,7 @@ import org.junit.Test; import generic.test.AbstractGenericTest; -public class DockingActionKeybindingTest extends AbstractGenericTest { +public class DockingActionKeyBindingTest extends AbstractGenericTest { @Test public void testKeybinding_Unmodified() { diff --git a/Ghidra/Framework/Generic/src/main/java/ghidra/util/StringUtilities.java b/Ghidra/Framework/Generic/src/main/java/ghidra/util/StringUtilities.java index c8c70e539c..84236b795a 100644 --- a/Ghidra/Framework/Generic/src/main/java/ghidra/util/StringUtilities.java +++ b/Ghidra/Framework/Generic/src/main/java/ghidra/util/StringUtilities.java @@ -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 * @return a string representation of the given list */ - public static String toString(List list, String separator) { - if (list == null) { + public static String toString(Collection collection, String separator) { + if (collection == null) { return null; } + int i = 0; StringBuffer buffer = new StringBuffer("[ "); - for (int i = 0; i < list.size(); i++) { - buffer.append(list.get(i).toString()); - if (i + 1 < list.size()) { + for (Object o : collection) { + buffer.append(o.toString()); + if (i + 1 < collection.size()) { buffer.append(separator); } + i++; } buffer.append(" ]"); diff --git a/Ghidra/Framework/Project/src/main/java/ghidra/framework/main/datatree/DataTree.java b/Ghidra/Framework/Project/src/main/java/ghidra/framework/main/datatree/DataTree.java index e67d1dfae2..e345ccc3ec 100644 --- a/Ghidra/Framework/Project/src/main/java/ghidra/framework/main/datatree/DataTree.java +++ b/Ghidra/Framework/Project/src/main/java/ghidra/framework/main/datatree/DataTree.java @@ -22,7 +22,7 @@ import javax.swing.*; import javax.swing.tree.TreePath; import docking.DockingUtils; -import docking.util.KeyBindingUtils; +import docking.actions.KeyBindingUtils; import docking.widgets.tree.*; import docking.widgets.tree.support.GTreeRenderer; import ghidra.framework.main.FrontEndTool; diff --git a/Ghidra/Framework/Project/src/main/java/ghidra/framework/plugintool/PluginConfigurationModel.java b/Ghidra/Framework/Project/src/main/java/ghidra/framework/plugintool/PluginConfigurationModel.java index 775460bf49..f0a36ded7f 100644 --- a/Ghidra/Framework/Project/src/main/java/ghidra/framework/plugintool/PluginConfigurationModel.java +++ b/Ghidra/Framework/Project/src/main/java/ghidra/framework/plugintool/PluginConfigurationModel.java @@ -21,6 +21,7 @@ import javax.swing.Icon; import javax.swing.event.ChangeListener; import docking.action.DockingActionIf; +import docking.actions.KeyBindingUtils; import ghidra.framework.plugintool.util.*; import ghidra.util.Msg; import resources.ResourceManager; @@ -212,12 +213,12 @@ public class PluginConfigurationModel { * @param pluginDescription The description for which to find loaded actions. * @return all of the actions loaded by the Plugin represented by the given PluginDescription. */ - public List getActionsForPlugin(PluginDescription pluginDescription) { + public Set getActionsForPlugin(PluginDescription pluginDescription) { if (!isLoaded(pluginDescription)) { - return Collections.emptyList(); + return Collections.emptySet(); } - return tool.getDockingActionsByOwnerName(pluginDescription.getName()); + return KeyBindingUtils.getKeyBindingActions(tool, pluginDescription.getName()); } /** diff --git a/Ghidra/Framework/Project/src/main/java/ghidra/framework/plugintool/dialog/KeyBindingsPanel.java b/Ghidra/Framework/Project/src/main/java/ghidra/framework/plugintool/dialog/KeyBindingsPanel.java index a97816af88..ab0077ae67 100644 --- a/Ghidra/Framework/Project/src/main/java/ghidra/framework/plugintool/dialog/KeyBindingsPanel.java +++ b/Ghidra/Framework/Project/src/main/java/ghidra/framework/plugintool/dialog/KeyBindingsPanel.java @@ -20,6 +20,7 @@ import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; import java.util.*; import java.util.List; +import java.util.Map.Entry; import javax.swing.*; import javax.swing.event.ListSelectionEvent; @@ -30,8 +31,8 @@ import docking.DockingUtils; import docking.KeyEntryTextField; import docking.action.DockingActionIf; import docking.action.KeyBindingData; +import docking.actions.KeyBindingUtils; import docking.tool.util.DockingToolConstants; -import docking.util.KeyBindingUtils; import docking.widgets.MultiLineLabel; import docking.widgets.OptionDialog; import docking.widgets.label.GIconLabel; @@ -39,8 +40,7 @@ import docking.widgets.table.*; import ghidra.framework.options.Options; import ghidra.framework.options.ToolOptions; import ghidra.framework.plugintool.PluginTool; -import ghidra.util.HTMLUtilities; -import ghidra.util.ReservedKeyBindings; +import ghidra.util.*; import ghidra.util.exception.AssertException; import ghidra.util.layout.PairLayout; import ghidra.util.layout.VerticalLayout; @@ -65,11 +65,13 @@ public class KeyBindingsPanel extends JPanel { private KeyBindingsTableModel tableModel; private ListSelectionModel selectionModel; private Options options; - private Map actionMap; // map action name to keystroke - private Map> keyMap; // map keystroke name to ArrayList of action names - private List actionList; - private Map originalValues; // original mapping for action name to - // keystroke (to know what changed) + + private Map actionsByFullName; + private Map> actionNamesByKeyStroke; + private Map keyStrokesByFullName; + private Map originalValues; // to know what has been changed + private List tableActions; + private KeyEntryTextField ksField; private boolean unappliedChanges; @@ -81,7 +83,7 @@ public class KeyBindingsPanel extends JPanel { public KeyBindingsPanel(PluginTool tool, Options options) { this.tool = tool; this.options = options; - actionList = new ArrayList<>(); + tableActions = new ArrayList<>(); create(); createActionMap(); addListeners(); @@ -100,10 +102,10 @@ public class KeyBindingsPanel extends JPanel { * Apply the changes to the actions. */ public void apply() { - Iterator iter = actionMap.keySet().iterator(); + Iterator iter = keyStrokesByFullName.keySet().iterator(); while (iter.hasNext()) { String actionName = iter.next(); - KeyStroke currentKeyStroke = actionMap.get(actionName); + KeyStroke currentKeyStroke = keyStrokesByFullName.get(actionName); KeyStroke originalKeyStroke = originalValues.get(actionName); updateOptions(actionName, originalKeyStroke, currentKeyStroke); } @@ -111,7 +113,7 @@ public class KeyBindingsPanel extends JPanel { changesMade(false); } - private boolean updateOptions(String actionName, KeyStroke currentKeyStroke, + private boolean updateOptions(String fullActionName, KeyStroke currentKeyStroke, KeyStroke newKeyStroke) { if ((currentKeyStroke != null && currentKeyStroke.equals(newKeyStroke)) || (currentKeyStroke == null && newKeyStroke == null)) { @@ -119,17 +121,17 @@ public class KeyBindingsPanel extends JPanel { } if (newKeyStroke != null) { - options.setKeyStroke(actionName, newKeyStroke); + options.setKeyStroke(fullActionName, newKeyStroke); } else { - options.removeOption(actionName); + options.removeOption(fullActionName); } - originalValues.put(actionName, newKeyStroke); - actionMap.put(actionName, newKeyStroke); + originalValues.put(fullActionName, newKeyStroke); + keyStrokesByFullName.put(fullActionName, newKeyStroke); - List actions = tool.getDockingActionsByFullActionName(actionName); + Set actions = tool.getAllActions(); for (DockingActionIf action : actions) { - if (action.isKeyBindingManaged()) { + if (action.getFullName().equals(fullActionName)) { action.setUnvalidatedKeyBindingData(new KeyBindingData(newKeyStroke)); } } @@ -145,46 +147,40 @@ public class KeyBindingsPanel extends JPanel { while (iter.hasNext()) { String actionName = iter.next(); KeyStroke originalKS = originalValues.get(actionName); - KeyStroke modifiedKS = actionMap.get(actionName); + KeyStroke modifiedKS = keyStrokesByFullName.get(actionName); if (modifiedKS != null && !modifiedKS.equals(originalKS)) { - actionMap.put(actionName, originalKS); + keyStrokesByFullName.put(actionName, originalKS); } } tableModel.fireTableDataChanged(); } public void reload() { - // run this after the current pending events in the swing - // thread so that the screen will repaint itself - SwingUtilities.invokeLater(() -> { - // clear the current user key stroke so that it does not - // appear as though the user is editing while restoring + Swing.runLater(() -> { + // clear the current user key stroke so that it does not appear as though the + // user is editing while restoring actionTable.clearSelection(); restoreDefaultKeybindings(); }); } - /** - * Create the maps for actions and names. - */ private void createActionMap() { - actionMap = new HashMap<>(); - keyMap = new HashMap<>(); + keyStrokesByFullName = new HashMap<>(); + actionNamesByKeyStroke = new HashMap<>(); originalValues = new HashMap<>(); String longestName = ""; - List actions = tool.getAllActions(); - for (DockingActionIf action : actions) { - if (isIgnored(action)) { - continue; - } + actionsByFullName = KeyBindingUtils.getAllKeyBindingActions(tool); + Set> entries = actionsByFullName.entrySet(); + for (Entry entry : entries) { - String actionName = action.getFullName(); - actionList.add(action); + DockingActionIf action = entry.getValue(); + tableActions.add(action); + String actionName = entry.getKey(); KeyStroke ks = options.getKeyStroke(actionName, null); - actionMap.put(actionName, ks); + keyStrokesByFullName.put(actionName, ks); addToKeyMap(ks, actionName); originalValues.put(actionName, ks); @@ -206,12 +202,6 @@ public class KeyBindingsPanel extends JPanel { 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. */ @@ -328,11 +318,10 @@ public class KeyBindingsPanel extends JPanel { return; } - // run this after the current pending events in the swing - // thread so that the screen will repaint itself - SwingUtilities.invokeLater(() -> { - // clear the current user key stroke so that it does not - // appear as though the user is editing while importing + // give Swing a chance to repaint + Swing.runLater(() -> { + // clear the current user key stroke so that it does not appear as though the + // user is editing while importing actionTable.clearSelection(); processKeyBindingsFromOptions(KeyBindingUtils.importKeyBindings()); }); @@ -349,9 +338,8 @@ public class KeyBindingsPanel extends JPanel { return; } - // run this after the current pending events in the swing - // thread so that the screen will repaint itself - SwingUtilities.invokeLater(() -> { + // give Swing a chance to repaint + Swing.runLater(() -> { ToolOptions keyBindingOptions = tool.getOptions(DockingToolConstants.KEY_BINDINGS); KeyBindingUtils.exportKeyBindings(keyBindingOptions); }); @@ -421,16 +409,16 @@ public class KeyBindingsPanel extends JPanel { } private void restoreDefaultKeybindings() { - Iterator iter = actionMap.keySet().iterator(); + Iterator iter = keyStrokesByFullName.keySet().iterator(); while (iter.hasNext()) { String actionName = iter.next(); - List actions = tool.getDockingActionsByFullActionName(actionName); - if (actions.size() == 0) { + DockingActionIf action = actionsByFullName.get(actionName); + if (action == null) { throw new AssertException("No actions defined for " + actionName); } - KeyStroke currentKeyStroke = actionMap.get(actionName); - KeyBindingData defaultBinding = actions.get(0).getDefaultKeyBindingData(); + KeyStroke currentKeyStroke = keyStrokesByFullName.get(actionName); + KeyBindingData defaultBinding = action.getDefaultKeyBindingData(); KeyStroke newKeyStroke = (defaultBinding == null) ? null : defaultBinding.getKeyBinding(); @@ -453,7 +441,7 @@ public class KeyBindingsPanel extends JPanel { String ksName = KeyEntryTextField.parseKeyStroke(keyStroke); // remove old keystroke for action name - KeyStroke oldKs = actionMap.get(actionName); + KeyStroke oldKs = keyStrokesByFullName.get(actionName); if (oldKs != null) { String oldName = KeyEntryTextField.parseKeyStroke(oldKs); if (oldName.equals(ksName)) { @@ -463,7 +451,7 @@ public class KeyBindingsPanel extends JPanel { } addToKeyMap(keyStroke, actionName); - actionMap.put(actionName, keyStroke); + keyStrokesByFullName.put(actionName, keyStroke); changesMade(true); return true; } @@ -486,7 +474,7 @@ public class KeyBindingsPanel extends JPanel { } int selectedRow = actionTable.getSelectedRow(); 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; } String ksName = KeyEntryTextField.parseKeyStroke(ks); - List list = keyMap.get(ksName); + List list = actionNamesByKeyStroke.get(ksName); if (list == null) { list = new ArrayList<>(); - keyMap.put(ksName, list); + actionNamesByKeyStroke.put(ksName, list); } if (!list.contains(actionName)) { list.add(actionName); @@ -515,11 +503,11 @@ public class KeyBindingsPanel extends JPanel { return; } String ksName = KeyEntryTextField.parseKeyStroke(ks); - List list = keyMap.get(ksName); + List list = actionNamesByKeyStroke.get(ksName); if (list != null) { list.remove(actionName); 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 */ private void showActionMapped(String ksName) { - List list = keyMap.get(ksName); + List list = actionNamesByKeyStroke.get(ksName); if (list == null) { return; } @@ -595,7 +583,7 @@ public class KeyBindingsPanel extends JPanel { // prevent non-existing keybindings from being added to Ghidra (this can happen // when actions exist in the imported bindings, but have been removed from // Ghidra - if (!actionMap.containsKey(name)) { + if (!keyStrokesByFullName.containsKey(name)) { continue; } @@ -647,12 +635,10 @@ public class KeyBindingsPanel extends JPanel { char keyChar = keyStroke.getKeyChar(); if (Character.isWhitespace(keyChar) || Character.getType(keyChar) == Character.DIRECTIONALITY_LEFT_TO_RIGHT_OVERRIDE) { - // remove keystroke removeKeystroke(actionName); } else { - // check the action to see if is different than the current - // value + // check the action to see if is different than the current value return checkAction(actionName, keyStroke); } } @@ -663,20 +649,24 @@ public class KeyBindingsPanel extends JPanel { private void removeKeystroke(String selectedActionName) { ksField.setText(""); - if (actionMap.containsKey(selectedActionName)) { - KeyStroke stroke = actionMap.get(selectedActionName); + if (keyStrokesByFullName.containsKey(selectedActionName)) { + KeyStroke stroke = keyStrokesByFullName.get(selectedActionName); if (stroke == null) { // nothing to remove; nothing has changed return; } removeFromKeyMap(stroke, selectedActionName); - actionMap.put(selectedActionName, null); + keyStrokesByFullName.put(selectedActionName, null); tableModel.fireTableDataChanged(); changesMade(true); } } + Map getKeyStrokeMap() { + return keyStrokesByFullName; + } + //================================================================================================== // Inner Classes //================================================================================================== @@ -690,8 +680,12 @@ public class KeyBindingsPanel extends JPanel { return; } - String selectedAction = getSelectedAction(); - KeyStroke ks = actionMap.get(selectedAction); + String fullActionName = getSelectedAction(); + if (fullActionName == null) { + return; + } + + KeyStroke ks = keyStrokesByFullName.get(fullActionName); String ksName = ""; clearInfoPanel(); @@ -705,18 +699,12 @@ public class KeyBindingsPanel extends JPanel { statusLabel.setPreferredSize( new Dimension(statusLabel.getPreferredSize().width, STATUS_LABEL_HEIGHT)); - try { - List actions = - tool.getDockingActionsByFullActionName(selectedAction); - String description = actions.get(0).getDescription(); - if (description == null || description.trim().isEmpty()) { - description = actions.get(0).getName(); - } - statusLabel.setText("" + HTMLUtilities.escapeHTML(description)); - } - catch (Exception ex) { - statusLabel.setText(""); + DockingActionIf action = actionsByFullName.get(fullActionName); + String description = action.getDescription(); + if (description == null || description.trim().isEmpty()) { + description = action.getName(); } + statusLabel.setText("" + HTMLUtilities.escapeHTML(description)); } } @@ -740,7 +728,7 @@ public class KeyBindingsPanel extends JPanel { return action.getName(); case KEY_BINDING: - KeyStroke ks = actionMap.get(action.getFullName()); + KeyStroke ks = keyStrokesByFullName.get(action.getFullName()); if (ks != null) { return KeyEntryTextField.parseKeyStroke(ks); } @@ -753,7 +741,7 @@ public class KeyBindingsPanel extends JPanel { @Override public List getModelData() { - return actionList; + return tableActions; } @Override @@ -773,7 +761,7 @@ public class KeyBindingsPanel extends JPanel { @Override public int getRowCount() { - return actionList.size(); + return tableActions.size(); } } } diff --git a/Ghidra/Framework/Project/src/main/java/ghidra/framework/plugintool/dialog/PluginDetailsPanel.java b/Ghidra/Framework/Project/src/main/java/ghidra/framework/plugintool/dialog/PluginDetailsPanel.java index b902d1b206..5fed0e4e1b 100644 --- a/Ghidra/Framework/Project/src/main/java/ghidra/framework/plugintool/dialog/PluginDetailsPanel.java +++ b/Ghidra/Framework/Project/src/main/java/ghidra/framework/plugintool/dialog/PluginDetailsPanel.java @@ -17,8 +17,7 @@ package ghidra.framework.plugintool.dialog; import java.awt.Color; import java.awt.Point; -import java.util.Collections; -import java.util.List; +import java.util.*; import javax.swing.KeyStroke; 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. */ class PluginDetailsPanel extends AbstractDetailsPanel { - + private static SimpleAttributeSet nameAttrSet; - private static SimpleAttributeSet depNameAttrSet; + private static SimpleAttributeSet depNameAttrSet; private static SimpleAttributeSet descrAttrSet; private static SimpleAttributeSet categoriesAttrSet; private static SimpleAttributeSet classAttrSet; @@ -47,84 +46,62 @@ class PluginDetailsPanel extends AbstractDetailsPanel { private static SimpleAttributeSet noValueAttrSet; private final PluginConfigurationModel model; - + PluginDetailsPanel(PluginConfigurationModel model) { super(); this.model = model; createFieldAttributes(); createMainPanel(); } - + void setPluginDescription(PluginDescription pluginDescription) { - - textLabel.setText(""); - if (pluginDescription == null) { - return; - } - + + textLabel.setText(""); + if (pluginDescription == null) { + return; + } + List dependencies = model.getDependencies(pluginDescription); Collections.sort(dependencies, (pd1, pd2) -> pd1.getName().compareTo(pd2.getName())); StringBuilder buffer = new StringBuilder(""); - - buffer.append( "" ); - - insertRowTitle(buffer, "Name"); + + buffer.append("
"); + + insertRowTitle(buffer, "Name"); insertRowValue(buffer, pluginDescription.getName(), !dependencies.isEmpty() ? depNameAttrSet : nameAttrSet); - insertRowTitle(buffer, "Description"); - insertRowValue(buffer, formatDescription(pluginDescription.getDescription()), descrAttrSet); + insertRowTitle(buffer, "Description"); + insertRowValue(buffer, formatDescription(pluginDescription.getDescription()), descrAttrSet); - insertRowTitle(buffer, "Status"); - insertRowValue(buffer, - pluginDescription.getStatus().getDescription(), - (pluginDescription.getStatus() == PluginStatus.RELEASED) ? - titleAttrSet :developerAttrSet); + insertRowTitle(buffer, "Status"); + insertRowValue(buffer, pluginDescription.getStatus().getDescription(), + (pluginDescription.getStatus() == PluginStatus.RELEASED) ? titleAttrSet + : developerAttrSet); - insertRowTitle(buffer, "Package"); - insertRowValue(buffer, pluginDescription.getPluginPackage().getName(), categoriesAttrSet); + insertRowTitle(buffer, "Package"); + insertRowValue(buffer, pluginDescription.getPluginPackage().getName(), categoriesAttrSet); - insertRowTitle(buffer, "Category"); - insertRowValue(buffer, pluginDescription.getCategory(), categoriesAttrSet); + insertRowTitle(buffer, "Category"); + insertRowValue(buffer, pluginDescription.getCategory(), categoriesAttrSet); - insertRowTitle(buffer, "Plugin Class"); - insertRowValue(buffer, pluginDescription.getPluginClass().getName(), classAttrSet); + insertRowTitle(buffer, "Plugin Class"); + insertRowValue(buffer, pluginDescription.getPluginClass().getName(), classAttrSet); - insertRowTitle(buffer, "Class Location"); - insertRowValue(buffer, pluginDescription.getSourceLocation(), locAttrSet); + insertRowTitle(buffer, "Class Location"); + insertRowValue(buffer, pluginDescription.getSourceLocation(), locAttrSet); insertRowTitle(buffer, "Used By"); - - buffer.append( "" ); - buffer.append( "" ); - - insertRowTitle(buffer, "Services Required"); buffer.append(""); buffer.append(""); - // - // Developer - // - // - // Optional: Actions loaded by this plugin - // - addLoadedActionsContent( buffer, pluginDescription ); - - buffer.append( "
" ); - - 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("
", dependencyAttrSet, buffer); - } - } - insertHTMLLine("", titleAttrSet, buffer); // add a newline - } - buffer.append( "
"); - List> servicesRequired = pluginDescription.getServicesRequired(); - if (servicesRequired.isEmpty()) { + if (dependencies.isEmpty()) { insertHTMLLine("None", titleAttrSet, buffer); } else { - for (int i = 0; i < servicesRequired.size(); i++) { - insertHTMLString(servicesRequired.get(i).getName(), dependencyAttrSet, + for (int i = 0; i < dependencies.size(); i++) { + insertHTMLString(dependencies.get(i).getPluginClass().getName(), dependencyAttrSet, buffer); if (i < dependencies.size() - 1) { insertHTMLString("
", dependencyAttrSet, buffer); @@ -135,165 +112,185 @@ class PluginDetailsPanel extends AbstractDetailsPanel { buffer.append("
" ); + insertRowTitle(buffer, "Services Required"); - textLabel.setText( buffer.toString() ); - sp.getViewport().setViewPosition(new Point(0,0)); - } + buffer.append(""); + + List> 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("
", dependencyAttrSet, buffer); + } + } + insertHTMLLine("", titleAttrSet, buffer); // add a newline + } + buffer.append(""); + buffer.append(""); + + // + // Developer + // + // + // Optional: Actions loaded by this plugin + // + addLoadedActionsContent(buffer, pluginDescription); + + buffer.append(""); + + textLabel.setText(buffer.toString()); + sp.getViewport().setViewPosition(new Point(0, 0)); + } // creates an HTML table to display actions loaded by the plugin private void addLoadedActionsContent(StringBuilder buffer, PluginDescription pluginDescription) { - if ( !model.isLoaded( pluginDescription ) ) { - return; - } - - buffer.append( "" ); - buffer.append( "" ); - insertHTMLLine("Loaded Actions:", titleAttrSet, buffer); - buffer.append( "" ); + if (!model.isLoaded(pluginDescription)) { + return; + } - List actionList = model.getActionsForPlugin( pluginDescription ); - if ( actionList.size() == 0 ) { - buffer.append( "" ); - insertHTMLLine("No actions for plugin", noValueAttrSet, buffer); - buffer.append( "" ); - buffer.append( "" ); - return; - } - - buffer.append( "" ); - - buffer.append( "" ); - - for ( DockingActionIf dockableAction : actionList ) { - buffer.append( "" ); - - buffer.append( ""); + buffer.append(""); - if ( popupPath != null ) { - insertHTMLString( "(in a context popup menu)", noValueAttrSet, buffer ); - } - else { - insertHTMLString( "Not in a menu", noValueAttrSet, buffer ); - } - } - - buffer.append( "" ); - - buffer.append( "" ); - } - - buffer.append( "
Action NameMenu PathKeybinding
" ); - insertHTMLString( dockableAction.getName(), locAttrSet, buffer ); - buffer.append( "" ); - 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(); + buffer.append("
"); + insertHTMLLine("Loaded Actions:", titleAttrSet, buffer); + buffer.append("" ); - KeyStroke keyBinding = dockableAction.getKeyBinding(); - if ( keyBinding != null ) { - String keyStrokeString = DockingKeyBindingAction.parseKeyStroke( keyBinding ); - insertHTMLString( keyStrokeString, locAttrSet, buffer ); - } - else { - insertHTMLString( "No keybinding", noValueAttrSet, buffer ); - } - - buffer.append( "
" ); - buffer.append( "" ); - buffer.append( "" ); + Set actions = model.getActionsForPlugin(pluginDescription); + if (actions.size() == 0) { + buffer.append(""); + insertHTMLLine("No actions for plugin", noValueAttrSet, buffer); + buffer.append(""); + buffer.append(""); + return; + } + + buffer.append(""); + + buffer.append( + ""); + + for (DockingActionIf dockableAction : actions) { + buffer.append(""); + + buffer.append(""); + + buffer.append(""); + } + + buffer.append("
Action NameMenu PathKeybinding
"); + insertHTMLString(dockableAction.getName(), locAttrSet, buffer); + buffer.append(""); + 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) { + insertHTMLString("(in a context popup menu)", noValueAttrSet, buffer); + } + else { + insertHTMLString("Not in a menu", noValueAttrSet, buffer); + } + } + + buffer.append(""); + KeyStroke keyBinding = dockableAction.getKeyBinding(); + if (keyBinding != null) { + String keyStrokeString = DockingKeyBindingAction.parseKeyStroke(keyBinding); + insertHTMLString(keyStrokeString, locAttrSet, buffer); + } + else { + insertHTMLString("No keybinding", noValueAttrSet, buffer); + } + + buffer.append("
"); + buffer.append(""); + buffer.append(""); } - - private String createStringForMenuPath( String[] path ) { - if ( path == null ) { - return null; - } - - StringBuffer buffy = new StringBuffer(); - for ( int i = 0; i < path.length; i++ ) { - buffy.append( path[i].replaceAll( "\\&", "" ) ); // strip off the mnemonic identifier '&' - if ( i != path.length-1 ) { - buffy.append( "->" ); - } - } - return buffy.toString(); + + private String createStringForMenuPath(String[] path) { + if (path == null) { + return null; + } + + StringBuffer buffy = new StringBuffer(); + for (int i = 0; i < path.length; i++) { + buffy.append(path[i].replaceAll("\\&", "")); // strip off the mnemonic identifier '&' + if (i != path.length - 1) { + buffy.append("->"); + } + } + return buffy.toString(); } - + @Override protected void createFieldAttributes() { - titleAttrSet = new SimpleAttributeSet(); + titleAttrSet = new SimpleAttributeSet(); 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.Foreground, new Color(140, 0, 0)); nameAttrSet = new SimpleAttributeSet(); 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.Foreground, new Color(0, 204, 51)); depNameAttrSet = new SimpleAttributeSet(); 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.Foreground, Color.RED); - + descrAttrSet = new SimpleAttributeSet(); 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.Foreground, Color.BLUE); categoriesAttrSet = new SimpleAttributeSet(); 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.Foreground, new Color(204, 0, 204)); classAttrSet = new SimpleAttributeSet(); 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.Foreground, Color.BLACK); - + locAttrSet = new SimpleAttributeSet(); 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.Foreground, Color.DARK_GRAY); - + developerAttrSet = new SimpleAttributeSet(); - developerAttrSet.addAttribute(StyleConstants.FontFamily, "Tahoma"); - developerAttrSet.addAttribute(StyleConstants.FontSize, new Integer(11)); + developerAttrSet.addAttribute(StyleConstants.FontFamily, "Tahoma"); + developerAttrSet.addAttribute(StyleConstants.FontSize, Integer.valueOf(11)); developerAttrSet.addAttribute(StyleConstants.Bold, Boolean.TRUE); developerAttrSet.addAttribute(StyleConstants.Foreground, new Color(230, 15, 85)); - + dependencyAttrSet = new SimpleAttributeSet(); - dependencyAttrSet.addAttribute(StyleConstants.FontFamily, "monospaced"); - dependencyAttrSet.addAttribute(StyleConstants.FontSize, new Integer(11)); + dependencyAttrSet.addAttribute(StyleConstants.FontFamily, "monospaced"); + dependencyAttrSet.addAttribute(StyleConstants.FontSize, Integer.valueOf(11)); dependencyAttrSet.addAttribute(StyleConstants.Bold, Boolean.TRUE); dependencyAttrSet.addAttribute(StyleConstants.Foreground, new Color(23, 100, 30)); - + noValueAttrSet = new SimpleAttributeSet(); - noValueAttrSet.addAttribute(StyleConstants.FontFamily, "Tahoma"); - noValueAttrSet.addAttribute(StyleConstants.FontSize, new Integer(11)); - noValueAttrSet.addAttribute(StyleConstants.Italic, Boolean.TRUE); - noValueAttrSet.addAttribute(StyleConstants.Foreground, new Color(192, 192, 192)); + noValueAttrSet.addAttribute(StyleConstants.FontFamily, "Tahoma"); + noValueAttrSet.addAttribute(StyleConstants.FontSize, Integer.valueOf(11)); + noValueAttrSet.addAttribute(StyleConstants.Italic, Boolean.TRUE); + noValueAttrSet.addAttribute(StyleConstants.Foreground, new Color(192, 192, 192)); } } - diff --git a/Ghidra/Framework/Project/src/main/java/ghidra/framework/plugintool/mgr/ProjectActionManager.java b/Ghidra/Framework/Project/src/main/java/ghidra/framework/plugintool/mgr/ProjectActionManager.java index 315f116a3b..ee11475c4b 100644 --- a/Ghidra/Framework/Project/src/main/java/ghidra/framework/plugintool/mgr/ProjectActionManager.java +++ b/Ghidra/Framework/Project/src/main/java/ghidra/framework/plugintool/mgr/ProjectActionManager.java @@ -21,26 +21,33 @@ import java.util.*; import javax.swing.KeyStroke; -import docking.ComponentProvider; -import docking.DockingWindowManager; +import docking.*; import docking.action.*; +import docking.tool.util.DockingToolConstants; import ghidra.framework.options.OptionType; import ghidra.framework.options.Options; import ghidra.framework.plugintool.PluginTool; -import ghidra.framework.plugintool.util.ToolConstants; import ghidra.util.exception.AssertException; /** * Helper class to manage plugin actions for the tool. */ public class ProjectActionManager implements PropertyChangeListener { + private DockingWindowManager winMgr; + private DockingWindowManagerActionUpdater winMgrActionUpdater; + + // TODO + // TODO + // TODO does this class need the shared action concept (probably not) + // TODO + // TODO private Map> actionMap; private Options keyBindingOptions; private PluginTool tool; /** - * Construct an ActionManager. + * Construct an ActionManager * @param tool plugin tool using this ActionManager * @param winMgr manager of the "Docking" arrangement * 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) { this.tool = tool; this.winMgr = winMgr; + this.winMgrActionUpdater = new DockingWindowManagerActionUpdater(winMgr); actionMap = new HashMap<>(); - keyBindingOptions = tool.getOptions(ToolConstants.KEY_BINDINGS); + keyBindingOptions = tool.getOptions(DockingToolConstants.KEY_BINDINGS); } public void dispose() { @@ -97,7 +105,8 @@ public class ProjectActionManager implements PropertyChangeListener { 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) { action.removePropertyChangeListener(this); removeActionFromMap(action); - winMgr.removeToolAction(action); + winMgrActionUpdater.removeToolAction(action); } /** @@ -140,7 +149,7 @@ public class ProjectActionManager implements PropertyChangeListener { action.setUnvalidatedKeyBindingData(new KeyBindingData(newKs)); } } - winMgr.addLocalAction(provider, action); + winMgrActionUpdater.addLocalAction(provider, action); } private void checkForAlreadyAddedAction(ComponentProvider provider, DockingActionIf action) { @@ -167,14 +176,15 @@ public class ProjectActionManager implements PropertyChangeListener { winMgr.removeProviderAction(provider, action); } + // TODO delete me /** * 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)" * @return list of actions; empty if no action exists with the given name */ - public List getDockingActionsByFullActionName(String fullActionName) { - List list = actionMap.get(fullActionName); + public List getDockingActionsByFullActionName(String fullName) { + List list = actionMap.get(fullName); if (list == null) { return new ArrayList<>(); } @@ -233,7 +243,7 @@ public class ProjectActionManager implements PropertyChangeListener { * */ public synchronized void restoreKeyBindings() { - keyBindingOptions = tool.getOptions(ToolConstants.KEY_BINDINGS); + keyBindingOptions = tool.getOptions(DockingToolConstants.KEY_BINDINGS); List actions = getAllActions(); for (DockingActionIf action : actions) { if (!action.isKeyBindingManaged()) { @@ -275,7 +285,7 @@ public class ProjectActionManager implements PropertyChangeListener { } KeyBindingData keyBindingData = (KeyBindingData) evt.getNewValue(); 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); if (newKeyStroke == null) { opt.removeOption(action.getFullName()); diff --git a/Ghidra/Test/IntegrationTest/src/screen/java/help/screenshot/AssemblerPluginScreenShots.java b/Ghidra/Test/IntegrationTest/src/screen/java/help/screenshot/AssemblerPluginScreenShots.java index 165715f96e..703c8263e4 100644 --- a/Ghidra/Test/IntegrationTest/src/screen/java/help/screenshot/AssemblerPluginScreenShots.java +++ b/Ghidra/Test/IntegrationTest/src/screen/java/help/screenshot/AssemblerPluginScreenShots.java @@ -18,12 +18,10 @@ package help.screenshot; import java.awt.AWTException; import java.awt.Robot; import java.awt.event.KeyEvent; -import java.util.List; import org.junit.Test; import docking.action.DockingActionIf; -import ghidra.app.plugin.core.assembler.AssembleDockingAction; import ghidra.app.plugin.core.assembler.AssemblerPlugin; import ghidra.app.plugin.core.codebrowser.CodeViewerProvider; import ghidra.framework.plugintool.util.PluginException; @@ -37,9 +35,7 @@ public class AssemblerPluginScreenShots extends GhidraScreenShotGenerator { positionCursor(0x0040512e); tool.addPlugin(AssemblerPlugin.class.getName()); - String fullActionName = "Assemble (AssemblerPlugin)"; - List actions = tool.getDockingActionsByFullActionName(fullActionName); - AssembleDockingAction action = (AssembleDockingAction) actions.get(0); + DockingActionIf action = getAction(tool, "AssemblerPlugin", "Assemble"); performAction(action, true); diff --git a/Ghidra/Test/IntegrationTest/src/screen/java/help/screenshot/DataTypeManagerPluginScreenShots.java b/Ghidra/Test/IntegrationTest/src/screen/java/help/screenshot/DataTypeManagerPluginScreenShots.java index 264e738402..08c4736744 100644 --- a/Ghidra/Test/IntegrationTest/src/screen/java/help/screenshot/DataTypeManagerPluginScreenShots.java +++ b/Ghidra/Test/IntegrationTest/src/screen/java/help/screenshot/DataTypeManagerPluginScreenShots.java @@ -156,10 +156,10 @@ public class DataTypeManagerPluginScreenShots extends GhidraScreenShotGenerator @Test public void testPreviewWindow() { - String fullActionName = "Show Preview Window (DataTypeManagerPlugin)"; - List action = tool.getDockingActionsByFullActionName(fullActionName); - performAction(action.get(0)); -// performAction("Show Preview Window", "DataTypeManagerPlugin", false); + + DockingActionIf action = getAction(tool, "DataTypeManagerPlugin", "Show Preview Window"); + performAction(action); + DataTypesProvider provider = getProvider(DataTypesProvider.class); GTree tree = (GTree) getInstanceField("archiveGTree", provider); GTreeRootNode rootNode = tree.getRootNode(); diff --git a/Ghidra/Test/IntegrationTest/src/screen/java/help/screenshot/ToolScreenShots.java b/Ghidra/Test/IntegrationTest/src/screen/java/help/screenshot/ToolScreenShots.java index df1b4dc1f3..e464465f77 100644 --- a/Ghidra/Test/IntegrationTest/src/screen/java/help/screenshot/ToolScreenShots.java +++ b/Ghidra/Test/IntegrationTest/src/screen/java/help/screenshot/ToolScreenShots.java @@ -283,10 +283,9 @@ public class ToolScreenShots extends GhidraScreenShotGenerator { DockingWindowManager windowManager = tool.getWindowManager(); DockingActionManager actionMgr = (DockingActionManager) getInstanceField("actionManager", windowManager); - String fullActionName = "Delete Function" + " (" + "FunctionPlugin" + ")"; - List 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); captureDialog(); diff --git a/Ghidra/Test/IntegrationTest/src/test.slow/java/ghidra/framework/main/SharedProjectUtil.java b/Ghidra/Test/IntegrationTest/src/test.slow/java/ghidra/framework/main/SharedProjectUtil.java index 4cb1b3a938..3e4ac23c54 100644 --- a/Ghidra/Test/IntegrationTest/src/test.slow/java/ghidra/framework/main/SharedProjectUtil.java +++ b/Ghidra/Test/IntegrationTest/src/test.slow/java/ghidra/framework/main/SharedProjectUtil.java @@ -18,14 +18,12 @@ */ package ghidra.framework.main; -import static org.junit.Assert.assertEquals; import static org.junit.Assert.fail; import java.io.File; import java.io.IOException; import java.net.InetAddress; import java.net.UnknownHostException; -import java.util.List; import javax.swing.*; @@ -239,10 +237,10 @@ public class SharedProjectUtil { } private static DockingActionIf getAction(FrontEndTool frontEndTool, String actionName) { - List actions = - frontEndTool.getDockingActionsByFullActionName(actionName + " (FrontEndPlugin)"); - assertEquals(1, actions.size()); - return actions.get(0); + + DockingActionIf action = + AbstractDockingTest.getAction(frontEndTool, "FrontEndPlugin", actionName); + return action; } private static class UtilProjectListener implements ProjectListener { diff --git a/Ghidra/Test/IntegrationTest/src/test.slow/java/ghidra/test/FrontEndTestEnv.java b/Ghidra/Test/IntegrationTest/src/test.slow/java/ghidra/test/FrontEndTestEnv.java index cdcc9c7638..8057736af8 100644 --- a/Ghidra/Test/IntegrationTest/src/test.slow/java/ghidra/test/FrontEndTestEnv.java +++ b/Ghidra/Test/IntegrationTest/src/test.slow/java/ghidra/test/FrontEndTestEnv.java @@ -23,8 +23,6 @@ import java.util.*; import javax.swing.*; import javax.swing.tree.TreePath; -import org.junit.Assert; - import docking.*; import docking.action.DockingActionIf; import docking.test.AbstractDockingTest; @@ -341,15 +339,10 @@ public class FrontEndTestEnv { return new ArrayList<>(Arrays.asList(tools)); } - public List getFrontEndActions() { - return frontEndTool.getDockingActionsByOwnerName("FrontEndPlugin"); - } - public DockingActionIf getAction(String actionName) { - List a = - frontEndTool.getDockingActionsByFullActionName(actionName + " (FrontEndPlugin)"); - Assert.assertEquals(1, a.size()); - return a.get(0); + DockingActionIf action = + AbstractDockingTest.getAction(frontEndTool, "FrontEndPlugin", actionName); + return action; } public void performFrontEndAction(DockingActionIf action) {