GT-2925 - Key Bindings - Support Window Menu Provider Key Bindings -

test and review fixes
This commit is contained in:
dragonmacher 2019-07-05 12:43:24 -04:00
parent 10621008e0
commit 6015650079
50 changed files with 539 additions and 640 deletions

View File

@ -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.
@ -23,20 +22,18 @@ import ghidra.program.model.address.AddressSetView;
import ghidra.program.model.listing.Function;
import ghidra.program.model.listing.FunctionIterator;
public class DeleteFunctionDefaultPlates extends GhidraScript {
public class DeleteFunctionDefaultPlatesScript extends GhidraScript {
private static String DEFAULT_PLATE = " FUNCTION";
/* (non-Javadoc)
* @see ghidra.app.script.GhidraScript#run()
*/
@Override
public void run() throws Exception {
public void run() throws Exception {
AddressSetView set = currentProgram.getMemory();
if (currentSelection != null && !currentSelection.isEmpty()) {
set = currentSelection;
}
int updateCount=0;
int updateCount = 0;
FunctionIterator iter = currentProgram.getFunctionManager().getFunctions(set, true);
while (iter.hasNext()) {
Function function = iter.next();
@ -47,7 +44,7 @@ public class DeleteFunctionDefaultPlates extends GhidraScript {
}
}
if (updateCount > 0) {
String cmt = updateCount > 1? "comments" : "comment";
String cmt = updateCount > 1 ? "comments" : "comment";
println("Removed " + updateCount + " default plate " + cmt + ".");
}
else {

View File

@ -148,6 +148,14 @@ public class CallTreePlugin extends ProgramPlugin {
tool.showComponentProvider(provider, true);
}
CallTreeProvider getPrimaryProvider() {
return primaryProvider;
}
DockingAction getShowCallTreeFromMenuAction() {
return showCallTreeFromMenuAction;
}
ProgramLocation getCurrentLocation() {
return currentLocation;
}

View File

@ -876,6 +876,7 @@ public class CallTreeProvider extends ComponentProviderAdapter implements Domain
// changes, which means we will get here while setting the location, but our program
// will have been null'ed out.
currentProgram = plugin.getCurrentProgram();
currentProgram.addListener(this);
}
Function function = plugin.getFunction(location);

View File

@ -915,18 +915,13 @@ public class CodeBrowserPlugin extends Plugin
}
};
// note: this action gets added later when the TableService is added
tableFromSelectionAction.setEnabled(false);
tableFromSelectionAction.setMenuBarData(new MenuData(
new String[] { ToolConstants.MENU_SELECTION, "Create Table From Selection" }, null,
"SelectUtils"));
tableFromSelectionAction
.setHelpLocation(new HelpLocation("CodeBrowserPlugin", "Selection_Table"));
// don't add the actions initially if the service isn't there
TableService tableService = tool.getService(TableService.class);
if (tableService != null) {
tool.addAction(tableFromSelectionAction);
}
tableFromSelectionAction.setHelpLocation(
new HelpLocation("CodeBrowserPlugin", "Selection_Table"));
}
private GhidraProgramTableModel<Address> createTableModel(CodeUnitIterator iterator,
@ -1001,8 +996,8 @@ public class CodeBrowserPlugin extends Plugin
public boolean goToField(Address a, String fieldName, int occurrence, int row, int col,
boolean scroll) {
boolean result = SystemUtilities
.runSwingNow(() -> doGoToField(a, fieldName, occurrence, row, col, scroll));
boolean result = SystemUtilities.runSwingNow(
() -> doGoToField(a, fieldName, occurrence, row, col, scroll));
return result;
}

View File

@ -36,7 +36,6 @@ import docking.widgets.fieldpanel.FieldPanel;
import docking.widgets.fieldpanel.HoverHandler;
import docking.widgets.fieldpanel.internal.FieldPanelCoordinator;
import docking.widgets.fieldpanel.support.*;
import ghidra.GhidraOptions;
import ghidra.app.nav.*;
import ghidra.app.plugin.core.clipboard.CodeBrowserClipboardProvider;
import ghidra.app.plugin.core.codebrowser.actions.*;
@ -63,8 +62,6 @@ public class CodeViewerProvider extends NavigatableComponentProviderAdapter
private static final String TITLE = "Listing: ";
private static final String OPERAND_OPTIONS_PREFIX = GhidraOptions.OPERAND_GROUP_TITLE + ".";
private static final Icon LISTING_FORMAT_EXPAND_ICON =
ResourceManager.loadImage("images/field.header.down.png");
private static final Icon LISTING_FORMAT_COLLAPSE_ICON =
@ -93,9 +90,6 @@ public class CodeViewerProvider extends NavigatableComponentProviderAdapter
private ProgramDropProvider curDropProvider;
private ToggleDockingAction toggleHoverAction;
//TODO - Need to improve CodeUnit.getRepresentation format options interface before adding this
//TODO private ToggleOperandMarkupAction[] toggleOperandMarkupActions;
private ProgramLocation currentLocation;
private ListingPanel otherPanel;
@ -976,9 +970,9 @@ public class CodeViewerProvider extends NavigatableComponentProviderAdapter
}
}
class ToggleHoverAction extends ToggleDockingAction {
private class ToggleHoverAction extends ToggleDockingAction {
ToggleHoverAction() {
super("Toggle Mouse Hover Popups", CodeViewerProvider.this.getName());
super("Toggle Mouse Hover Popups", CodeViewerProvider.this.getOwner());
setEnabled(true);
setToolBarData(new ToolBarData(HOVER_ON_ICON, "yyyz"));
setSelected(true);
@ -998,31 +992,6 @@ public class CodeViewerProvider extends NavigatableComponentProviderAdapter
}
}
class ToggleOperandMarkupAction extends ToggleDockingAction {
final String optionName;
ToggleOperandMarkupAction(String operandOption) {
super(operandOption, CodeViewerProvider.this.getName());
this.optionName = OPERAND_OPTIONS_PREFIX + operandOption;
boolean state =
tool.getOptions(GhidraOptions.CATEGORY_BROWSER_FIELDS).getBoolean(optionName, true);
setMenuBarData(new MenuData(new String[] { operandOption }));
setSelected(state);
setEnabled(true);
setHelpLocation(new HelpLocation("CodeBrowserPlugin", "Operands_Field"));
}
public Object getOptionName() {
return optionName;
}
@Override
public void actionPerformed(ActionContext context) {
boolean state = isSelected();
tool.getOptions(GhidraOptions.CATEGORY_BROWSER_FIELDS).setBoolean(optionName, state);
}
}
/**
* A class that allows clients to install transient highlighters while keeping the
* middle-mouse highlighting on at the same time.

View File

@ -39,7 +39,7 @@ public class CollapseAllDataAction extends ProgramLocationContextAction {
private CodeViewerProvider provider;
public CollapseAllDataAction(CodeViewerProvider provider) {
super("Collapse All Data", provider.getName());
super("Collapse All Data", provider.getOwner());
this.provider = provider;
setPopupMenuData(new MenuData(new String[] { "Collapse All Data" }, null, "Structure"));
@ -95,8 +95,7 @@ public class CollapseAllDataAction extends ProgramLocationContextAction {
ProgramLocation location = context.getLocation();
Data data = getTopLevelComponentData(location);
TaskLauncher.launchModal("Collapse Data",
monitor -> model.closeAllData(data, monitor));
TaskLauncher.launchModal("Collapse Data", monitor -> model.closeAllData(data, monitor));
}
private ListingModel getModel() {

View File

@ -36,7 +36,7 @@ public class ExpandAllDataAction extends ProgramLocationContextAction {
private CodeViewerProvider provider;
public ExpandAllDataAction(CodeViewerProvider provider) {
super("Expand All Data", provider.getName());
super("Expand All Data", provider.getOwner());
this.provider = provider;
setPopupMenuData(new MenuData(new String[] { "Expand All Data" }, null, "Structure"));

View File

@ -39,7 +39,7 @@ public class ToggleExpandCollapseDataAction extends ProgramLocationContextAction
private CodeViewerProvider provider;
public ToggleExpandCollapseDataAction(CodeViewerProvider provider) {
super("Toggle Expand/Collapse Data", provider.getName());
super("Toggle Expand/Collapse Data", provider.getOwner());
this.provider = provider;
setPopupMenuData(

View File

@ -466,7 +466,6 @@ class GhidraScriptActionManager {
if (action == null) {
action = new ScriptAction(plugin, script);
actionMap.put(script, action);
plugin.getTool().addAction(action);
}
return action;
}

View File

@ -347,7 +347,7 @@ public class SymbolTablePlugin extends Plugin implements DomainObjectListener {
private void createSymActions() {
String popupGroup = "1";
openRefsAction = new DockingAction("Symbol References", getName()) {
openRefsAction = new DockingAction("Symbol References", getName(), KeyBindingType.SHARED) {
@Override
public void actionPerformed(ActionContext context) {
refProvider.open();
@ -359,7 +359,7 @@ public class SymbolTablePlugin extends Plugin implements DomainObjectListener {
new MenuData(new String[] { "Symbol References" }, icon, popupGroup));
openRefsAction.setToolBarData(new ToolBarData(icon));
openRefsAction.setDescription("Symbol References");
openRefsAction.setDescription("Display Symbol References");
tool.addLocalAction(symProvider, openRefsAction);
deleteAction = new DockingAction("Delete Symbols", getName()) {

View File

@ -62,7 +62,7 @@ public interface PluginConstants {
*/
char ANYSINGLECHAR_WILDCARD_CHAR = '?';
String CODE_BROWSER = "CodeBrowserPlugin";
String CODE_BROWSER = "Listing";
String MEMORY_MAP = "Memory Map";
String BYTE_VIEWER = "ByteViewerPlugin";
String BOOKMARKS = "Bookmarks";

View File

@ -159,6 +159,25 @@ public class ComponentProviderActionsTest extends AbstractGhidraHeadedIntegratio
assertMenuItemHasKeyStroke(newKs);
}
@Test
public void testSetKeyBinding_ViaDialog_FromWindowMenu_ToAlreadyBoundAction() {
//
// Test the conflicting key binding use case
//
HasDefaultKeyBindingComponentProvider otherProvider =
new HasDefaultKeyBindingComponentProvider(tool);
otherProvider.setVisible(true);
showProvider();
KeyStroke newKs = CONTROL_T;
applyBindingToDialog_FromWindowsMenu(newKs);
assertCollisionsWithKeyStroke();
}
@Test
public void testSetKeyBinding_ViaOptions_WithoutToolbarAction() {
@ -235,6 +254,14 @@ public class ComponentProviderActionsTest extends AbstractGhidraHeadedIntegratio
}
}
@Test
public void testDefaultKeyBindingAppearsInWindowMenu() {
provider.setDefaultKeyBinding(new KeyBindingData(CONTROL_T));
showProvider();
assertWindowMenuActionHasKeyBinding(CONTROL_T);
}
//==================================================================================================
// Private Methods
//==================================================================================================
@ -279,7 +306,7 @@ public class ComponentProviderActionsTest extends AbstractGhidraHeadedIntegratio
.stream()
.filter(a -> a.getOwner().equals(DockingWindowManager.DOCKING_WINDOWS_OWNER))
.findFirst()
.get()
.orElseGet(() -> null)
;
//@formatter:on
});
@ -310,7 +337,7 @@ public class ComponentProviderActionsTest extends AbstractGhidraHeadedIntegratio
}
private void assertNoToolbarAction() {
assertNotNull("No toolbar action found for provider", getToolbarShowProviderAction());
assertNull("No toolbar action found for provider", getToolbarShowProviderAction());
}
private void assertToolbarAction() {
@ -341,6 +368,13 @@ public class ComponentProviderActionsTest extends AbstractGhidraHeadedIntegratio
expected, action.getMenuBarData().getMenuIcon());
}
private void assertWindowMenuActionHasKeyBinding(KeyStroke ks) {
DockingActionIf action = getWindowMenuShowProviderAction();
assertEquals(
"Windows menu key bindings for provider does not match the value set on the provider",
ks, action.getKeyBinding());
}
private void assertCannotShowKeyBindingDialog_FromWindowsMenu() {
// simulate the user mousing over the 'Window' menu's action
DockingActionIf windowMenuAction = getWindowMenuShowProviderAction();
@ -367,6 +401,24 @@ public class ComponentProviderActionsTest extends AbstractGhidraHeadedIntegratio
assertFalse("Invalid key stroke: " + ks, runSwing(() -> dialog.isVisible()));
}
private void applyBindingToDialog_FromWindowsMenu(KeyStroke ks) {
DockingActionIf windowMenuAction = getWindowMenuShowProviderAction();
DockingWindowManager.setMouseOverAction(windowMenuAction);
performLaunchKeyStrokeDialogAction();
KeyEntryDialog dialog = waitForDialogComponent(KeyEntryDialog.class);
runSwing(() -> dialog.setKeyStroke(ks));
}
private void assertCollisionsWithKeyStroke() {
KeyEntryDialog dialog = waitForDialogComponent(KeyEntryDialog.class);
JTextPane collisionPane = (JTextPane) getInstanceField("collisionPane", dialog);
String collisionText = runSwing(() -> collisionPane.getText());
assertTrue(collisionText.contains("Actions mapped to"));
}
private void assertMenuItemHasKeyStroke(KeyStroke expected) {
DockingActionIf action = getWindowMenuShowProviderAction();
@ -415,6 +467,21 @@ public class ComponentProviderActionsTest extends AbstractGhidraHeadedIntegratio
public JComponent getComponent() {
return component;
}
}
private class HasDefaultKeyBindingComponentProvider extends ComponentProvider {
private JComponent component = new JTextField("Hey!");
HasDefaultKeyBindingComponentProvider(DockingTool tool) {
super(tool, HasDefaultKeyBindingComponentProvider.class.getSimpleName(),
"Fooberry Plugin");
setDefaultKeyBinding(new KeyBindingData(CONTROL_T));
}
@Override
public JComponent getComponent() {
return component;
}
}
}

