mirror of
https://github.com/NationalSecurityAgency/ghidra
synced 2024-08-27 21:10:26 +00:00
GT-2869 - Key Bindings - refactor of methods to provide all actions
This commit is contained in:
parent
c1de98304a
commit
43fa7e3f92
|
@ -20,6 +20,7 @@ import java.io.*;
|
|||
import java.util.*;
|
||||
|
||||
import 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<Plugin> 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<DockingActionIf> getActions(PluginTool tool, Plugin plugin) {
|
||||
List<DockingActionIf> actions = tool.getDockingActionsByOwnerName(plugin.getName());
|
||||
Set<DockingActionIf> actions = KeyBindingUtils.getKeyBindingActions(tool, plugin.getName());
|
||||
List<DockingActionIf> list = new ArrayList<>(actions);
|
||||
Comparator<DockingActionIf> comparator = (action1, action2) -> {
|
||||
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<Plugin> getSortedPlugins(PluginTool tool) {
|
||||
List<Plugin> list = tool.getManagedPlugins();
|
||||
Plugin[] plugins = new Plugin[list.size()];
|
||||
list.toArray(plugins);
|
||||
Comparator<Plugin> 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;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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<DockingActionIf> actions = tool.getDockingActionsByOwnerName(plugin.getName());
|
||||
Set<DockingActionIf> actions = tool.getDockingActionsByOwnerName(plugin.getName());
|
||||
for (DockingActionIf action : actions) {
|
||||
if (!(action instanceof CompositeEditorTableAction)) {
|
||||
continue;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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";
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
||||
/**
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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";
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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<DockingActionIf> 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) {
|
||||
|
|
|
@ -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<DockingActionIf> 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);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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<DockingActionIf> actions;
|
||||
private Set<DockingActionIf> 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();
|
||||
|
|
|
@ -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<DockingActionIf> 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) {
|
||||
|
|
|
@ -165,7 +165,7 @@ public abstract class AbstractDataActionTest extends AbstractGhidraHeadedIntegra
|
|||
builtInDataTypesManager.setFavorite(root.getDataType("word"), true);
|
||||
}
|
||||
|
||||
protected void checkActions(List<DockingActionIf> actions, boolean enabled, String caseStr) {
|
||||
protected void checkActions(Set<DockingActionIf> actions, boolean enabled, String caseStr) {
|
||||
checkAction(actions, CREATE_STRUCTURE, enabled, caseStr);
|
||||
checkAction(actions, 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<DockingActionIf> actions = tool.getDockingActionsByOwnerName(plugin.getName());
|
||||
Set<DockingActionIf> 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<DockingActionIf> actions) {
|
||||
protected void checkOnUndefined(Set<DockingActionIf> 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<DockingActionIf> actions, Class<?> expectedDataType) {
|
||||
protected void checkOnDefined(Set<DockingActionIf> 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<DockingActionIf> actions, DataType interiorDt, int arraySize) {
|
||||
protected void checkOnArray(Set<DockingActionIf> 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<DockingActionIf> actions, int structSize) {
|
||||
protected void checkOnStructure(Set<DockingActionIf> 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<DockingActionIf> actions = tool.getDockingActionsByOwnerName(plugin.getName());
|
||||
Set<DockingActionIf> 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<DockingActionIf> actions, String name, boolean isEnabled,
|
||||
protected void checkAction(Set<DockingActionIf> actions, String name, boolean isEnabled,
|
||||
String caseName) {
|
||||
for (DockingActionIf element : actions) {
|
||||
String actionName = element.getName();
|
||||
|
|
|
@ -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<DockingActionIf> actions;
|
||||
Set<DockingActionIf> 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<DockingActionIf> actions = tool.getDockingActionsByOwnerName(plugin.getName());
|
||||
Set<DockingActionIf> 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<DockingActionIf> actions = tool.getDockingActionsByOwnerName(plugin.getName());
|
||||
Set<DockingActionIf> 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<DockingActionIf> actions = tool.getDockingActionsByOwnerName(plugin.getName());
|
||||
Set<DockingActionIf> 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<DockingActionIf> actions = tool.getDockingActionsByOwnerName(plugin.getName());
|
||||
Set<DockingActionIf> 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<DockingActionIf> actions = tool.getDockingActionsByOwnerName(plugin.getName());
|
||||
Set<DockingActionIf> 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<DockingActionIf> actions = tool.getDockingActionsByOwnerName(plugin.getName());
|
||||
Set<DockingActionIf> 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<DockingActionIf> actions = tool.getDockingActionsByOwnerName(plugin.getName());
|
||||
Set<DockingActionIf> 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<DockingActionIf> actions = tool.getDockingActionsByOwnerName(plugin.getName());
|
||||
Set<DockingActionIf> 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<DockingActionIf> actions = tool.getDockingActionsByOwnerName(plugin.getName());
|
||||
Set<DockingActionIf> 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<DockingActionIf> actions = tool.getDockingActionsByOwnerName(plugin.getName());
|
||||
Set<DockingActionIf> 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<DockingActionIf> actions = tool.getDockingActionsByOwnerName(plugin.getName());
|
||||
Set<DockingActionIf> 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<DockingActionIf> 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<DockingActionIf> actions = tool.getDockingActionsByOwnerName(plugin.getName());
|
||||
Set<DockingActionIf> actions = getActionsByOwner(tool, plugin.getName());
|
||||
checkOnStructure(actions, 0x20);
|
||||
|
||||
gotoLocation(0x01006c00);
|
||||
|
@ -708,14 +705,14 @@ public class DataAction4Test extends AbstractDataActionTest {
|
|||
|
||||
doAction(DEFINE_BYTE, true);
|
||||
|
||||
List<DockingActionIf> actions = tool.getDockingActionsByOwnerName(plugin.getName());
|
||||
Set<DockingActionIf> 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<DockingActionIf> actions = tool.getDockingActionsByOwnerName(plugin.getName());
|
||||
Set<DockingActionIf> 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();
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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<DockingActionIf> actions = tool.getDockingActionsByOwnerName("EquatePlugin");
|
||||
Set<DockingActionIf> 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<DockingActionIf> actions = tool.getDockingActionsByOwnerName("EquatePlugin");
|
||||
Set<DockingActionIf> 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<DockingActionIf> actions = tool.getDockingActionsByOwnerName("EquatePlugin");
|
||||
Set<DockingActionIf> 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<DockingActionIf> actions = tool.getDockingActionsByOwnerName("EquatePlugin");
|
||||
Set<DockingActionIf> actions = getActionsByOwner(tool, "EquatePlugin");
|
||||
for (DockingActionIf action : actions) {
|
||||
String name = action.getName();
|
||||
if (name.startsWith("Convert") && name.indexOf("Signed") < 0) {
|
||||
|
|
|
@ -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<DockingActionIf> actions = tool.getDockingActionsByOwnerName("EquatePlugin");
|
||||
Set<DockingActionIf> 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<DockingActionIf> actions = tool.getDockingActionsByOwnerName("EquatePlugin");
|
||||
Set<DockingActionIf> 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<DockingActionIf> actions = tool.getDockingActionsByOwnerName("EquatePlugin");
|
||||
Set<DockingActionIf> actions = getActionsByOwner(tool, "EquatePlugin");
|
||||
for (DockingActionIf action : actions) {
|
||||
String name = action.getName();
|
||||
if (!name.startsWith("Convert") || !action.isAddToPopup(getListingContext())) {
|
||||
|
|
|
@ -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<DockingActionIf> actions = tool.getDockingActionsByOwnerName(plugin.getName());
|
||||
Set<DockingActionIf> 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<DockingActionIf> actions = tool.getDockingActionsByOwnerName(plugin.getName());
|
||||
Set<DockingActionIf> 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<DockingActionIf> actions = tool.getDockingActionsByOwnerName(plugin.getName());
|
||||
Set<DockingActionIf> 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<DockingActionIf> actions, String name, boolean isValidContext,
|
||||
private void checkAction(Set<DockingActionIf> actions, String name, boolean isValidContext,
|
||||
String caseName) {
|
||||
for (DockingActionIf action : actions) {
|
||||
String actionName = action.getName();
|
||||
|
|
|
@ -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<DockingActionIf> actions = tool.getDockingActionsByOwnerName(plugin.getName());
|
||||
Set<DockingActionIf> 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<DockingActionIf> actions = tool.getDockingActionsByOwnerName(plugin.getName());
|
||||
Set<DockingActionIf> actions = getActionsByOwner(tool, plugin.getName());
|
||||
for (DockingActionIf action : actions) {
|
||||
if (!action.getName().equals("View Memory Map")) {
|
||||
assertTrue(!action.isEnabledForContext(provider.getActionContext(null)));
|
||||
|
|
|
@ -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<DockingActionIf> actions = tool.getDockingActionsByOwnerName(plugin.getName());
|
||||
Set<DockingActionIf> 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<DockingActionIf> actions = tool.getDockingActionsByOwnerName(plugin.getName());
|
||||
Set<DockingActionIf> actions = getActionsByOwner(tool, plugin.getName());
|
||||
for (DockingActionIf action : actions) {
|
||||
String name = action.getName();
|
||||
if (name.equals("Add Block") || name.equals("Merge Blocks") ||
|
||||
|
|
|
@ -18,8 +18,7 @@ package ghidra.app.plugin.core.module;
|
|||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.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<DockingActionIf> actions;
|
||||
private Set<DockingActionIf> 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);
|
||||
|
|
|
@ -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<DockingActionIf> actions = tool.getDockingActionsByOwnerName(plugin.getName());
|
||||
Set<DockingActionIf> 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) {
|
||||
|
|
|
@ -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<DockingActionIf> actions =
|
||||
getActionsByOwnerAndName(plugin.getTool(), plugin.getName(), "Rerun Last Script");
|
||||
assertFalse(actions.isEmpty());
|
||||
DockingActionIf runLastAction = CollectionUtils.any(actions);
|
||||
return runLastAction;
|
||||
}
|
||||
|
||||
protected void assertRunLastActionEnabled(boolean enabled) {
|
||||
|
||||
DockingActionIf runLastAction = getRunLastScriptAction();
|
||||
final AtomicReference<Boolean> ref = new AtomicReference<>();
|
||||
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<DockingActionIf> actions = tool.getDockingActionsByOwnerName(actionOwner);
|
||||
Set<DockingActionIf> actions = getActionsByOwner(tool, actionOwner);
|
||||
for (DockingActionIf action : actions) {
|
||||
KeyStroke keyBinding = action.getKeyBinding();
|
||||
if (keyBinding == null) {
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -1306,11 +1306,8 @@ public class SymbolTablePluginTest extends AbstractGhidraHeadedIntegrationTest {
|
|||
|
||||
private void setupSymbolTableFilterToShowParameters() throws Exception {
|
||||
// get the filter action - "Set Filter"
|
||||
List<DockingActionIf> 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);
|
||||
|
|
|
@ -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<DockingActionIf> 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) {
|
||||
|
|
|
@ -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<DockingActionIf> 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 {
|
||||
|
|
|
@ -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<String, KeyStroke> 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<DockingActionIf> list = tool.getAllActions();
|
||||
DockingActionIf action = null;
|
||||
for (int i = 0; i < list.size(); i++) {
|
||||
action = list.get(i);
|
||||
Set<DockingActionIf> 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<String, KeyStroke> panelKeyStrokeMap) {
|
||||
List<String> 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;
|
||||
|
|
|
@ -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<DockingActionIf> list = tool.getAllActions();
|
||||
for (int i = 0; i < list.size(); i++) {
|
||||
DockingActionIf action = list.get(i);
|
||||
Set<DockingActionIf> 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<DockingActionIf> list = tool.getAllActions();
|
||||
DockingActionIf action = null;
|
||||
for (int i = 0; i < list.size(); i++) {
|
||||
action = list.get(i);
|
||||
Set<DockingActionIf> 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<DockingActionIf> list = tool.getAllActions();
|
||||
DockingActionIf action = null;
|
||||
for (int i = 0; i < list.size(); i++) {
|
||||
action = list.get(i);
|
||||
Set<DockingActionIf> 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<DockingActionIf> list = tool.getAllActions();
|
||||
DockingActionIf action = null;
|
||||
for (int i = 0; i < list.size(); i++) {
|
||||
action = list.get(i);
|
||||
Set<DockingActionIf> list = tool.getAllActions();
|
||||
for (DockingActionIf action : list) {
|
||||
if (!action.isKeyBindingManaged()) {
|
||||
continue;
|
||||
}
|
||||
|
|
|
@ -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<DockingActionIf> 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<DockingActionIf> actions =
|
||||
tool.getDockingActionsByFullActionName("Configure Tool (Project Window)");
|
||||
assertEquals(1, actions.size());
|
||||
|
||||
performAction(actions.get(0), true);
|
||||
DockingActionIf action = getAction(tool, "Project Window", "Configure Tool");
|
||||
performAction(action, true);
|
||||
waitForPostedSwingRunnables();
|
||||
SwingUtilities.invokeAndWait(() -> tool.showConfig(false, false));
|
||||
runSwing(() -> tool.showConfig(false, false));
|
||||
|
||||
provider = tool.getManagePluginsDialog();
|
||||
pluginManagerComponent = (PluginManagerComponent) getInstanceField("comp", provider);
|
||||
|
|
|
@ -254,11 +254,9 @@ public class ManagePluginsTest extends AbstractGhidraHeadedIntegrationTest {
|
|||
}
|
||||
|
||||
private void showProvider() {
|
||||
List<DockingActionIf> actions =
|
||||
tool.getDockingActionsByFullActionName("Configure Tool (Tool)");
|
||||
assertEquals(1, actions.size());
|
||||
|
||||
performAction(actions.get(0), true);
|
||||
DockingActionIf action = getAction(tool, "Tool", "Configure Tool");
|
||||
performAction(action, true);
|
||||
waitForSwing();
|
||||
provider = tool.getManagePluginsDialog();
|
||||
pluginManagerComponent = (PluginManagerComponent) getInstanceField("comp", provider);
|
||||
|
|
|
@ -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<DockingActionIf> actionList =
|
||||
tool.getDockingActionsByFullActionName("Close File (ProgramManagerPlugin)");
|
||||
assertTrue(!actionList.isEmpty());
|
||||
|
||||
performAction(actionList.get(0), new ProgramActionContext(null, program), false);
|
||||
DockingActionIf action = getAction(tool, "ProgramManagerPlugin", "Close File");
|
||||
performAction(action, new ProgramActionContext(null, program), false);
|
||||
|
||||
waitForPostedSwingRunnables();
|
||||
}
|
||||
|
|
|
@ -201,10 +201,9 @@ public class DateEditorTest extends AbstractGhidraHeadedIntegrationTest {
|
|||
}
|
||||
|
||||
private void showProgramOptions() {
|
||||
List<DockingActionIf> list = tool.getAllActions();
|
||||
for (int i = 0; i < list.size(); i++) {
|
||||
|
||||
DockingActionIf action = list.get(i);
|
||||
// TODO change to getAction("Program Options")
|
||||
Set<DockingActionIf> list = tool.getAllActions();
|
||||
for (DockingActionIf action : list) {
|
||||
if (action.getName().equals("Program Options")) {
|
||||
performAction(action, plugin.getProvider(), false);
|
||||
break;
|
||||
|
|
|
@ -988,10 +988,9 @@ public class OptionsDialogTest extends AbstractGhidraHeadedIntegrationTest {
|
|||
}
|
||||
|
||||
private void showOptionsDialog(PluginTool pluginTool) throws Exception {
|
||||
List<DockingActionIf> list = pluginTool.getAllActions();
|
||||
for (int i = 0; i < list.size(); i++) {
|
||||
|
||||
DockingActionIf action = list.get(i);
|
||||
// TODO change to getAction("Edit Options")
|
||||
Set<DockingActionIf> list = pluginTool.getAllActions();
|
||||
for (DockingActionIf action : list) {
|
||||
if (action.getName().equals("Edit Options")) {
|
||||
performAction(action, false);
|
||||
break;
|
||||
|
|
|
@ -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<DockingActionIf> getAllActions() {
|
||||
return Collections.emptyList();
|
||||
public Set<DockingActionIf> getAllActions() {
|
||||
return Collections.emptySet();
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<DockingActionIf> getDockingActionsByOwnerName(String owner) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<DockingActionIf> getDockingActionsByFullActionName(String fullActionName) {
|
||||
return Collections.emptyList();
|
||||
public Set<DockingActionIf> getDockingActionsByOwnerName(String owner) {
|
||||
return Collections.emptySet();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -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<DockingActionIf> 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();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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<T extends DualDecompilerFiel
|
|||
|
||||
String leftTitle1 = FunctionUtility.getFunctionTitle(functions[LEFT]);
|
||||
String rightTitle1 = FunctionUtility.getFunctionTitle(functions[RIGHT]);
|
||||
titlePanels[LEFT] = new TitledPanel(leftTitle1, cPanels[LEFT], 5);
|
||||
titlePanels[RIGHT] = new TitledPanel(rightTitle1, cPanels[RIGHT], 5);
|
||||
|
||||
// use mutable labels, as the titles update when functions are selected
|
||||
GDHtmlLabel leftTitleLabel = new GDHtmlLabel(leftTitle1);
|
||||
GDHtmlLabel rightTitleLabel = new GDHtmlLabel(rightTitle1);
|
||||
|
||||
titlePanels[LEFT] = new TitledPanel(leftTitleLabel, cPanels[LEFT], 5);
|
||||
titlePanels[RIGHT] = new TitledPanel(rightTitleLabel, cPanels[RIGHT], 5);
|
||||
|
||||
// Set the MINIMUM_PANEL_WIDTH for the left and right panel to prevent the split pane's
|
||||
// divider from becoming locked (can't be moved) due to extra long title names.
|
||||
|
|
|
@ -35,6 +35,7 @@ import docking.*;
|
|||
import docking.action.*;
|
||||
import docking.menu.ActionState;
|
||||
import docking.menu.MultiStateDockingAction;
|
||||
import docking.test.AbstractDockingTest;
|
||||
import docking.widgets.EventTrigger;
|
||||
import docking.widgets.OptionDialog;
|
||||
import docking.widgets.dialogs.MultiLineInputDialog;
|
||||
|
@ -470,13 +471,11 @@ public abstract class AbstractFunctionGraphTest extends AbstractGhidraHeadedInte
|
|||
protected void performReload() throws Exception {
|
||||
|
||||
String name = "Reset Graph";
|
||||
List<DockingActionIf> actions =
|
||||
tool.getDockingActionsByFullActionName(name + " (FunctionGraphPlugin)");
|
||||
assertEquals("Could not find action: " + name, 1, actions.size());
|
||||
|
||||
DockingActionIf action = getAction(tool, graphPlugin.getName(), name);
|
||||
long start = System.currentTimeMillis();
|
||||
|
||||
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<DockingActionIf> actions =
|
||||
tool.getDockingActionsByFullActionName(name + " (FunctionGraphPlugin)");
|
||||
assertEquals("Could not find action: " + name, 1, actions.size());
|
||||
ToggleDockingAction dockAction = (ToggleDockingAction) actions.get(0);
|
||||
DockingActionIf action = getAction(tool, "FunctionGraphPlugin", name);
|
||||
ToggleDockingAction dockAction = (ToggleDockingAction) action;
|
||||
performAction(dockAction, true);
|
||||
}
|
||||
|
||||
protected void undockSatellite() {
|
||||
String name = "Dock Satellite View";
|
||||
List<DockingActionIf> actions =
|
||||
tool.getDockingActionsByFullActionName(name + " (FunctionGraphPlugin)");
|
||||
assertEquals("Could not find action: " + name, 1, actions.size());
|
||||
|
||||
ToggleDockingAction dockAction = (ToggleDockingAction) actions.get(0);
|
||||
DockingActionIf action = getAction(tool, "FunctionGraphPlugin", name);
|
||||
ToggleDockingAction dockAction = (ToggleDockingAction) action;
|
||||
assertTrue(name + " action is not selected as expected", dockAction.isSelected());
|
||||
|
||||
performAction(dockAction, true);
|
||||
|
@ -938,11 +933,9 @@ public abstract class AbstractFunctionGraphTest extends AbstractGhidraHeadedInte
|
|||
|
||||
protected void redockSatellite() {
|
||||
String name = "Dock Satellite View";
|
||||
List<DockingActionIf> actions =
|
||||
tool.getDockingActionsByFullActionName(name + " (FunctionGraphPlugin)");
|
||||
assertEquals("Could not find action: " + name, 1, actions.size());
|
||||
|
||||
ToggleDockingAction dockAction = (ToggleDockingAction) actions.get(0);
|
||||
DockingActionIf action = getAction(tool, "FunctionGraphPlugin", name);
|
||||
ToggleDockingAction dockAction = (ToggleDockingAction) action;
|
||||
assertFalse(name + " action is not selected as expected", dockAction.isSelected());
|
||||
|
||||
performAction(dockAction, true);
|
||||
|
@ -1210,10 +1203,8 @@ public abstract class AbstractFunctionGraphTest extends AbstractGhidraHeadedInte
|
|||
|
||||
protected FGController cloneGraph() {
|
||||
|
||||
List<DockingActionIf> 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<FGVertex> 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<FGVertex> 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<FGVertex> 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<FGVertex> 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<FGVertex> 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<FGVertex, FGEdge> 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<DockingActionIf> 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<FGVertex> selectVertices(FunctionGraph functionGraph, FGVertex... vertices) {
|
||||
|
||||
|
||||
Set<FGVertex> set = new HashSet<>();
|
||||
for (FGVertex vertex : vertices) {
|
||||
set.add(vertex);
|
||||
}
|
||||
|
||||
|
||||
pickVertices(set);
|
||||
|
||||
|
||||
waitForSwing();
|
||||
return set;
|
||||
}
|
||||
|
||||
protected Set<FGVertex> selectVertices(FunctionGraph functionGraph, String... addressString) {
|
||||
|
||||
|
||||
Set<FGVertex> 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<DockingActionIf> 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<FGVertex> 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<FGVertex, FGEdge> graph = functionGraph;
|
||||
Collection<FGEdge> 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<FGVertex, FGEdge> 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<DockingActionIf> 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<DockingActionIf> 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
|
||||
|
|
|
@ -177,10 +177,8 @@ public class FunctionGraphPlugin2Test extends AbstractFunctionGraphTest {
|
|||
GraphPerspectiveInfo<FGVertex, FGEdge> primaryPerspective =
|
||||
primaryController.getGraphPerspective(location);
|
||||
|
||||
List<DockingActionIf> 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());
|
||||
|
|
|
@ -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<DockingActionIf> actions = tool.getDockingActionsByOwnerName("Tool");
|
||||
Set<DockingActionIf> actions = getActionsByOwner(tool, "Tool");
|
||||
for (DockingActionIf action : actions) {
|
||||
if (name.equals(action.getName())) {
|
||||
return action;
|
||||
|
|
|
@ -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<DockingActionIf> actions = tool.getDockingActionsByOwnerName("Tool");
|
||||
for (DockingActionIf action : actions) {
|
||||
if (action.getName().equals(actionName)) {
|
||||
return action;
|
||||
}
|
||||
}
|
||||
throw new IllegalArgumentException("Unable to find Tool action '" + actionName + "'");
|
||||
}
|
||||
|
||||
private void initializeOptions() {
|
||||
Options options = tool.getOptions(GhidraOptions.CATEGORY_BROWSER_DISPLAY);
|
||||
options.registerOptionsEditor(new ListingDisplayOptionsEditor(this, options));
|
||||
|
|
|
@ -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<DockingActionIf> actions = tool.getDockingActionsByOwnerName("Tool");
|
||||
for (DockingActionIf action : actions) {
|
||||
if (action.getName().equals(actionName)) {
|
||||
return action;
|
||||
}
|
||||
}
|
||||
throw new IllegalArgumentException("Unable to find Tool action '" + actionName + "'");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void optionsChanged(ToolOptions options, String optionName, Object oldValue,
|
||||
Object newValue) {
|
||||
|
|
|
@ -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<DockingActionIf> getAllActions() {
|
||||
return actionMgr.getAllActions();
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<DockingActionIf> getDockingActionsByOwnerName(String owner) {
|
||||
List<DockingActionIf> actions = actionMgr.getActions(owner);
|
||||
public Set<DockingActionIf> getAllActions() {
|
||||
Set<DockingActionIf> actions = actionMgr.getAllActions();
|
||||
DockingActionManager am = winMgr.getActionManager();
|
||||
actions.addAll(am.getAllActions());
|
||||
return actions;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<DockingActionIf> getDockingActionsByFullActionName(String fullActionName) {
|
||||
Set<DockingActionIf> set = new HashSet<>();
|
||||
set.addAll(actionMgr.getDockingActionsByFullActionName(fullActionName));
|
||||
set.addAll(winMgr.getActions(fullActionName));
|
||||
return new ArrayList<>(set);
|
||||
public Set<DockingActionIf> getDockingActionsByOwnerName(String owner) {
|
||||
return actionMgr.getActions(owner);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -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.*;
|
||||
|
|
|
@ -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<DockingActionIf> getAllDockingActionsByFullActionName(String fullActionName) {
|
||||
public Set<DockingActionIf> 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<DockingActionIf> actions = new ArrayList<>();
|
||||
Set<DockingActionIf> actions = new HashSet<>();
|
||||
SystemUtilities.runSwingNow(() -> {
|
||||
actions.addAll(getGlobalDockingActionsByFullActionName(fullActionName));
|
||||
actions.addAll(getLocalDockingActionsByFullActionName(fullActionName));
|
||||
actions.addAll(globalActions);
|
||||
actions.addAll(keyBindingsManager.getLocalActions());
|
||||
});
|
||||
return actions;
|
||||
}
|
||||
|
||||
private List<DockingActionIf> getGlobalDockingActionsByFullActionName(String fullActionName) {
|
||||
List<DockingActionIf> matchingActions = new ArrayList<>();
|
||||
ArrayList<DockingActionIf> existingAction = new ArrayList<>(globalActions);
|
||||
for (DockingActionIf action : existingAction) {
|
||||
if (fullActionName.equals(action.getFullName())) {
|
||||
matchingActions.add(action);
|
||||
}
|
||||
}
|
||||
return matchingActions;
|
||||
}
|
||||
|
||||
private List<DockingActionIf> getLocalDockingActionsByFullActionName(String fullActionName) {
|
||||
List<DockingActionIf> matchingActions = new ArrayList<>();
|
||||
ArrayList<DockingActionIf> existingAction =
|
||||
new ArrayList<>(keyBindingsManager.getLocalActions());
|
||||
for (DockingActionIf action : existingAction) {
|
||||
if (fullActionName.equals(action.getFullName())) {
|
||||
matchingActions.add(action);
|
||||
}
|
||||
}
|
||||
return matchingActions;
|
||||
}
|
||||
|
||||
public Action getDockingKeyAction(KeyStroke keyStroke) {
|
||||
return keyBindingsManager.getDockingKeyAction(keyStroke);
|
||||
}
|
||||
|
|
|
@ -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.
|
||||
*
|
||||
* <p>Note: the result may contain conceptually duplicate actions, which is when multiple
|
||||
* actions exist that share the same full name (the full name is the action name with the
|
||||
* owner name, such as "My Action (MyPlugin)".
|
||||
*
|
||||
* @return set of all actions
|
||||
*/
|
||||
public List<DockingActionIf> getAllActions();
|
||||
public Set<DockingActionIf> getAllActions();
|
||||
|
||||
/**
|
||||
* Returns all actions for the given owner
|
||||
*
|
||||
* <p>Note: the result may contain conceptually duplicate actions, which is when multiple
|
||||
* actions exist that share the same full name (the full name is the action name with the
|
||||
* owner name, such as "My Action (MyPlugin)".
|
||||
*
|
||||
* @param owner the action owner's name
|
||||
* @return the actions
|
||||
*/
|
||||
public List<DockingActionIf> getDockingActionsByOwnerName(String owner);
|
||||
|
||||
/**
|
||||
* Return an list of actions with the given full name
|
||||
* @param fullActionName action name that includes the owner's name in
|
||||
* parentheses, e.g. "MyAction (MyPlugin)"
|
||||
* @return the actions
|
||||
*/
|
||||
public List<DockingActionIf> getDockingActionsByFullActionName(String fullActionName);
|
||||
public Set<DockingActionIf> getDockingActionsByOwnerName(String owner);
|
||||
|
||||
/**
|
||||
* Shows or hides the component provider in the tool
|
||||
|
|
|
@ -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<DockingActionIf> getActions(String fullActionName) {
|
||||
return actionManager.getAllDockingActionsByFullActionName(fullActionName);
|
||||
/**
|
||||
* Returns all actions registered with this manager
|
||||
* @return the actions
|
||||
*/
|
||||
public Set<DockingActionIf> getAllActions() {
|
||||
return actionManager.getAllActions();
|
||||
}
|
||||
|
||||
//==================================================================================================
|
||||
// End Package-level Methods
|
||||
//==================================================================================================
|
||||
|
||||
/**
|
||||
* Hides or shows the component associated with the given provider.
|
||||
* <p><br>
|
||||
|
|
|
@ -0,0 +1,72 @@
|
|||
/* ###
|
||||
* IP: GHIDRA
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package docking;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
import docking.action.DockingActionIf;
|
||||
|
||||
/**
|
||||
* A class that exists primarily to provide access to action-related package-level methods of the
|
||||
* {@link DockingWindowManager}. This allows the manager's interface to hide methods that
|
||||
* don't make sense for public consumption.
|
||||
*/
|
||||
public class DockingWindowManagerActionUpdater {
|
||||
|
||||
private DockingWindowManager windowManager;
|
||||
|
||||
public DockingWindowManagerActionUpdater(DockingWindowManager windowManager) {
|
||||
this.windowManager = windowManager;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds an action to the global menu or toolbar which appear in the main frame. If the action
|
||||
* has a menu path, it will be in the menu. If it has an icon, it will appear in the toolbar.
|
||||
* @param action the action to be added
|
||||
*/
|
||||
public void addToolAction(DockingActionIf action) {
|
||||
windowManager.addToolAction(action);
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes the given action from the global menu and toolbar
|
||||
* @param action the action to be removed
|
||||
*/
|
||||
public void removeToolAction(DockingActionIf action) {
|
||||
windowManager.removeToolAction(action);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns all actions registered with this manager
|
||||
* @return the actions
|
||||
*/
|
||||
public Set<DockingActionIf> getAllActions() {
|
||||
return windowManager.getAllActions();
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds an action that will be associated with the given provider. These actions will
|
||||
* appear in the local header for the component as a toolbar button or a drop-down menu
|
||||
* item if it has an icon and menu path respectively.
|
||||
*
|
||||
* @param provider the provider whose header on which the action is to be placed
|
||||
* @param action the action to add to the providers header bar
|
||||
*/
|
||||
public void addLocalAction(ComponentProvider provider, DockingActionIf action) {
|
||||
windowManager.addLocalAction(provider, action);
|
||||
}
|
||||
|
||||
}
|
|
@ -25,7 +25,7 @@ import java.awt.event.KeyListener;
|
|||
import javax.swing.*;
|
||||
import javax.swing.text.JTextComponent;
|
||||
|
||||
import docking.util.KeyBindingUtils;
|
||||
import docking.actions.KeyBindingUtils;
|
||||
import ghidra.util.bean.GGlassPane;
|
||||
import ghidra.util.exception.AssertException;
|
||||
|
||||
|
|
|
@ -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<DockingActionIf> 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<DockingActionIf> allActions = dockingActionManager.getAllActions();
|
||||
DockingActionIf sharedAction =
|
||||
KeyBindingUtils.getSharedKeyBindingAction(allActions, actionName);
|
||||
if (sharedAction != null) {
|
||||
return sharedAction;
|
||||
}
|
||||
|
||||
return dockingAction;
|
||||
|
|
|
@ -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<DockingActionIf> actions =
|
||||
actionManager.getAllDockingActionsByFullActionName(action.getFullName());
|
||||
Set<DockingActionIf> allActions = actionManager.getAllActions();
|
||||
Set<DockingActionIf> 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<String, DockingActionIf> 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();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
|
@ -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<String, List<DockingActionIf>> actionMap = new HashMap<>();
|
||||
private DockingWindowManagerActionUpdater winMgrActionUpdater;
|
||||
|
||||
private Map<String, List<DockingActionIf>> actionMap =
|
||||
LazyMap.lazyMap(new HashMap<>(), () -> new ArrayList<>());
|
||||
private Map<String, SharedStubKeyBindingAction> sharedActionMap = new HashMap<>();
|
||||
private 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<DockingActionIf> actionList = actionMap.get(name);
|
||||
if (actionList == null) {
|
||||
List<DockingActionIf> newList = new ArrayList<>();
|
||||
newList.add(action);
|
||||
actionMap.put(name, newList);
|
||||
}
|
||||
else {
|
||||
actionList.add(action);
|
||||
|
||||
List<DockingActionIf> list = actionMap.get(name);
|
||||
if (!list.isEmpty()) {
|
||||
KeyBindingUtils.assertSameDefaultKeyBindings(action, actionList);
|
||||
}
|
||||
|
||||
actionList.add(action);
|
||||
}
|
||||
|
||||
private void removeActionFromMap(DockingActionIf action) {
|
||||
String name = action.getFullName();
|
||||
List<DockingActionIf> 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<DockingActionIf> actions = getActions(owner);
|
||||
Predicate<String> ownerMatches = actionOwner -> actionOwner.equals(owner);
|
||||
Set<DockingActionIf> 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<DockingActionIf> 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<DockingActionIf> getDockingActionsByFullActionName(String fullName) {
|
||||
public Set<DockingActionIf> getDockingActionsByFullActionName(String fullName) {
|
||||
List<DockingActionIf> 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.
|
||||
* <p>
|
||||
* This method will only return a single instance of any named action, even if multiple
|
||||
* actions have been registered with the same name.
|
||||
* <p>
|
||||
* 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<DockingActionIf> getUniqueActionList(String owner) {
|
||||
private Set<DockingActionIf> getActions(Predicate<String> ownerFilter) {
|
||||
|
||||
List<DockingActionIf> matchingActionList = new ArrayList<>();
|
||||
for (List<DockingActionIf> 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<DockingActionIf> result = new HashSet<>();
|
||||
for (List<DockingActionIf> 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<DockingActionIf> getActions(String owner) {
|
||||
List<DockingActionIf> list = getUniqueActionList(owner);
|
||||
return list;
|
||||
public synchronized Set<DockingActionIf> getActions(String owner) {
|
||||
Predicate<String> 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<DockingActionIf> getAllActions() {
|
||||
return getUniqueActionList(null);
|
||||
public synchronized Set<DockingActionIf> getAllActions() {
|
||||
Predicate<String> 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<DockingActionIf> actions = getAllActions();
|
||||
Set<DockingActionIf> 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<DockingActionIf> actionList = actionMap.get(name);
|
||||
if (actionList != null && actionList.remove(action) && actionList.isEmpty()) {
|
||||
actionMap.remove(name);
|
||||
}
|
||||
actionMap.get(name).remove(action);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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<String, DockingActionIf> getAllKeyBindingActions(DockingTool tool) {
|
||||
|
||||
Map<String, DockingActionIf> deduper = new HashMap<>();
|
||||
Set<DockingActionIf> actions = tool.getAllActions();
|
||||
for (DockingActionIf action : actions) {
|
||||
if (isIgnored(action)) {
|
||||
// don't bother tracking non-keybinding actions; this would be a mistake due
|
||||
// to the potential for a shared key binding action overwriting its
|
||||
// SharedStubKeyBindingAction
|
||||
continue;
|
||||
}
|
||||
|
||||
deduper.put(action.getFullName(), action);
|
||||
}
|
||||
|
||||
return deduper;
|
||||
}
|
||||
|
||||
/**
|
||||
* A utility method to get all key binding actions that have the given owner.
|
||||
* This method will remove duplicate actions and will only return actions
|
||||
* that are {@link DockingActionIf#isKeyBindingManaged()}
|
||||
*
|
||||
* @param tool the tool containing the actions
|
||||
* @param owner the action owner name
|
||||
* @return the actions
|
||||
*/
|
||||
public static Set<DockingActionIf> getKeyBindingActions(DockingTool tool, String owner) {
|
||||
|
||||
Map<String, DockingActionIf> deduper = new HashMap<>();
|
||||
Set<DockingActionIf> actions = tool.getDockingActionsByOwnerName(owner);
|
||||
for (DockingActionIf action : actions) {
|
||||
if (isIgnored(action)) {
|
||||
// don't bother tracking non-keybinding actions; this would be a mistake due
|
||||
// to the potential for a shared key binding action overwriting its
|
||||
// SharedStubKeyBindingAction
|
||||
continue;
|
||||
}
|
||||
|
||||
deduper.put(action.getFullName(), action);
|
||||
}
|
||||
|
||||
return CollectionUtils.asSet(deduper.values());
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns all actions that match the given owner and name
|
||||
*
|
||||
* @param tool the tool containing the actions
|
||||
* @param owner the owner
|
||||
* @param name the name
|
||||
* @return the actions
|
||||
*/
|
||||
public static Set<DockingActionIf> getActions(DockingTool tool, String owner, String name) {
|
||||
Set<DockingActionIf> actions = tool.getDockingActionsByOwnerName(owner);
|
||||
return getActions(actions, owner, name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns all actions that match the given owner and name
|
||||
*
|
||||
* @param allActions the universe of actions
|
||||
* @param owner the owner
|
||||
* @param name the name
|
||||
* @return the actions
|
||||
*/
|
||||
public static Set<DockingActionIf> getActions(Set<DockingActionIf> allActions, String owner,
|
||||
String name) {
|
||||
|
||||
Set<DockingActionIf> ownerMatch =
|
||||
Sets.filter(allActions, action -> action.getOwner().equals(owner));
|
||||
return Sets.filter(ownerMatch, action -> action.getName().equals(name));
|
||||
}
|
||||
|
||||
/**
|
||||
* A method to locate the {@link SharedStubKeyBindingAction} representative for the given
|
||||
* action name. This method is not useful to general clients.
|
||||
*
|
||||
* @param allActions all actions in the system
|
||||
* @param sharedName the name of the shared action
|
||||
* @return the shared action representative
|
||||
*/
|
||||
public static DockingActionIf getSharedKeyBindingAction(Set<DockingActionIf> allActions,
|
||||
String sharedName) {
|
||||
|
||||
Set<DockingActionIf> toolActions = getActions(allActions, "Tool", sharedName);
|
||||
|
||||
//@formatter:off
|
||||
return toolActions
|
||||
.stream()
|
||||
.filter(action -> action instanceof SharedStubKeyBindingAction)
|
||||
.findAny()
|
||||
.orElse(null)
|
||||
;
|
||||
//@formatter:on
|
||||
}
|
||||
|
||||
private static boolean isIgnored(DockingActionIf action) {
|
||||
// not keybinding managed; a shared keybinding implies that this action should not be in
|
||||
// the UI, as there will be a single proxy in place of all actions sharing that binding
|
||||
return !action.isKeyBindingManaged() || action.usesSharedKeyBinding();
|
||||
}
|
||||
|
||||
/**
|
||||
* Takes the existing docking action and allows it to be registered with
|
||||
* Swing components
|
||||
|
@ -341,6 +456,46 @@ public class KeyBindingUtils {
|
|||
return new ActionAdapter(action);
|
||||
}
|
||||
|
||||
public static void assertSameDefaultKeyBindings(DockingActionIf newAction,
|
||||
List<DockingActionIf> existingActions) {
|
||||
|
||||
KeyBindingData newDefaultBinding = newAction.getDefaultKeyBindingData();
|
||||
KeyStroke defaultKs = getKeyStroke(newDefaultBinding);
|
||||
for (DockingActionIf action : existingActions) {
|
||||
KeyBindingData existingDefaultBinding = action.getDefaultKeyBindingData();
|
||||
KeyStroke existingKs = getKeyStroke(existingDefaultBinding);
|
||||
if (!Objects.equals(defaultKs, existingKs)) {
|
||||
logDifferentKeyBindingsWarnigMessage(newAction, action, existingKs);
|
||||
break; // one warning seems like enough
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void logDifferentKeyBindingsWarnigMessage(DockingActionIf newAction,
|
||||
DockingActionIf existingAction, KeyStroke existingDefaultKs) {
|
||||
|
||||
//@formatter:off
|
||||
String s = "Shared Key Binding Actions have different default values. These " +
|
||||
"must be the same." +
|
||||
"\n\tAction name: '"+existingAction.getName()+"'" +
|
||||
"\n\tAction 1: " + existingAction.getInceptionInformation() +
|
||||
"\n\t\tKey Binding: " + existingDefaultKs +
|
||||
"\n\tAction 2: " + newAction.getInceptionInformation() +
|
||||
"\n\t\tKey Binding: " + newAction.getKeyBinding() +
|
||||
"\nUsing the " +
|
||||
"first value set - " + existingDefaultKs;
|
||||
//@formatter:on
|
||||
|
||||
Msg.warn(KeyBindingUtils.class, s, ReflectionUtilities.createJavaFilteredThrowable());
|
||||
}
|
||||
|
||||
private static KeyStroke getKeyStroke(KeyBindingData data) {
|
||||
if (data == null) {
|
||||
return null;
|
||||
}
|
||||
return data.getKeyBinding();
|
||||
}
|
||||
|
||||
//==================================================================================================
|
||||
// Private Methods
|
||||
//==================================================================================================
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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<DockingActionIf> getActions(DockingTool tool, String name) {
|
||||
public static Set<DockingActionIf> getActionsByName(DockingTool tool, String name) {
|
||||
|
||||
Set<DockingActionIf> actions = new HashSet<>();
|
||||
Set<DockingActionIf> result = new HashSet<>();
|
||||
|
||||
List<DockingActionIf> toolActions = tool.getAllActions();
|
||||
Set<DockingActionIf> toolActions = tool.getAllActions();
|
||||
for (DockingActionIf action : toolActions) {
|
||||
if (action.getName().equals(name)) {
|
||||
actions.add(action);
|
||||
result.add(action);
|
||||
}
|
||||
}
|
||||
return actions;
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* A helper method to find all actions with the given owner's name
|
||||
*
|
||||
* @param tool the tool containing all system actions
|
||||
* @param name the owner's name to match
|
||||
* @return the matching actions; empty list if no matches
|
||||
*/
|
||||
public static Set<DockingActionIf> getActionsByOwner(DockingTool tool, String name) {
|
||||
return tool.getDockingActionsByOwnerName(name);
|
||||
}
|
||||
|
||||
/**
|
||||
* A helper method to find all actions by name, with the given owner's name
|
||||
*
|
||||
* @param tool the tool containing all system actions
|
||||
* @param owner the owner's name
|
||||
* @param name the owner's name to match
|
||||
* @return the matching actions; empty list if no matches
|
||||
*/
|
||||
public static Set<DockingActionIf> getActionsByOwnerAndName(DockingTool tool, String owner,
|
||||
String name) {
|
||||
Set<DockingActionIf> ownerActions = tool.getDockingActionsByOwnerName(owner);
|
||||
return Sets.filter(ownerActions, action -> action.getName().equals(name));
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds the singular tool action by the given name. If more than one action exists with
|
||||
* that name, then an exception is thrown. If you want more than one matching action,
|
||||
* the call {@link #getActions(DockingTool, String)} instead.
|
||||
* the call {@link #getActionsByName(DockingTool, String)} instead.
|
||||
*
|
||||
* <P>Note: more specific test case subclasses provide other methods for finding actions
|
||||
* 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<DockingActionIf> actions = getActions(tool, name);
|
||||
Set<DockingActionIf> 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.
|
||||
*
|
||||
* <P>Note: more specific test case subclasses provide other methods for finding actions
|
||||
* when you have an owner name (which is usually the plugin name).
|
||||
|
@ -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<DockingActionIf> actions = tool.getDockingActionsByFullActionName(fullName);
|
||||
Set<DockingActionIf> 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);
|
||||
|
|
|
@ -442,7 +442,9 @@ public abstract class AbstractSortedTableModel<T> extends AbstractGTableModel<T>
|
|||
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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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<DockingActionIf> actions = getActions(tool, action.getName());
|
||||
Set<DockingActionIf> 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<DockingActionIf> actions = getActions(tool, action.getName());
|
||||
Set<DockingActionIf> actions = getActionsByName(tool, action.getName());
|
||||
for (DockingActionIf toolAction : actions) {
|
||||
assertNotSame(toolAction, action);
|
||||
}
|
||||
}
|
||||
|
||||
private void assertNoSharedKeyBindingStubInstalled(String sharedName) {
|
||||
List<DockingActionIf> 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) {
|
|
@ -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() {
|
|
@ -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(" ]");
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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<DockingActionIf> getActionsForPlugin(PluginDescription pluginDescription) {
|
||||
public Set<DockingActionIf> getActionsForPlugin(PluginDescription pluginDescription) {
|
||||
if (!isLoaded(pluginDescription)) {
|
||||
return Collections.emptyList();
|
||||
return Collections.emptySet();
|
||||
}
|
||||
|
||||
return tool.getDockingActionsByOwnerName(pluginDescription.getName());
|
||||
return KeyBindingUtils.getKeyBindingActions(tool, pluginDescription.getName());
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -20,6 +20,7 @@ import java.beans.PropertyChangeEvent;
|
|||
import java.beans.PropertyChangeListener;
|
||||
import java.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<String, KeyStroke> actionMap; // map action name to keystroke
|
||||
private Map<String, List<String>> keyMap; // map keystroke name to ArrayList of action names
|
||||
private List<DockingActionIf> actionList;
|
||||
private Map<String, KeyStroke> originalValues; // original mapping for action name to
|
||||
// keystroke (to know what changed)
|
||||
|
||||
private Map<String, DockingActionIf> actionsByFullName;
|
||||
private Map<String, List<String>> actionNamesByKeyStroke;
|
||||
private Map<String, KeyStroke> keyStrokesByFullName;
|
||||
private Map<String, KeyStroke> originalValues; // to know what has been changed
|
||||
private List<DockingActionIf> 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<String> iter = actionMap.keySet().iterator();
|
||||
Iterator<String> 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<DockingActionIf> actions = tool.getDockingActionsByFullActionName(actionName);
|
||||
Set<DockingActionIf> 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<DockingActionIf> actions = tool.getAllActions();
|
||||
for (DockingActionIf action : actions) {
|
||||
if (isIgnored(action)) {
|
||||
continue;
|
||||
}
|
||||
actionsByFullName = KeyBindingUtils.getAllKeyBindingActions(tool);
|
||||
Set<Entry<String, DockingActionIf>> entries = actionsByFullName.entrySet();
|
||||
for (Entry<String, DockingActionIf> 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<String> iter = actionMap.keySet().iterator();
|
||||
Iterator<String> iter = keyStrokesByFullName.keySet().iterator();
|
||||
while (iter.hasNext()) {
|
||||
String actionName = iter.next();
|
||||
List<DockingActionIf> 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<String> list = keyMap.get(ksName);
|
||||
List<String> 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<String> list = keyMap.get(ksName);
|
||||
List<String> 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<String> list = keyMap.get(ksName);
|
||||
List<String> 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<String, KeyStroke> 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<DockingActionIf> actions =
|
||||
tool.getDockingActionsByFullActionName(selectedAction);
|
||||
String description = actions.get(0).getDescription();
|
||||
if (description == null || description.trim().isEmpty()) {
|
||||
description = actions.get(0).getName();
|
||||
}
|
||||
statusLabel.setText("<html>" + 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("<html>" + 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<DockingActionIf> 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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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<PluginDescription> dependencies = model.getDependencies(pluginDescription);
|
||||
Collections.sort(dependencies, (pd1, pd2) -> pd1.getName().compareTo(pd2.getName()));
|
||||
|
||||
StringBuilder buffer = new StringBuilder("<HTML>");
|
||||
|
||||
buffer.append( "<TABLE cellpadding=2>" );
|
||||
|
||||
insertRowTitle(buffer, "Name");
|
||||
|
||||
buffer.append("<TABLE cellpadding=2>");
|
||||
|
||||
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( "<TD VALIGN=\"TOP\">" );
|
||||
|
||||
if (dependencies.isEmpty()) {
|
||||
insertHTMLLine("None", titleAttrSet, buffer);
|
||||
}
|
||||
else {
|
||||
for (int i = 0; i < dependencies.size(); i++) {
|
||||
insertHTMLString(dependencies.get(i).getPluginClass().getName(), dependencyAttrSet,
|
||||
buffer);
|
||||
if (i < dependencies.size() - 1) {
|
||||
insertHTMLString("<BR>", dependencyAttrSet, buffer);
|
||||
}
|
||||
}
|
||||
insertHTMLLine("", titleAttrSet, buffer); // add a newline
|
||||
}
|
||||
buffer.append( "</TD>" );
|
||||
buffer.append( "</TR>" );
|
||||
|
||||
insertRowTitle(buffer, "Services Required");
|
||||
|
||||
buffer.append("<TD VALIGN=\"TOP\">");
|
||||
|
||||
List<Class<?>> 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("<BR>", dependencyAttrSet, buffer);
|
||||
|
@ -135,165 +112,185 @@ class PluginDetailsPanel extends AbstractDetailsPanel {
|
|||
buffer.append("</TD>");
|
||||
buffer.append("</TR>");
|
||||
|
||||
//
|
||||
// Developer
|
||||
//
|
||||
//
|
||||
// Optional: Actions loaded by this plugin
|
||||
//
|
||||
addLoadedActionsContent( buffer, pluginDescription );
|
||||
|
||||
buffer.append( "</TABLE>" );
|
||||
insertRowTitle(buffer, "Services Required");
|
||||
|
||||
textLabel.setText( buffer.toString() );
|
||||
sp.getViewport().setViewPosition(new Point(0,0));
|
||||
}
|
||||
buffer.append("<TD VALIGN=\"TOP\">");
|
||||
|
||||
List<Class<?>> servicesRequired = pluginDescription.getServicesRequired();
|
||||
if (servicesRequired.isEmpty()) {
|
||||
insertHTMLLine("None", titleAttrSet, buffer);
|
||||
}
|
||||
else {
|
||||
for (int i = 0; i < servicesRequired.size(); i++) {
|
||||
insertHTMLString(servicesRequired.get(i).getName(), dependencyAttrSet, buffer);
|
||||
if (i < dependencies.size() - 1) {
|
||||
insertHTMLString("<BR>", dependencyAttrSet, buffer);
|
||||
}
|
||||
}
|
||||
insertHTMLLine("", titleAttrSet, buffer); // add a newline
|
||||
}
|
||||
buffer.append("</TD>");
|
||||
buffer.append("</TR>");
|
||||
|
||||
//
|
||||
// Developer
|
||||
//
|
||||
//
|
||||
// Optional: Actions loaded by this plugin
|
||||
//
|
||||
addLoadedActionsContent(buffer, pluginDescription);
|
||||
|
||||
buffer.append("</TABLE>");
|
||||
|
||||
textLabel.setText(buffer.toString());
|
||||
sp.getViewport().setViewPosition(new Point(0, 0));
|
||||
}
|
||||
|
||||
// creates an HTML table to display actions loaded by the plugin
|
||||
private void addLoadedActionsContent(StringBuilder buffer,
|
||||
PluginDescription pluginDescription) {
|
||||
if ( !model.isLoaded( pluginDescription ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
buffer.append( "<TR>" );
|
||||
buffer.append( "<TD VALIGN=\"TOP\">" );
|
||||
insertHTMLLine("Loaded Actions:", titleAttrSet, buffer);
|
||||
buffer.append( "</TD>" );
|
||||
if (!model.isLoaded(pluginDescription)) {
|
||||
return;
|
||||
}
|
||||
|
||||
List<DockingActionIf> actionList = model.getActionsForPlugin( pluginDescription );
|
||||
if ( actionList.size() == 0 ) {
|
||||
buffer.append( "<TD VALIGN=\"TOP\">" );
|
||||
insertHTMLLine("No actions for plugin", noValueAttrSet, buffer);
|
||||
buffer.append( "</TD>" );
|
||||
buffer.append( "</TR>" );
|
||||
return;
|
||||
}
|
||||
|
||||
buffer.append( "<TD VALIGN=\"TOP\">" );
|
||||
|
||||
buffer.append( "<TABLE BORDER=1><TR><TH>Action Name</TH><TH>Menu Path</TH><TH>Keybinding</TH></TR>" );
|
||||
|
||||
for ( DockingActionIf dockableAction : actionList ) {
|
||||
buffer.append( "<TR><TD WIDTH=\"200\">" );
|
||||
insertHTMLString( dockableAction.getName(), locAttrSet, buffer );
|
||||
buffer.append( "</TD>" );
|
||||
|
||||
buffer.append( "<TD WIDTH=\"300\">" );
|
||||
MenuData menuBarData = dockableAction.getMenuBarData();
|
||||
String[] menuPath = menuBarData == null ? null : menuBarData.getMenuPath();
|
||||
String menuPathString = createStringForMenuPath( menuPath );
|
||||
if ( menuPathString != null ) {
|
||||
insertHTMLString( menuPathString, locAttrSet, buffer );
|
||||
}
|
||||
else {
|
||||
MenuData popupMenuData = dockableAction.getPopupMenuData();
|
||||
String[] popupPath = popupMenuData == null ? null : popupMenuData.getMenuPath();
|
||||
buffer.append("<TR>");
|
||||
buffer.append("<TD VALIGN=\"TOP\">");
|
||||
insertHTMLLine("Loaded Actions:", titleAttrSet, buffer);
|
||||
buffer.append("</TD>");
|
||||
|
||||
if ( popupPath != null ) {
|
||||
insertHTMLString( "(in a context popup menu)", noValueAttrSet, buffer );
|
||||
}
|
||||
else {
|
||||
insertHTMLString( "Not in a menu", noValueAttrSet, buffer );
|
||||
}
|
||||
}
|
||||
|
||||
buffer.append( "</TD>" );
|
||||
|
||||
buffer.append( "<TD WIDTH=\"100\">" );
|
||||
KeyStroke keyBinding = dockableAction.getKeyBinding();
|
||||
if ( keyBinding != null ) {
|
||||
String keyStrokeString = DockingKeyBindingAction.parseKeyStroke( keyBinding );
|
||||
insertHTMLString( keyStrokeString, locAttrSet, buffer );
|
||||
}
|
||||
else {
|
||||
insertHTMLString( "No keybinding", noValueAttrSet, buffer );
|
||||
}
|
||||
|
||||
buffer.append( "</TD></TR>" );
|
||||
}
|
||||
|
||||
buffer.append( "</TABLE>" );
|
||||
buffer.append( "</TD>" );
|
||||
buffer.append( "</TR>" );
|
||||
Set<DockingActionIf> actions = model.getActionsForPlugin(pluginDescription);
|
||||
if (actions.size() == 0) {
|
||||
buffer.append("<TD VALIGN=\"TOP\">");
|
||||
insertHTMLLine("No actions for plugin", noValueAttrSet, buffer);
|
||||
buffer.append("</TD>");
|
||||
buffer.append("</TR>");
|
||||
return;
|
||||
}
|
||||
|
||||
buffer.append("<TD VALIGN=\"TOP\">");
|
||||
|
||||
buffer.append(
|
||||
"<TABLE BORDER=1><TR><TH>Action Name</TH><TH>Menu Path</TH><TH>Keybinding</TH></TR>");
|
||||
|
||||
for (DockingActionIf dockableAction : actions) {
|
||||
buffer.append("<TR><TD WIDTH=\"200\">");
|
||||
insertHTMLString(dockableAction.getName(), locAttrSet, buffer);
|
||||
buffer.append("</TD>");
|
||||
|
||||
buffer.append("<TD WIDTH=\"300\">");
|
||||
MenuData menuBarData = dockableAction.getMenuBarData();
|
||||
String[] menuPath = menuBarData == null ? null : menuBarData.getMenuPath();
|
||||
String menuPathString = createStringForMenuPath(menuPath);
|
||||
if (menuPathString != null) {
|
||||
insertHTMLString(menuPathString, locAttrSet, buffer);
|
||||
}
|
||||
else {
|
||||
MenuData popupMenuData = dockableAction.getPopupMenuData();
|
||||
String[] popupPath = popupMenuData == null ? null : popupMenuData.getMenuPath();
|
||||
|
||||
if (popupPath != null) {
|
||||
insertHTMLString("(in a context popup menu)", noValueAttrSet, buffer);
|
||||
}
|
||||
else {
|
||||
insertHTMLString("Not in a menu", noValueAttrSet, buffer);
|
||||
}
|
||||
}
|
||||
|
||||
buffer.append("</TD>");
|
||||
|
||||
buffer.append("<TD WIDTH=\"100\">");
|
||||
KeyStroke keyBinding = dockableAction.getKeyBinding();
|
||||
if (keyBinding != null) {
|
||||
String keyStrokeString = DockingKeyBindingAction.parseKeyStroke(keyBinding);
|
||||
insertHTMLString(keyStrokeString, locAttrSet, buffer);
|
||||
}
|
||||
else {
|
||||
insertHTMLString("No keybinding", noValueAttrSet, buffer);
|
||||
}
|
||||
|
||||
buffer.append("</TD></TR>");
|
||||
}
|
||||
|
||||
buffer.append("</TABLE>");
|
||||
buffer.append("</TD>");
|
||||
buffer.append("</TR>");
|
||||
}
|
||||
|
||||
private String createStringForMenuPath( String[] path ) {
|
||||
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));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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<String, List<DockingActionIf>> 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<DockingActionIf> getDockingActionsByFullActionName(String fullActionName) {
|
||||
List<DockingActionIf> list = actionMap.get(fullActionName);
|
||||
public List<DockingActionIf> getDockingActionsByFullActionName(String fullName) {
|
||||
List<DockingActionIf> 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<DockingActionIf> 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());
|
||||
|
|
|
@ -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<DockingActionIf> actions = tool.getDockingActionsByFullActionName(fullActionName);
|
||||
AssembleDockingAction action = (AssembleDockingAction) actions.get(0);
|
||||
DockingActionIf action = getAction(tool, "AssemblerPlugin", "Assemble");
|
||||
|
||||
performAction(action, true);
|
||||
|
||||
|
|
|
@ -156,10 +156,10 @@ public class DataTypeManagerPluginScreenShots extends GhidraScreenShotGenerator
|
|||
|
||||
@Test
|
||||
public void testPreviewWindow() {
|
||||
String fullActionName = "Show Preview Window (DataTypeManagerPlugin)";
|
||||
List<DockingActionIf> 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();
|
||||
|
|
|
@ -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<DockingActionIf> actions = tool.getDockingActionsByFullActionName(fullActionName);
|
||||
|
||||
final KeyEntryDialog keyEntryDialog = new KeyEntryDialog(actions.get(0), actionMgr);
|
||||
DockingActionIf action = getAction(tool, "FunctionPlugin", "Delete Function");
|
||||
final KeyEntryDialog keyEntryDialog = new KeyEntryDialog(action, actionMgr);
|
||||
|
||||
runSwing(() -> tool.showDialog(keyEntryDialog), false);
|
||||
captureDialog();
|
||||
|
|
|
@ -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<DockingActionIf> 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 {
|
||||
|
|
|
@ -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<DockingActionIf> getFrontEndActions() {
|
||||
return frontEndTool.getDockingActionsByOwnerName("FrontEndPlugin");
|
||||
}
|
||||
|
||||
public DockingActionIf getAction(String actionName) {
|
||||
List<DockingActionIf> 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) {
|
||||
|
|
Loading…
Reference in a new issue