View File

@ -18,6 +18,7 @@ package docking.action;
import static org.junit.Assert.*;
import java.awt.event.KeyEvent;
import java.util.Map;
import javax.swing.*;
@ -25,6 +26,7 @@ import org.junit.*;
import docking.*;
import docking.actions.KeyEntryDialog;
import docking.actions.ToolActions;
import ghidra.app.plugin.core.codebrowser.CodeBrowserPlugin;
import ghidra.app.plugin.core.data.DataPlugin;
import ghidra.app.plugin.core.function.FunctionPlugin;
@ -186,20 +188,26 @@ public class KeyEntryDialogTest extends AbstractGhidraHeadedIntegrationTest {
}
public DockingAction getKeyBindingAction() {
DockingWindowManager dwm = DockingWindowManager.getInstance(tool.getToolFrame());
ActionToGuiMapper dockingActionManager =
(ActionToGuiMapper) getInstanceField("actionManager", dwm);
return (DockingAction) getInstanceField("keyBindingsAction", dockingActionManager);
ToolActions toolActions = tool.getToolActions();
KeyBindingsManager kbm =
(KeyBindingsManager) getInstanceField("keyBindingsManager", toolActions);
Map<KeyStroke, DockingKeyBindingAction> dockingKeyMap =
(Map<KeyStroke, DockingKeyBindingAction>) getInstanceField("dockingKeyMap", kbm);
KeyStroke ks = KeyStroke.getKeyStroke(KeyEvent.VK_F4, 0);
DockingKeyBindingAction dockingAction = dockingKeyMap.get(ks);
DockingAction f4Action = (DockingAction) getInstanceField("docakbleAction", dockingAction);
return f4Action;
}
private void showDialog(final DockingAction actionToEdit) throws Exception {
final DockingAction keyBindingAction = getKeyBindingAction();
DockingAction keyBindingAction = getKeyBindingAction();
executeOnSwingWithoutBlocking(() -> {
DockingWindowManager.setMouseOverAction(actionToEdit);
performAction(keyBindingAction, false);
});
keyEntryDialog = waitForDialogComponent(tool.getToolFrame(), KeyEntryDialog.class, 2000);
keyEntryDialog = waitForDialogComponent(KeyEntryDialog.class);
assertNotNull(keyEntryDialog);
collisionPane = (JTextPane) getInstanceField("collisionPane", keyEntryDialog);

View File

@ -718,7 +718,7 @@ public class BookmarkPluginTest extends AbstractGhidraHeadedIntegrationTest {
}
private void showBookmarkProvider() throws Exception {
DockingActionIf action = getAction(plugin, "Show Bookmarks");
DockingActionIf action = getAction(plugin, "Bookmarks");
performAction(action, true);
table = plugin.getBookmarkTable();
waitForTable();

View File

@ -46,7 +46,6 @@ import ghidra.framework.plugintool.PluginTool;
import ghidra.program.database.ProgramBuilder;
import ghidra.program.database.ProgramDB;
import ghidra.program.model.address.Address;
import ghidra.program.model.address.AddressFactory;
import ghidra.program.model.data.DataType;
import ghidra.program.model.data.PointerDataType;
import ghidra.program.model.listing.Function;
@ -62,7 +61,6 @@ public class CallTreePluginTest extends AbstractGhidraHeadedIntegrationTest {
private TestEnv env;
private CodeBrowserPlugin codeBrowserPlugin;
private PluginTool tool;
private ProgramDB program;
private CallTreePlugin callTreePlugin;
private CallTreeProvider provider;
private List<CallTreeProvider> providers;
@ -70,14 +68,10 @@ public class CallTreePluginTest extends AbstractGhidraHeadedIntegrationTest {
private GTree incomingTree;
private GTree outgoingTree;
private DockingAction showProviderAction;
private ProgramBuilder builder;
private ProgramDB program;
private GoToService goToService;
private AddressFactory addressFactory;
public CallTreePluginTest() {
super();
}
@SuppressWarnings("unchecked")
// cast to list
@ -91,7 +85,6 @@ public class CallTreePluginTest extends AbstractGhidraHeadedIntegrationTest {
callTreePlugin = env.getPlugin(CallTreePlugin.class);
providers = (List<CallTreeProvider>) getInstanceField("providers", callTreePlugin);
showProviderAction = (DockingAction) getInstanceField("showProviderAction", callTreePlugin);
GoToServicePlugin goToPlugin = env.getPlugin(GoToServicePlugin.class);
goToService = (GoToService) invokeInstanceMethod("getGotoService", goToPlugin);
@ -100,20 +93,18 @@ public class CallTreePluginTest extends AbstractGhidraHeadedIntegrationTest {
env.showTool();
program = createProgram();
addressFactory = program.getAddressFactory();
ProgramManager pm = tool.getService(ProgramManager.class);
pm.openProgram(program.getDomainFile());
// setup a good start location
goTo(addr("5000"));
provider = getProvider();
provider = callTreePlugin.getPrimaryProvider();
tool.showComponentProvider(provider, true);
incomingTree = (GTree) getInstanceField("incomingTree", provider);
outgoingTree = (GTree) getInstanceField("outgoingTree", provider);
}
ProgramBuilder builder;
private ProgramDB createProgram() throws Exception {
builder = new ProgramBuilder("Call Trees", ProgramBuilder._TOY);
@ -385,21 +376,21 @@ public class CallTreePluginTest extends AbstractGhidraHeadedIntegrationTest {
assertNotNull("Provider did not update its information when made visible",
providerFunction());
final ToggleDockingAction navigateIncomingLoctionsAction =
ToggleDockingAction navigateIncomingLoctionsAction =
(ToggleDockingAction) getAction("Navigation Incoming Location Changes");
assertTrue(!navigateIncomingLoctionsAction.isSelected());
setToggleActionSelected(navigateIncomingLoctionsAction, provider.getActionContext(null),
false);
assertEquals("Provider's location does not match that of the listing.", currentFunction(),
providerFunction());
goTo(addr("0x6000"));
assertTrue("Provider's location matches that of the listing when not following " +
"location changes.", !currentFunction().equals(providerFunction()));
assertNotEquals("Provider's location matches that of the listing when not following " +
"location changes", currentFunction(), providerFunction());
performAction(navigateIncomingLoctionsAction, true);
assertEquals("Provider's location does not match that of the listing.", currentFunction(),
assertEquals("Provider's location does not match that of the listing", currentFunction(),
providerFunction());
}
@ -779,21 +770,6 @@ public class CallTreePluginTest extends AbstractGhidraHeadedIntegrationTest {
return functionManager.getFunctionAt(address);
}
private CallTreeProvider getProvider() {
final AtomicReference<CallTreeProvider> ref = new AtomicReference<>();
// run in swing, as two threads are accessing/manipulating a variable
runSwing(() -> {
if (providers.size() == 0) {
ref.set(showProvider());
}
else {
ref.set(providers.get(0));
}
});
return ref.get();
}
private CallTreeProvider getProvider(final String address) {
final CallTreeProvider[] providerBox = new CallTreeProvider[1];
@ -939,13 +915,13 @@ public class CallTreePluginTest extends AbstractGhidraHeadedIntegrationTest {
}
private void fullyExpandIncomingNode(GTreeNode node) {
DockingActionIf expandAction = getAction(callTreePlugin, "Fully Expand Selected Nodes");
DockingActionIf expandAction = getLocalAction(provider, "Fully Expand Selected Nodes");
performAction(expandAction, new ActionContext(provider, incomingTree), false);
waitForTree(node.getTree());
}
private void fullyExpandOutgoingNode(GTreeNode node) {
DockingActionIf expandAction = getAction(callTreePlugin, "Fully Expand Selected Nodes");
DockingActionIf expandAction = getLocalAction(provider, "Fully Expand Selected Nodes");
performAction(expandAction, new ActionContext(provider, outgoingTree), false);
waitForTree(node.getTree());
}
@ -1054,11 +1030,11 @@ public class CallTreePluginTest extends AbstractGhidraHeadedIntegrationTest {
String name = child.getName();
Integer integer = map.get(name);
if (integer == null) {
integer = new Integer(0);
integer = 0;
}
int asInt = integer;
asInt++;
map.put(name, new Integer(asInt));
map.put(name, asInt);
}
return map;
}
@ -1088,10 +1064,7 @@ public class CallTreePluginTest extends AbstractGhidraHeadedIntegrationTest {
}
private DockingActionIf getAction(String actionName) {
// make sure there is a provider from which to get actions
getProvider();
DockingActionIf action = getAction(tool, "CallTreePlugin", actionName);
DockingActionIf action = getLocalAction(provider, actionName);
return action;
}
@ -1121,20 +1094,14 @@ public class CallTreePluginTest extends AbstractGhidraHeadedIntegrationTest {
}
}
/**
* Shows and returns a provider for the current address.
*/
private CallTreeProvider showProvider() {
performAction(showProviderAction, true);
return getProvider();
}
/**
* Shows and returns a provider for the specified address.
*/
private CallTreeProvider showProvider(String address) {
goTo(addr(address));
performAction(showProviderAction, true);
DockingAction action = callTreePlugin.getShowCallTreeFromMenuAction();
performAction(action);
return getProvider(address);
}

View File

@ -61,6 +61,9 @@ public class CodeBrowserScreenMovementTest extends AbstractProgramBasedTest {
@Before
public void setUp() throws Exception {
// warning: this test is sensitive to size and layout of the visible component providers;
// any layout changes may affect the values being tested below
initialize();
fp = codeBrowser.getFieldPanel();
@ -115,6 +118,9 @@ public class CodeBrowserScreenMovementTest extends AbstractProgramBasedTest {
@Test
public void testBasicControls() throws Exception {
// warning: this test is sensitive to size and layout of the visible component providers;
// any layout changes may affect the values being tested below
fp = codeBrowser.getFieldPanel();
ListingPanel panel = codeBrowser.getListingPanel();
JScrollBar scrollbar = panel.getVerticalScrollBar();

View File

@ -68,7 +68,7 @@ public class ExpandCollapseDataActionsTest extends AbstractGhidraHeadedIntegrati
pm.openProgram(program.getDomainFile());
addrFactory = program.getAddressFactory();
env.showTool();
provider = (CodeViewerProvider) tool.getComponentProvider("CodeBrowserPlugin");
provider = (CodeViewerProvider) tool.getComponentProvider("Listing");
listingModel = provider.getListingPanel().getListingModel();
CodeBrowserPlugin plugin = getPlugin(tool, CodeBrowserPlugin.class);
toggleExpand = getAction(plugin, "Toggle Expand/Collapse Data");

View File

@ -62,7 +62,7 @@ public class StructureEditorArchiveTest extends AbstractStructureEditorTest {
tool.addPlugin(DataTypeManagerPlugin.class.getName());
dtmService = tool.getService(DataTypeManagerService.class);
plugin = (DataTypeManagerPlugin) dtmService;
manageDts = getAction(plugin, "Data Type Manager");
manageDts = getAction(plugin, "DataTypes Provider");
DataTypesProvider dataTypesProvider = plugin.getProvider();
dtTree = dataTypesProvider.getGTree();

View File

@ -55,14 +55,6 @@ public class ArchiveRemappedHeadedTest extends AbstractGhidraHeadedIntegrationTe
private File vs12ArchiveFile;
private File vs9ArchiveFile;
/**
* Constructor for ArchiveRemappedTest.
* @param testName
*/
public ArchiveRemappedHeadedTest() {
super();
}
@Before
public void setUp() throws Exception {
@ -97,10 +89,9 @@ public class ArchiveRemappedHeadedTest extends AbstractGhidraHeadedIntegrationTe
env.showTool();
tool.showComponentProvider(provider, true);
waitForPostedSwingRunnables();
provider = plugin.getProvider();
tool.showComponentProvider(provider, true);
tree = provider.getGTree();
waitForTree(tree);
}

View File

@ -87,7 +87,7 @@ public class MemoryMapPluginTest extends AbstractGhidraHeadedIntegrationTest {
@Test
public void testActionEnabled() {
DockingActionIf action = getAction(plugin, "View Memory Map");
DockingActionIf action = getAction(plugin, "Memory Map");
assertTrue(action.isEnabled());
}
@ -99,7 +99,7 @@ public class MemoryMapPluginTest extends AbstractGhidraHeadedIntegrationTest {
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")) {
action.getName().equals("Memory Map")) {
assertTrue(action.isEnabledForContext(provider.getActionContext(null)));
}
else {
@ -116,7 +116,7 @@ public class MemoryMapPluginTest extends AbstractGhidraHeadedIntegrationTest {
assertEquals(0, table.getModel().getRowCount());
Set<DockingActionIf> actions = getActionsByOwner(tool, plugin.getName());
for (DockingActionIf action : actions) {
if (!action.getName().equals("View Memory Map")) {
if (!action.getName().equals("Memory Map")) {
assertTrue(!action.isEnabledForContext(provider.getActionContext(null)));
}
}
@ -297,7 +297,7 @@ public class MemoryMapPluginTest extends AbstractGhidraHeadedIntegrationTest {
/////////////////////////////////////////////////////////////////////////
private void showProvider() {
DockingActionIf action = getAction(plugin, "View Memory Map");
DockingActionIf action = getAction(plugin, "Memory Map");
performAction(action, true);
provider = plugin.getMemoryMapProvider();
}

View File

@ -137,7 +137,7 @@ public class MemoryMapProvider1Test extends AbstractGhidraHeadedIntegrationTest
String name = action.getName();
if (name.equals("Add Block") || name.equals("Merge Blocks") ||
name.equals("Delete Block") || name.equals("Set Image Base") ||
name.equals("View Memory Map")) {
name.equals("Memory Map")) {
assertTrue(action.isEnabled());
}
else {
@ -667,7 +667,7 @@ public class MemoryMapProvider1Test extends AbstractGhidraHeadedIntegrationTest
/////////////////////////////////////////////////////////////////////
private void showProvider() {
DockingActionIf action = getAction(plugin, "View Memory Map");
DockingActionIf action = getAction(plugin, "Memory Map");
performAction(action, true);
waitForPostedSwingRunnables();
provider = plugin.getMemoryMapProvider();

View File

@ -1332,7 +1332,7 @@ public class MemoryMapProvider2Test extends AbstractGhidraHeadedIntegrationTest
///////////////////////////////////////////////////////////////////
private void showProvider() {
DockingActionIf action = getAction(plugin, "View Memory Map");
DockingActionIf action = getAction(plugin, "Memory Map");
performAction(action, true);
provider = plugin.getMemoryMapProvider();
table = provider.getTable();

View File

@ -886,7 +886,7 @@ public class MemoryMapProvider3Test extends AbstractGhidraHeadedIntegrationTest
///////////////////////////////////////////////////////////////////
private void showProvider() {
DockingActionIf action = getAction(plugin, "View Memory Map");
DockingActionIf action = getAction(plugin, "Memory Map");
performAction(action, true);
waitForPostedSwingRunnables();
provider = plugin.getMemoryMapProvider();

View File

@ -54,10 +54,6 @@ public class MemoryMapProvider4Test extends AbstractGhidraHeadedIntegrationTest
private JTable table;
private TableModel model;
public MemoryMapProvider4Test() {
super();
}
private Program buildProgram(String programName) throws Exception {
ProgramBuilder builder = new ProgramBuilder(programName, ProgramBuilder._TOY);
builder.createMemory(".text", Long.toHexString(0x1001000), 0x6600);
@ -247,7 +243,7 @@ public class MemoryMapProvider4Test extends AbstractGhidraHeadedIntegrationTest
}
private void showProvider() {
DockingActionIf action = getAction(plugin, "View Memory Map");
DockingActionIf action = getAction(plugin, "Memory Map");
performAction(action, true);
waitForPostedSwingRunnables();
provider = plugin.getMemoryMapProvider();

View File

@ -71,8 +71,7 @@ public class NextPrevAddressPluginTest extends AbstractGhidraHeadedIntegrationTe
NextPrevAddressPlugin plugin = env.getPlugin(NextPrevAddressPlugin.class);
previousAction =
(MultiActionDockingAction) TestUtils.getInstanceField("previousAction", plugin);
nextAction =
(MultiActionDockingAction) TestUtils.getInstanceField("nextAction", plugin);
nextAction = (MultiActionDockingAction) TestUtils.getInstanceField("nextAction", plugin);
GoToAddressLabelPlugin goToPlugin = env.getPlugin(GoToAddressLabelPlugin.class);
dialog = goToPlugin.getDialog();
@ -355,9 +354,9 @@ public class NextPrevAddressPluginTest extends AbstractGhidraHeadedIntegrationTe
@SuppressWarnings("unchecked")
// let caution fly
private JButton findButtonForAction(DockingWindowManager windowManager, DockingAction action) {
Object actionManager = TestUtils.getInstanceField("actionManager", windowManager);
Object actionToGuiMapper = TestUtils.getInstanceField("actionToGuiMapper", windowManager);
Object menuAndToolBarManager =
TestUtils.getInstanceField("menuAndToolBarManager", actionManager);
TestUtils.getInstanceField("menuAndToolBarManager", actionToGuiMapper);
Map<WindowNode, WindowActionManager> map =
(Map<WindowNode, WindowActionManager>) TestUtils.getInstanceField(
"windowToActionManagerMap", menuAndToolBarManager);

View File

@ -37,12 +37,9 @@ import ghidra.program.util.ProgramSelection;
import ghidra.test.*;
/**
* Test for deleting default plate comments on a function.
*
*
*
* Test for deleting default plate comments on a function
*/
public class DeleteFunctionDefaultPlatesTest extends AbstractGhidraHeadedIntegrationTest {
public class DeleteFunctionDefaultPlatesScriptTest extends AbstractGhidraHeadedIntegrationTest {
private TestEnv env;
private PluginTool tool;
@ -50,13 +47,6 @@ public class DeleteFunctionDefaultPlatesTest extends AbstractGhidraHeadedIntegra
private File script;
private ToyProgramBuilder builder;
public DeleteFunctionDefaultPlatesTest() {
super();
}
/*
* @see TestCase#setUp()
*/
@Before
public void setUp() throws Exception {
env = new TestEnv();
@ -71,11 +61,8 @@ public class DeleteFunctionDefaultPlatesTest extends AbstractGhidraHeadedIntegra
ProgramManager pm = tool.getService(ProgramManager.class);
pm.openProgram(program.getDomainFile());
//script =
// new File(Application.getApplicationRootDirectory().getFile(),
// "Features/Base/ghidra_scripts/DeleteFunctionDefaultPlates.java");
script = Application.getModuleFile("Base",
"ghidra_scripts/DeleteFunctionDefaultPlates.java").getFile(true);
"ghidra_scripts/DeleteFunctionDefaultPlatesScript.java").getFile(true);
env.showTool();
}
@ -97,9 +84,6 @@ public class DeleteFunctionDefaultPlatesTest extends AbstractGhidraHeadedIntegra
return builder.getProgram();
}
/*
* @see TestCase#tearDown()
*/
@After
public void tearDown() throws Exception {
env.dispose();

View File

@ -90,7 +90,7 @@ public class SymbolTreePlugin1Test extends AbstractGhidraHeadedIntegrationTest {
tool.addPlugin(SymbolTreePlugin.class.getName());
plugin = env.getPlugin(SymbolTreePlugin.class);
symTreeAction = getAction(plugin, "Display Symbol Tree");
symTreeAction = getAction(plugin, "Symbol Tree");
cbPlugin = env.getPlugin(CodeBrowserPlugin.class);
util = new SymbolTreeTestUtils(plugin);
@ -107,15 +107,6 @@ public class SymbolTreePlugin1Test extends AbstractGhidraHeadedIntegrationTest {
env.dispose();
}
@Test
public void testActionEnabled() {
assertTrue(symTreeAction.isEnabledForContext(null));
util.openProgram();
assertTrue(symTreeAction.isEnabledForContext(null));
}
@Test
public void testShowDisplay() throws Exception {
showSymbolTree();

View File

@ -90,14 +90,14 @@ class SymbolTreeTestUtils {
this.plugin = plugin;
this.program = buildProgram();
symTreeAction = getAction(plugin, "Display Symbol Tree");
symTreeAction = getAction(plugin, "Symbol Tree");
}
SymbolTreeTestUtils(SymbolTreePlugin plugin, Program program) {
this.plugin = plugin;
this.program = program;
symTreeAction = getAction(plugin, "Display Symbol Tree");
symTreeAction = getAction(plugin, "Symbol Tree");
}
public static Program buildProgram() throws Exception {

View File

@ -21,6 +21,7 @@ import java.awt.*;
import java.awt.event.*;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import java.util.function.BiConsumer;
import javax.swing.*;
@ -59,6 +60,7 @@ import ghidra.util.table.GhidraTableFilterPanel;
import ghidra.util.table.ProgramTableModel;
import ghidra.util.table.field.AddressBasedLocation;
import ghidra.util.xml.XmlUtilities;
import util.CollectionUtils;
public class SymbolTablePluginTest extends AbstractGhidraHeadedIntegrationTest {
@ -93,8 +95,14 @@ public class SymbolTablePluginTest extends AbstractGhidraHeadedIntegrationTest {
plugin = env.getPlugin(SymbolTablePlugin.class);
provider = (SymbolProvider) getInstanceField("symProvider", plugin);
viewSymAction = getAction(plugin, "View Symbol Table");
viewRefAction = getAction(plugin, "View Symbol References");
viewSymAction = getAction(plugin, "Symbol Table");
// this action is actually in the tool twice: once for the provider and once as a
// local action in the Symbol Table header, so we must pick one
Set<DockingActionIf> symbolReferencesActions =
getActionsByOwnerAndName(tool, plugin.getName(), "Symbol References");
viewRefAction = CollectionUtils.any(symbolReferencesActions);
deleteAction = getAction(plugin, "Delete Symbols");
makeSelectionAction = getAction(plugin, "Make Selection");
setFilterAction = getAction(plugin, "Set Filter");

View File

@ -1,390 +0,0 @@
/* ###
* 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 ghidra.framework.main.datatree;
import static org.junit.Assert.*;
import java.awt.Container;
import java.util.ArrayList;
import java.util.List;
import javax.swing.*;
import javax.swing.tree.DefaultTreeCellEditor;
import javax.swing.tree.TreePath;
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;
import docking.widgets.tree.support.BreadthFirstIterator;
import ghidra.framework.data.DomainObjectAdapter;
import ghidra.framework.main.FrontEndTool;
import ghidra.framework.model.DomainFile;
import ghidra.framework.model.DomainFolder;
import ghidra.program.database.ProgramBuilder;
import ghidra.program.database.ProgramDB;
import ghidra.program.model.listing.Program;
import ghidra.test.AbstractGhidraHeadedIntegrationTest;
import ghidra.test.TestEnv;
import ghidra.util.task.TaskMonitorAdapter;
import resources.MultiIcon;
import resources.ResourceManager;
/**
*
* Mores Tests for actions in the front end (Ghidra project window).
*
*/
public class ActionManager2Test extends AbstractGhidraHeadedIntegrationTest {
private FrontEndTool frontEndTool;
private TestEnv env;
private DataTree tree;
private DomainFolder rootFolder;
private GTreeRootNode rootNode;
@Before
public void setUp() throws Exception {
env = new TestEnv();
frontEndTool = env.getFrontEndTool();
env.showFrontEndTool();
tree = findComponent(frontEndTool.getToolFrame(), DataTree.class);
rootFolder = env.getProject().getProjectData().getRootFolder();
Program p = createDefaultProgram("p1", ProgramBuilder._TOY, this);
rootFolder.createFile("notepad", p, TaskMonitorAdapter.DUMMY_MONITOR);
p.release(this);
p = createDefaultProgram("p2", ProgramBuilder._TOY, this);
rootFolder.createFile("X07", p, TaskMonitorAdapter.DUMMY_MONITOR);
p.release(this);
rootNode = tree.getRootNode();
expandPath(rootNode.getTreePath());
}
@After
public void tearDown() throws Exception {
env.dispose();
}
@Test
public void testRenameFolder() throws Exception {
rootFolder.createFolder("myFolder");
waitForSwing();
final GTreeNode myNode = rootNode.getChild("myFolder");
setSelectionPath(myNode.getTreePath());
DockingActionIf renameAction = getAction("Rename");
performAction(renameAction, getDomainFileActionContext(), true);
waitForTree();
// select "Rename" action
SwingUtilities.invokeAndWait(() -> {
int row = tree.getRowForPath(myNode.getTreePath());
JTree jTree = (JTree) getInstanceField("tree", tree);
DefaultTreeCellEditor cellEditor = (DefaultTreeCellEditor) tree.getCellEditor();
Container container = (Container) cellEditor.getTreeCellEditorComponent(jTree, myNode,
true, true, false, row);
JTextField textField = (JTextField) container.getComponent(0);
textField.setText("MyNewFolder");
tree.stopEditing();
});
waitForSwing();
assertNotNull(rootNode.getChild("MyNewFolder"));
assertNull(rootNode.getChild("myFolder"));
}
@Test
public void testRenameFile() throws Exception {
final GTreeNode npNode = rootNode.getChild("notepad");
setSelectionPath(npNode.getTreePath());
DockingActionIf renameAction = getAction("Rename");
performAction(renameAction, getDomainFileActionContext(), true);
waitForTree();
// select "Rename" action
SwingUtilities.invokeAndWait(() -> {
int row = tree.getRowForPath(npNode.getTreePath());
DefaultTreeCellEditor cellEditor = (DefaultTreeCellEditor) tree.getCellEditor();
JTree jTree = (JTree) getInstanceField("tree", tree);
Container container = (Container) cellEditor.getTreeCellEditorComponent(jTree, npNode,
true, true, false, row);
JTextField textField = (JTextField) container.getComponent(0);
textField.setText("My_notepad");
tree.stopEditing();
});
waitForSwing();
assertNotNull(rootNode.getChild("My_notepad"));
assertNull(rootNode.getChild("notepad"));
}
@Test
public void testRenameFileInUse() throws Exception {
final GTreeNode npNode = rootNode.getChild("notepad");
DomainFile df = ((DomainFileNode) npNode).getDomainFile();
setInUse(df);
setSelectionPath(npNode.getTreePath());
DockingActionIf renameAction = getAction("Rename");
executeOnSwingWithoutBlocking(
() -> performAction(renameAction, getDomainFileActionContext(), true));
waitForSwing();
OptionDialog dlg = waitForDialogComponent(OptionDialog.class);
assertEquals("Rename Not Allowed", dlg.getTitle());
pressButtonByText(dlg.getComponent(), "OK");
assertNotNull(rootNode.getChild("notepad"));
}
private void setInUse(DomainFile df) throws Exception {
setInUse(df, "/notepad");
}
private void setInUse(DomainFile df, final String path) throws Exception {
ProgramDB program = createDefaultProgram("test1", ProgramBuilder._TOY, this);
//
// Unusual Code Alert!
// We are calling an internal method to trigger the 'in use' state, as it is much
// faster to do this than it is to open a program in a tool!
//
//@formatter:off
Object projectFileManager = getInstanceField("fileManager", df);
invokeInstanceMethod("setDomainObject", projectFileManager,
new Class[] { String.class, DomainObjectAdapter.class },
new Object[] { path, program }
);
//@formatter:on
}
@Test
public void testRenameFolderInUse() throws Exception {
// folder contains a file that is in use
DomainFolder f = rootFolder.createFolder("myFolder");
f = f.createFolder("A");
f = f.createFolder("B");
f = f.createFolder("C");
Program p = createDefaultProgram("new", ProgramBuilder._TOY, this);
DomainFile df = f.createFile("notepad", p, TaskMonitorAdapter.DUMMY_MONITOR);
waitForSwing();
final GTreeNode myNode = rootNode.getChild("myFolder");
((DomainFolderNode) myNode).getDomainFolder().createFile("notepad", p,
TaskMonitorAdapter.DUMMY_MONITOR);
p.release(this);
waitForSwing();
tree.expandPath(myNode.getTreePath());
assertNotNull(myNode.getChild("notepad"));
setInUse(df, "/myFolder/notepad");
setSelectionPath(myNode.getTreePath());
final DockingActionIf renameAction = getAction("Rename");
performAction(renameAction, getDomainFileActionContext(), true);
waitForTree();
// attempt to rename "myFolder"
SwingUtilities.invokeLater(() -> {
int row = tree.getRowForPath(myNode.getTreePath());
DefaultTreeCellEditor cellEditor = (DefaultTreeCellEditor) tree.getCellEditor();
JTree jTree = (JTree) getInstanceField("tree", tree);
Container container = (Container) cellEditor.getTreeCellEditorComponent(jTree, myNode,
true, true, false, row);
JTextField textField = (JTextField) container.getComponent(0);
textField.setText("My_Newfolder");
tree.stopEditing();
});
waitForSwing();
OptionDialog d =
waitForDialogComponent(frontEndTool.getToolFrame(), OptionDialog.class, 2000);
assertNotNull(d);
assertEquals("Rename Failed", d.getTitle());
pressButtonByText(d.getComponent(), "OK");
assertNotNull(rootNode.getChild("myFolder"));
}
@Test
public void testExpandAll() throws Exception {
DomainFolder f = rootFolder.createFolder("myFolder");
f = f.createFolder("A");
f = f.createFolder("B");
f = f.createFolder("C");
waitForSwing();
GTreeNode myNode = rootNode.getChild("myFolder");
setSelectionPath(rootNode.getTreePath());
DockingActionIf expandAction = getAction("Expand All");
performAction(expandAction, getDomainFileActionContext(), true);
GTreeNode aNode = myNode.getChild("A");
assertNotNull(aNode);
GTreeNode bNode = aNode.getChild("B");
assertNotNull(bNode);
GTreeNode cNode = bNode.getChild("C");
assertNotNull(cNode);
}
@Test
public void testCollapseAll() throws Exception {
DomainFolder f = rootFolder.createFolder("myFolder");
f = f.createFolder("A");
f = f.createFolder("B");
f = f.createFolder("C");
waitForSwing();
GTreeNode myNode = rootNode.getChild("myFolder");
setSelectionPath(myNode.getTreePath());
DockingActionIf expandAction = getAction("Expand All");
performAction(expandAction, getDomainFileActionContext(), true);
waitForTree();
DockingActionIf collapseAction = getAction("Collapse All");
performAction(collapseAction, getDomainFileActionContext(), true);
waitForTree();
assertTrue(!tree.isExpanded(myNode.getTreePath()));
GTreeNode aNode = myNode.getChild("A");
assertTrue(!tree.isExpanded(aNode.getTreePath()));
GTreeNode bNode = aNode.getChild("B");
assertTrue(!tree.isExpanded(bNode.getTreePath()));
GTreeNode cNode = bNode.getChild("C");
assertNotNull(cNode);
assertTrue(!tree.isExpanded(cNode.getTreePath()));
}
@Test
public void testSelectAll() throws Exception {
DomainFolder f = rootFolder.createFolder("myFolder");
f = f.createFolder("A");
f = f.createFolder("B");
f = f.createFolder("C");
waitForSwing();
setSelectionPath(rootNode.getTreePath());
DockingActionIf selectAction = getAction("Select All");
performAction(selectAction, getDomainFileActionContext(), true);
waitForTree();
BreadthFirstIterator it = new BreadthFirstIterator(tree, rootNode);
while (it.hasNext()) {
GTreeNode node = it.next();
assertTrue(tree.isPathSelected(node.getTreePath()));
}
}
@Test
public void testSetReadOnly() throws Exception {
GTreeNode npNode = rootNode.getChild("notepad");
setSelectionPath(npNode.getTreePath());
ToggleDockingAction readOnlyAction = (ToggleDockingAction) getAction("Read-Only");
readOnlyAction.setSelected(true);
performAction(readOnlyAction, getDomainFileActionContext(), true);
assertTrue(((DomainFileNode) npNode).getDomainFile().isReadOnly());
ImageIcon icon = ResourceManager.loadImage("fileIcons/ProgramReadOnly.gif");
icon = ResourceManager.getScaledIcon(icon, 16, 16);
assertTrue(npNode.getIcon(false) instanceof MultiIcon);
}
@Test
public void testSetReadOnlyInUse() throws Exception {
GTreeNode npNode = rootNode.getChild("notepad");
DomainFile df = ((DomainFileNode) npNode).getDomainFile();
setInUse(df);
setSelectionPath(npNode.getTreePath());
ToggleDockingAction readOnlyAction = (ToggleDockingAction) getAction("Read-Only");
readOnlyAction.setSelected(true);
performAction(readOnlyAction, getDomainFileActionContext(), true);
assertTrue(((DomainFileNode) npNode).getDomainFile().isReadOnly());
}
//==================================================================================================
// Private Methods
//==================================================================================================
private ActionContext getDomainFileActionContext() {
List<DomainFile> fileList = new ArrayList<>();
List<DomainFolder> folderList = new ArrayList<>();
TreePath[] paths = tree.getSelectionPaths();
for (TreePath path : paths) {
GTreeNode node = (GTreeNode) path.getLastPathComponent();
if (node instanceof DomainFileNode) {
fileList.add(((DomainFileNode) node).getDomainFile());
}
else if (node instanceof DomainFolderNode) {
folderList.add(((DomainFolderNode) node).getDomainFolder());
}
}
return new ProjectDataTreeActionContext(null, null, paths, folderList, fileList, tree,
true);
}
private DockingActionIf getAction(String actionName) {
DockingActionIf action =
AbstractDockingTest.getAction(frontEndTool, "FrontEndPlugin", actionName);
return action;
}
private void setSelectionPath(final TreePath path) throws Exception {
tree.setSelectionPath(path);
waitForTree();
}
private void expandPath(TreePath treePath) {
tree.expandPath(treePath);
waitForTree();
}
private void waitForTree() {
waitForSwing();
while (tree.isBusy()) {
try {
Thread.sleep(10);
}
catch (InterruptedException e) {
// try again
}
}
waitForSwing();
}
}

View File

@ -30,12 +30,12 @@ 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;
import docking.widgets.tree.support.GTreeDragNDropHandler;
import docking.widgets.tree.support.GTreeNodeTransferable;
import docking.widgets.tree.support.*;
import ghidra.framework.data.DomainObjectAdapter;
import ghidra.framework.main.FrontEndTool;
import ghidra.framework.model.DomainFile;
@ -46,11 +46,13 @@ import ghidra.program.model.listing.Program;
import ghidra.test.AbstractGhidraHeadedIntegrationTest;
import ghidra.test.TestEnv;
import ghidra.util.task.TaskMonitor;
import resources.MultiIcon;
import resources.ResourceManager;
/**
* Tests for actions in the front end (Ghidra project window).
* Tests for actions in the front end (Ghidra project window)
*/
public class ActionManager1Test extends AbstractGhidraHeadedIntegrationTest {
public class FrontEndPluginActionsTest extends AbstractGhidraHeadedIntegrationTest {
private FrontEndTool frontEndTool;
private TestEnv env;
@ -58,10 +60,6 @@ public class ActionManager1Test extends AbstractGhidraHeadedIntegrationTest {
private DomainFolder rootFolder;
private GTreeRootNode rootNode;
public ActionManager1Test() {
super();
}
@Before
public void setUp() throws Exception {
@ -533,10 +531,237 @@ public class ActionManager1Test extends AbstractGhidraHeadedIntegrationTest {
assertNull(getChild(rootNode, "tms"));
}
@Test
public void testRenameFolder() throws Exception {
rootFolder.createFolder("myFolder");
waitForSwing();
final GTreeNode myNode = rootNode.getChild("myFolder");
setSelectionPath(myNode.getTreePath());
DockingActionIf renameAction = getAction("Rename");
performAction(renameAction, getDomainFileActionContext(), true);
waitForTree();
// select "Rename" action
SwingUtilities.invokeAndWait(() -> {
int row = tree.getRowForPath(myNode.getTreePath());
JTree jTree = (JTree) getInstanceField("tree", tree);
DefaultTreeCellEditor cellEditor = (DefaultTreeCellEditor) tree.getCellEditor();
Container container = (Container) cellEditor.getTreeCellEditorComponent(jTree, myNode,
true, true, false, row);
JTextField textField = (JTextField) container.getComponent(0);
textField.setText("MyNewFolder");
tree.stopEditing();
});
waitForSwing();
assertNotNull(rootNode.getChild("MyNewFolder"));
assertNull(rootNode.getChild("myFolder"));
}
@Test
public void testRenameFile() throws Exception {
final GTreeNode npNode = rootNode.getChild("notepad");
setSelectionPath(npNode.getTreePath());
DockingActionIf renameAction = getAction("Rename");
performAction(renameAction, getDomainFileActionContext(), true);
waitForTree();
// select "Rename" action
SwingUtilities.invokeAndWait(() -> {
int row = tree.getRowForPath(npNode.getTreePath());
DefaultTreeCellEditor cellEditor = (DefaultTreeCellEditor) tree.getCellEditor();
JTree jTree = (JTree) getInstanceField("tree", tree);
Container container = (Container) cellEditor.getTreeCellEditorComponent(jTree, npNode,
true, true, false, row);
JTextField textField = (JTextField) container.getComponent(0);
textField.setText("My_notepad");
tree.stopEditing();
});
waitForSwing();
assertNotNull(rootNode.getChild("My_notepad"));
assertNull(rootNode.getChild("notepad"));
}
@Test
public void testRenameFileInUse() throws Exception {
final GTreeNode npNode = rootNode.getChild("notepad");
DomainFile df = ((DomainFileNode) npNode).getDomainFile();
setInUse(df);
setSelectionPath(npNode.getTreePath());
DockingActionIf renameAction = getAction("Rename");
executeOnSwingWithoutBlocking(
() -> performAction(renameAction, getDomainFileActionContext(), true));
waitForSwing();
OptionDialog dlg = waitForDialogComponent(OptionDialog.class);
assertEquals("Rename Not Allowed", dlg.getTitle());
pressButtonByText(dlg.getComponent(), "OK");
assertNotNull(rootNode.getChild("notepad"));
}
@Test
public void testRenameFolderInUse() throws Exception {
// folder contains a file that is in use
DomainFolder f = rootFolder.createFolder("myFolder");
f = f.createFolder("A");
f = f.createFolder("B");
f = f.createFolder("C");
Program p = createDefaultProgram("new", ProgramBuilder._TOY, this);
DomainFile df = f.createFile("notepad", p, TaskMonitor.DUMMY);
waitForSwing();
final GTreeNode myNode = rootNode.getChild("myFolder");
((DomainFolderNode) myNode).getDomainFolder().createFile("notepad", p, TaskMonitor.DUMMY);
p.release(this);
waitForSwing();
tree.expandPath(myNode.getTreePath());
assertNotNull(myNode.getChild("notepad"));
setInUse(df, "/myFolder/notepad");
setSelectionPath(myNode.getTreePath());
final DockingActionIf renameAction = getAction("Rename");
performAction(renameAction, getDomainFileActionContext(), true);
waitForTree();
// attempt to rename "myFolder"
SwingUtilities.invokeLater(() -> {
int row = tree.getRowForPath(myNode.getTreePath());
DefaultTreeCellEditor cellEditor = (DefaultTreeCellEditor) tree.getCellEditor();
JTree jTree = (JTree) getInstanceField("tree", tree);
Container container = (Container) cellEditor.getTreeCellEditorComponent(jTree, myNode,
true, true, false, row);
JTextField textField = (JTextField) container.getComponent(0);
textField.setText("My_Newfolder");
tree.stopEditing();
});
waitForSwing();
OptionDialog d = waitForDialogComponent(OptionDialog.class);
assertNotNull(d);
assertEquals("Rename Failed", d.getTitle());
pressButtonByText(d.getComponent(), "OK");
assertNotNull(rootNode.getChild("myFolder"));
}
@Test
public void testExpandAll() throws Exception {
DomainFolder f = rootFolder.createFolder("myFolder");
f = f.createFolder("A");
f = f.createFolder("B");
f = f.createFolder("C");
waitForSwing();
GTreeNode myNode = rootNode.getChild("myFolder");
setSelectionPath(rootNode.getTreePath());
DockingActionIf expandAction = getAction("Expand All");
performAction(expandAction, getDomainFileActionContext(), true);
GTreeNode aNode = myNode.getChild("A");
assertNotNull(aNode);
GTreeNode bNode = aNode.getChild("B");
assertNotNull(bNode);
GTreeNode cNode = bNode.getChild("C");
assertNotNull(cNode);
}
@Test
public void testCollapseAll() throws Exception {
DomainFolder f = rootFolder.createFolder("myFolder");
f = f.createFolder("A");
f = f.createFolder("B");
f = f.createFolder("C");
waitForSwing();
GTreeNode myNode = rootNode.getChild("myFolder");
setSelectionPath(myNode.getTreePath());
DockingActionIf expandAction = getAction("Expand All");
performAction(expandAction, getDomainFileActionContext(), true);
waitForTree();
DockingActionIf collapseAction = getAction("Collapse All");
performAction(collapseAction, getDomainFileActionContext(), true);
waitForTree();
assertTrue(!tree.isExpanded(myNode.getTreePath()));
GTreeNode aNode = myNode.getChild("A");
assertTrue(!tree.isExpanded(aNode.getTreePath()));
GTreeNode bNode = aNode.getChild("B");
assertTrue(!tree.isExpanded(bNode.getTreePath()));
GTreeNode cNode = bNode.getChild("C");
assertNotNull(cNode);
assertTrue(!tree.isExpanded(cNode.getTreePath()));
}
@Test
public void testSelectAll() throws Exception {
DomainFolder f = rootFolder.createFolder("myFolder");
f = f.createFolder("A");
f = f.createFolder("B");
f = f.createFolder("C");
waitForSwing();
setSelectionPath(rootNode.getTreePath());
DockingActionIf selectAction = getAction("Select All");
performAction(selectAction, getDomainFileActionContext(), true);
waitForTree();
BreadthFirstIterator it = new BreadthFirstIterator(tree, rootNode);
while (it.hasNext()) {
GTreeNode node = it.next();
assertTrue(tree.isPathSelected(node.getTreePath()));
}
}
@Test
public void testSetReadOnly() throws Exception {
GTreeNode npNode = rootNode.getChild("notepad");
setSelectionPath(npNode.getTreePath());
ToggleDockingAction readOnlyAction = (ToggleDockingAction) getAction("Read-Only");
readOnlyAction.setSelected(true);
performAction(readOnlyAction, getDomainFileActionContext(), true);
assertTrue(((DomainFileNode) npNode).getDomainFile().isReadOnly());
ImageIcon icon = ResourceManager.loadImage("fileIcons/ProgramReadOnly.gif");
icon = ResourceManager.getScaledIcon(icon, 16, 16);
assertTrue(npNode.getIcon(false) instanceof MultiIcon);
}
@Test
public void testSetReadOnlyInUse() throws Exception {
GTreeNode npNode = rootNode.getChild("notepad");
DomainFile df = ((DomainFileNode) npNode).getDomainFile();
setInUse(df);
setSelectionPath(npNode.getTreePath());
ToggleDockingAction readOnlyAction = (ToggleDockingAction) getAction("Read-Only");
readOnlyAction.setSelected(true);
performAction(readOnlyAction, getDomainFileActionContext(), true);
assertTrue(((DomainFileNode) npNode).getDomainFile().isReadOnly());
}
//==================================================================================================
// Private Methods
//==================================================================================================
private void setSelectionPath(final TreePath path) throws Exception {
tree.setSelectionPath(path);
waitForTree();
}
private void pressDelete() {
DockingActionIf deleteAction = getAction("Delete");
performAction(deleteAction, getDomainFileActionContext(), false);

View File

@ -43,6 +43,11 @@ public class DummyToolActions implements DockingToolActions {
// stub
}
@Override
public DockingActionIf getLocalAction(ComponentProvider provider, String actionName) {
return null;
}
@Override
public Set<DockingActionIf> getActions(String owner) {
return null;
@ -62,5 +67,4 @@ public class DummyToolActions implements DockingToolActions {
public void removeActions(ComponentProvider provider) {
// stub
}
}

View File

@ -26,7 +26,7 @@
</COMPONENT_NODE>
</SPLIT_NODE>
<COMPONENT_NODE TOP_INFO="0">
<COMPONENT_INFO NAME="ConsolePlugin" OWNER="ConsolePlugin" TITLE="Console" ACTIVE="false" GROUP="Default" INSTANCE_ID="2999653489311119719" />
<COMPONENT_INFO NAME="Console" OWNER="ConsolePlugin" TITLE="Console" ACTIVE="false" GROUP="Default" INSTANCE_ID="2999653489311119719" />
</COMPONENT_NODE>
</SPLIT_NODE>
<SPLIT_NODE WIDTH="996" HEIGHT="491" DIVIDER_LOCATION="622" ORIENTATION="HORIZONTAL">

View File

@ -27,7 +27,7 @@ import org.junit.*;
import com.google.common.cache.*;
import docking.action.DockingAction;
import docking.ComponentProvider;
import generic.test.TestUtils;
import ghidra.app.decompiler.DecompileResults;
import ghidra.app.plugin.core.codebrowser.CodeBrowserPlugin;
@ -201,10 +201,8 @@ public class DecompilerCachingTest extends AbstractGhidraHeadedIntegrationTest {
}
private void showDecompilerProvider() {
DockingAction showDecompileAction =
(DockingAction) TestUtils.getInstanceField("decompileAction", decompilePlugin);
performAction(showDecompileAction, true);
ComponentProvider decompiler = tool.getComponentProvider("Decompiler");
tool.showComponentProvider(decompiler, true);
decompilerProvider = waitForComponentProvider(DecompilerProvider.class);
}

View File

@ -15,7 +15,7 @@
*/
package ghidra.app.plugin.core.functiongraph;
import static ghidra.graph.viewer.GraphViewerUtils.*;
import static ghidra.graph.viewer.GraphViewerUtils.getGraphScale;
import static org.junit.Assert.*;
import java.awt.*;
@ -552,9 +552,9 @@ public abstract class AbstractFunctionGraphTest extends AbstractGhidraHeadedInte
}
protected void showFunctionGraphProvider() {
DockingAction showGraphAction =
(DockingAction) TestUtils.getInstanceField("showFunctionGraphAction", graphPlugin);
performAction(showGraphAction, true);
ComponentProvider provider = tool.getComponentProvider("Function Graph");
tool.showComponentProvider(provider, true);
graphProvider = waitForComponentProvider(FGProvider.class);
assertNotNull("Graph not shown", graphProvider);

View File

@ -51,7 +51,7 @@ class DiffActionManager {
static final String IGNORE_DIFFS_NEXT_ACTION = "Ignore Selection and Goto Next Difference";
static final String NEXT_DIFF_ACTION = "Next Difference";
static final String PREVIOUS_DIFF_ACTION = "Previous Difference";
static final String DIFF_DETAILS_ACTION = "Diff Location Details";
static final String DIFF_DETAILS_ACTION = "Show Diff Location Details";
static final String SHOW_DIFF_SETTINGS_ACTION = "Show Diff Apply Settings";
static final String GET_DIFFS_ACTION = "Get Differences";
static final String SELECT_ALL_DIFFS_ACTION = "Select All Differences";

View File

@ -665,7 +665,7 @@ public class DiffTest extends DiffTestAdapter {
checkDiffAction("Ignore Selection and Goto Next Difference", true, false);
checkDiffAction("Next Difference", true, true);
checkDiffAction("Previous Difference", true, false);
checkDiffAction("Diff Location Details", true, true);
checkDiffAction("Show Diff Location Details", true, true);
checkDiffAction("Show Diff Apply Settings", true, true);
checkDiffAction("Get Differences", true, true);
checkDiffAction("Select All Differences", true, true);
@ -699,7 +699,7 @@ public class DiffTest extends DiffTestAdapter {
checkDiffAction("Ignore Selection and Goto Next Difference", false, false);
checkDiffAction("Next Difference", false, false);
checkDiffAction("Previous Difference", false, false);
checkDiffAction("Diff Location Details", false, false);
checkDiffAction("Show Diff Location Details", false, false);
checkDiffAction("Show Diff Apply Settings", false, false);
checkDiffAction("Get Differences", false, false);
checkDiffAction("Select All Differences", false, false);
@ -715,7 +715,7 @@ public class DiffTest extends DiffTestAdapter {
checkDiffAction("Ignore Selection and Goto Next Difference", false, false);
checkDiffAction("Next Difference", false, false);
checkDiffAction("Previous Difference", false, false);
checkDiffAction("Diff Location Details", false, false);
checkDiffAction("Show Diff Location Details", false, false);
checkDiffAction("Show Diff Apply Settings", false, false);
checkDiffAction("Get Differences", false, false);
checkDiffAction("Select All Differences", false, false);
@ -732,7 +732,7 @@ public class DiffTest extends DiffTestAdapter {
checkDiffAction("Ignore Selection and Goto Next Difference", true, false);
checkDiffAction("Next Difference", true, true);
checkDiffAction("Previous Difference", true, true);
checkDiffAction("Diff Location Details", true, true);
checkDiffAction("Show Diff Location Details", true, true);
checkDiffAction("Show Diff Apply Settings", true, true);
checkDiffAction("Get Differences", true, true);
checkDiffAction("Select All Differences", true, true);

View File

@ -67,6 +67,7 @@ public abstract class AbstractDockingTool implements DockingTool {
@Override
public void removeComponentProvider(ComponentProvider provider) {
Runnable r = () -> {
toolActions.removeGlobalAction(provider.getShowProviderAction());
toolActions.removeActions(provider);
winMgr.removeComponent(provider);
};

View File

@ -168,7 +168,8 @@ class DockableToolBarManager {
private DockableComponent dockableComponent;
ToolBarCloseAction(DockableComponent dockableComponent) {
super("Close Window", DockingWindowManager.DOCKING_WINDOWS_OWNER);
super("Close Window", DockingWindowManager.DOCKING_WINDOWS_OWNER,
KeyBindingType.UNSUPPORTED);
this.dockableComponent = dockableComponent;
setDescription("Close Window");
setToolBarData(new ToolBarData(closeIcon, null));

View File

@ -47,16 +47,14 @@ import util.CollectionUtils;
* Manages the "Docking" arrangement of a set of components and actions. The components can be "docked"
* together or exist in their own window. Actions can be associated with components so they
* "move" with the component as it moved from one location to another.
*
* <P>
* Components are added via ComponentProviders. A ComponentProvider is an interface for getting
* a component and its related information. The docking window manager will get the component
* from the provider as needed. It is up to the provider if it wants to reuse the component or
* recreate a new one when the component is requested. When the user "hides" (by using
* the x button on the component area) a component, the docking window manager removes all
* recreate a new one when the component is requested. When the user hides a component (by using
* the x button on the component header), the docking window manager removes all
* knowledge of the component and will request it again from the provider if the component
* becomes "unhidden". The provider is also notified whenever a component is hidden. Some
* providers will use the notification to remove the provider from the docking window manager so
* that the can not "unhide" the component using the built-in window menu.
* is again shown. The provider is also notified whenever a component is hidden and shown.
*/
public class DockingWindowManager implements PropertyChangeListener, PlaceholderInstaller {
@ -712,8 +710,11 @@ public class DockingWindowManager implements PropertyChangeListener, Placeholder
ComponentPlaceholder placeholder = getActivePlaceholder(provider);
if (placeholder != null) {
showComponent(placeholder, visibleState, true);
return;
}
else {
if (visibleState) {
// a null placeholder implies the client is trying to show a provider that has not
// been added to the tool
Msg.warn(this, "Attempting to show an unknown Component Provider '" +

View File

@ -76,11 +76,7 @@ class ShowComponentAction extends DockingAction implements Comparable<ShowCompon
// keybinding data used to show the binding in the menu
ComponentProvider provider = placeholder.getProvider();
DockingActionIf action = provider.getShowProviderAction();
KeyBindingData kbData = action.getKeyBindingData();
if (kbData != null) {
setKeyBindingData(kbData);
}
synchronizeKeyBinding(provider);
// Use provider Help for this action
HelpLocation helpLocation = provider.getHelpLocation();
@ -94,6 +90,21 @@ class ShowComponentAction extends DockingAction implements Comparable<ShowCompon
}
}
/**
* Ensures that the given provider's key binding matches this class's key binding
* @param provider the provider
*/
private void synchronizeKeyBinding(ComponentProvider provider) {
DockingActionIf action = provider.getShowProviderAction();
KeyBindingData defaultBinding = action.getDefaultKeyBindingData();
setKeyBindingData(defaultBinding);
KeyBindingData kbData = action.getKeyBindingData();
if (kbData != null) {
setUnvalidatedKeyBindingData(kbData);
}
}
private static KeyBindingType createKeyBindingType(boolean isTransient,
ComponentPlaceholder placeholder) {

View File

@ -55,6 +55,16 @@ public interface DockingActionIf extends HelpDescriptor {
*/
public String getOwner();
/**
* Returns a description of this actions owner. For most actions this will return the
* same value as {@link #getOwner()}.
*
* @return the description
*/
public default String getOwnerDescription() {
return getOwner();
}
/**
* Returns a short description of this action. Generally used for a tooltip
* @return the description

View File

@ -39,7 +39,7 @@ public class KeyBindingsManager implements PropertyChangeListener {
actionToProviderMap = new HashMap<>();
}
public void addAction(DockingActionIf action, ComponentProvider optionalProvider) {
public void addAction(ComponentProvider optionalProvider, DockingActionIf action) {
action.addPropertyChangeListener(this);
if (optionalProvider != null) {
actionToProviderMap.put(action, optionalProvider);
@ -48,7 +48,7 @@ public class KeyBindingsManager implements PropertyChangeListener {
KeyStroke keyBinding = action.getKeyBinding();
if (keyBinding != null) {
addKeyBinding(action, optionalProvider, keyBinding);
addKeyBinding(optionalProvider, action, keyBinding);
}
}
@ -67,7 +67,7 @@ public class KeyBindingsManager implements PropertyChangeListener {
removeKeyBinding(action.getKeyBinding(), action);
}
private void addKeyBinding(DockingActionIf action, ComponentProvider provider,
private void addKeyBinding(ComponentProvider provider, DockingActionIf action,
KeyStroke keyStroke) {
if (ReservedKeyBindings.isReservedKeystroke(keyStroke)) {
throw new AssertException("Cannot assign action to a reserved keystroke. " +
@ -145,7 +145,7 @@ public class KeyBindingsManager implements PropertyChangeListener {
if (newKeyData != null) {
KeyStroke ks = newKeyData.getKeyBinding();
if (ks != null) {
addKeyBinding(action, actionToProviderMap.get(action), ks);
addKeyBinding(actionToProviderMap.get(action), action, ks);
}
}
}

View File

@ -63,6 +63,7 @@ public class MultipleKeyAction extends DockingKeyBindingAction {
throw new IllegalArgumentException(
"KeyStrokes don't match - was: " + keyStroke + " new: " + keyBinding);
}
actions.add(new ActionData(action, provider));
}
@ -273,5 +274,10 @@ public class MultipleKeyAction extends DockingKeyBindingAction {
boolean isMyProvider(ComponentProvider otherProvider) {
return provider == otherProvider;
}
@Override
public String toString() {
return provider.toString() + " - " + action;
}
}
}

View File

@ -34,6 +34,15 @@ public interface DockingToolActions {
*/
public void addLocalAction(ComponentProvider provider, DockingActionIf action);
/**
* Gets the provider action by the given name
*
* @param provider the provider
* @param actionName the action name
* @return the action
*/
public DockingActionIf getLocalAction(ComponentProvider provider, String actionName);
/**
* Removes the given provider's local action
*

View File

@ -155,6 +155,7 @@ public class KeyEntryDialog extends DialogComponentProvider {
KeyStroke existingKeyStroke = action.getKeyBinding();
if (Objects.equals(existingKeyStroke, newKeyStroke)) {
setStatusText("Key binding unchanged");
return;
}
@ -177,11 +178,18 @@ public class KeyEntryDialog extends DialogComponentProvider {
}
private void updateCollisionPane(KeyStroke ks) {
clearStatusText();
collisionPane.setText("");
if (ks == null) {
return;
}
KeyStroke existingKeyStroke = action.getKeyBinding();
if (Objects.equals(existingKeyStroke, ks)) {
setStatusText("Key binding unchanged");
return;
}
List<DockingActionIf> list = getManagedActionsForKeyStroke(ks);
if (list.size() == 0) {
return;
@ -193,7 +201,7 @@ public class KeyEntryDialog extends DialogComponentProvider {
for (int i = 0; i < list.size(); i++) {
DockingActionIf a = list.get(i);
String collisionStr = "\t" + a.getName() + " (" + a.getOwner() + ")\n";
String collisionStr = "\t" + a.getName() + " (" + a.getOwnerDescription() + ")\n";
int offset = doc.getLength();
doc.insertString(offset, collisionStr, textAttrSet);
doc.setParagraphAttributes(offset, 1, tabAttrSet, false);
@ -211,6 +219,7 @@ public class KeyEntryDialog extends DialogComponentProvider {
if (multiAction == null) {
return Collections.emptyList();
}
List<DockingActionIf> list = multiAction.getActions();
Map<String, DockingActionIf> nameMap = new HashMap<>(list.size());

View File

@ -85,13 +85,14 @@ public class SharedStubKeyBindingAction extends DockingAction implements Options
updateActionKeyStrokeFromOptions(action, defaultKs);
}
public String getOwnersDescription() {
@Override
public String getOwnerDescription() {
List<String> owners = getDistinctOwners();
Collections.sort(owners);
if (owners.size() == 1) {
return owners.get(0);
}
return '(' + StringUtils.join(owners, ", ") + ')';
return StringUtils.join(owners, ", ");
}
private List<String> getDistinctOwners() {
@ -99,6 +100,11 @@ public class SharedStubKeyBindingAction extends DockingAction implements Options
Set<DockingActionIf> actions = clientActions.keySet();
for (DockingActionIf action : actions) {
String owner = action.getOwner();
if (DockingWindowManager.DOCKING_WINDOWS_OWNER.equals(owner)) {
// special case: this is the owner for special system-level actions
continue;
}
if (!results.contains(owner)) {
results.add(owner);
}
@ -139,12 +145,16 @@ public class SharedStubKeyBindingAction extends DockingAction implements Options
private void updateActionKeyStrokeFromOptions(DockingActionIf action, KeyStroke defaultKs) {
KeyStroke stubKs = defaultKs;
KeyStroke optionsKs = getKeyStrokeFromOptions(defaultKs);
if (!Objects.equals(defaultKs, optionsKs)) {
// we use the 'unvalidated' call since this value is provided by the user--we assume
// that user input is correct; we only validate programmer input
action.setUnvalidatedKeyBindingData(new KeyBindingData(optionsKs));
stubKs = optionsKs;
}
setUnvalidatedKeyBindingData(new KeyBindingData(stubKs));
}
private KeyStroke getKeyStrokeFromOptions(KeyStroke validatedKeyStroke) {

View File

@ -115,27 +115,21 @@ public class ToolActions implements DockingToolActions, PropertyChangeListener {
action.addPropertyChangeListener(this);
addActionToMap(action);
setKeyBindingOption(action);
keyBindingsManager.addAction(action, provider);
initializeKeyBinding(provider, action);
actionGuiHelper.addLocalAction(provider, action);
}
/**
* Adds the action to the tool.
* @param action the action to be added.
*/
@Override
public synchronized void addGlobalAction(DockingActionIf action) {
checkForAlreadyAddedAction(null, action);
action.addPropertyChangeListener(this);
addActionToMap(action);
setKeyBindingOption(action);
keyBindingsManager.addAction(action, null);
initializeKeyBinding(null, action);
actionGuiHelper.addToolAction(action);
}
private void setKeyBindingOption(DockingActionIf action) {
private void initializeKeyBinding(ComponentProvider provider, DockingActionIf action) {
KeyBindingType type = action.getKeyBindingType();
if (!type.supportsKeyBindings()) {
@ -143,7 +137,7 @@ public class ToolActions implements DockingToolActions, PropertyChangeListener {
}
if (type.isShared()) {
installSharedKeyBinding(action);
installSharedKeyBinding(provider, action);
return;
}
@ -154,9 +148,11 @@ public class ToolActions implements DockingToolActions, PropertyChangeListener {
if (!Objects.equals(ks, newKs)) {
action.setUnvalidatedKeyBindingData(new KeyBindingData(newKs));
}
keyBindingsManager.addAction(provider, action);
}
private void installSharedKeyBinding(DockingActionIf action) {
private void installSharedKeyBinding(ComponentProvider provider, DockingActionIf action) {
String name = action.getName();
KeyStroke defaultKeyStroke = action.getKeyBinding();
@ -172,6 +168,9 @@ public class ToolActions implements DockingToolActions, PropertyChangeListener {
});
stub.addClientAction(action);
// note: only put the stub in the manager, not the actual action
keyBindingsManager.addAction(provider, stub);
}
/**
@ -318,10 +317,12 @@ public class ToolActions implements DockingToolActions, PropertyChangeListener {
for (DockingActionIf action : set) {
removeLocalAction(provider, action);
}
}
private void removeAction(DockingActionIf action) {
keyBindingsManager.removeAction(action);
getActionStorage(action).remove(action);
if (!action.getKeyBindingType().isShared()) {
return;
@ -370,6 +371,19 @@ public class ToolActions implements DockingToolActions, PropertyChangeListener {
}
}
@Override
public DockingActionIf getLocalAction(ComponentProvider provider, String actionName) {
Iterator<DockingActionIf> it = actionGuiHelper.getComponentActions(provider);
while (it.hasNext()) {
DockingActionIf action = it.next();
if (action.getName().equals(actionName)) {
return action;
}
}
return null;
}
public Action getAction(KeyStroke ks) {
return keyBindingsManager.getDockingKeyAction(ks);
}

View File

@ -43,6 +43,7 @@ import com.google.common.collect.Sets;
import docking.*;
import docking.action.DockingActionIf;
import docking.action.ToggleDockingActionIf;
import docking.actions.DockingToolActions;
import docking.dnd.GClipboard;
import docking.framework.DockingApplicationConfiguration;
import docking.menu.DockingToolbarButton;
@ -1195,8 +1196,18 @@ public abstract class AbstractDockingTest extends AbstractGenericTest {
return CollectionUtils.any(actions);
}
/**
* Returns the action by the given name that belongs to the given provider
*
* @param provider the provider
* @param actionName the action name
* @return the action
*/
public static DockingActionIf getLocalAction(ComponentProvider provider, String actionName) {
return getAction(provider.getTool(), provider.getName(), actionName);
DockingTool tool = provider.getTool();
DockingToolActions toolActions = tool.getToolActions();
DockingActionIf action = toolActions.getLocalAction(provider, actionName);
return action;
}
/**
@ -1850,10 +1861,12 @@ public abstract class AbstractDockingTest extends AbstractGenericTest {
*
* @param tool the tool in which the provider lives
* @param name the name of the provider to show
* @return the newly shown provider
*/
public void showProvider(DockingTool tool, String name) {
public ComponentProvider showProvider(DockingTool tool, String name) {
ComponentProvider provider = tool.getComponentProvider(name);
tool.showComponentProvider(provider, true);
return provider;
}
/**

View File

@ -32,7 +32,6 @@ import docking.KeyEntryTextField;
import docking.action.DockingActionIf;
import docking.action.KeyBindingData;
import docking.actions.KeyBindingUtils;
import docking.actions.SharedStubKeyBindingAction;
import docking.tool.util.DockingToolConstants;
import docking.widgets.MultiLineLabel;
import docking.widgets.OptionDialog;
@ -708,18 +707,11 @@ public class KeyBindingsPanel extends JPanel {
}
return "";
case PLUGIN_NAME:
return getOwner(action);
return action.getOwnerDescription();
}
return "Unknown Column!";
}
private String getOwner(DockingActionIf action) {
if (action instanceof SharedStubKeyBindingAction) {
return ((SharedStubKeyBindingAction) action).getOwnersDescription();
}
return action.getOwner();
}
@Override
public List<DockingActionIf> getModelData() {
return tableActions;