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
@@ -1,6 +1,5 @@
/* ### /* ###
* IP: GHIDRA * IP: GHIDRA
* REVIEWED: YES
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@@ -23,20 +22,18 @@ import ghidra.program.model.address.AddressSetView;
import ghidra.program.model.listing.Function; import ghidra.program.model.listing.Function;
import ghidra.program.model.listing.FunctionIterator; import ghidra.program.model.listing.FunctionIterator;
public class DeleteFunctionDefaultPlates extends GhidraScript { public class DeleteFunctionDefaultPlatesScript extends GhidraScript {
private static String DEFAULT_PLATE = " FUNCTION"; private static String DEFAULT_PLATE = " FUNCTION";
/* (non-Javadoc)
* @see ghidra.app.script.GhidraScript#run()
*/
@Override @Override
public void run() throws Exception { public void run() throws Exception {
AddressSetView set = currentProgram.getMemory(); AddressSetView set = currentProgram.getMemory();
if (currentSelection != null && !currentSelection.isEmpty()) { if (currentSelection != null && !currentSelection.isEmpty()) {
set = currentSelection; set = currentSelection;
} }
int updateCount=0; int updateCount = 0;
FunctionIterator iter = currentProgram.getFunctionManager().getFunctions(set, true); FunctionIterator iter = currentProgram.getFunctionManager().getFunctions(set, true);
while (iter.hasNext()) { while (iter.hasNext()) {
Function function = iter.next(); Function function = iter.next();
@@ -47,7 +44,7 @@ public class DeleteFunctionDefaultPlates extends GhidraScript {
} }
} }
if (updateCount > 0) { if (updateCount > 0) {
String cmt = updateCount > 1? "comments" : "comment"; String cmt = updateCount > 1 ? "comments" : "comment";
println("Removed " + updateCount + " default plate " + cmt + "."); println("Removed " + updateCount + " default plate " + cmt + ".");
} }
else { else {
@@ -148,6 +148,14 @@ public class CallTreePlugin extends ProgramPlugin {
tool.showComponentProvider(provider, true); tool.showComponentProvider(provider, true);
} }
CallTreeProvider getPrimaryProvider() {
return primaryProvider;
}
DockingAction getShowCallTreeFromMenuAction() {
return showCallTreeFromMenuAction;
}
ProgramLocation getCurrentLocation() { ProgramLocation getCurrentLocation() {
return currentLocation; return currentLocation;
} }
@@ -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 // changes, which means we will get here while setting the location, but our program
// will have been null'ed out. // will have been null'ed out.
currentProgram = plugin.getCurrentProgram(); currentProgram = plugin.getCurrentProgram();
currentProgram.addListener(this);
} }
Function function = plugin.getFunction(location); Function function = plugin.getFunction(location);
@@ -915,18 +915,13 @@ public class CodeBrowserPlugin extends Plugin
} }
}; };
// note: this action gets added later when the TableService is added
tableFromSelectionAction.setEnabled(false); tableFromSelectionAction.setEnabled(false);
tableFromSelectionAction.setMenuBarData(new MenuData( tableFromSelectionAction.setMenuBarData(new MenuData(
new String[] { ToolConstants.MENU_SELECTION, "Create Table From Selection" }, null, new String[] { ToolConstants.MENU_SELECTION, "Create Table From Selection" }, null,
"SelectUtils")); "SelectUtils"));
tableFromSelectionAction tableFromSelectionAction.setHelpLocation(
.setHelpLocation(new HelpLocation("CodeBrowserPlugin", "Selection_Table")); 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);
}
} }
private GhidraProgramTableModel<Address> createTableModel(CodeUnitIterator iterator, 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, public boolean goToField(Address a, String fieldName, int occurrence, int row, int col,
boolean scroll) { boolean scroll) {
boolean result = SystemUtilities boolean result = SystemUtilities.runSwingNow(
.runSwingNow(() -> doGoToField(a, fieldName, occurrence, row, col, scroll)); () -> doGoToField(a, fieldName, occurrence, row, col, scroll));
return result; return result;
} }
@@ -36,7 +36,6 @@ import docking.widgets.fieldpanel.FieldPanel;
import docking.widgets.fieldpanel.HoverHandler; import docking.widgets.fieldpanel.HoverHandler;
import docking.widgets.fieldpanel.internal.FieldPanelCoordinator; import docking.widgets.fieldpanel.internal.FieldPanelCoordinator;
import docking.widgets.fieldpanel.support.*; import docking.widgets.fieldpanel.support.*;
import ghidra.GhidraOptions;
import ghidra.app.nav.*; import ghidra.app.nav.*;
import ghidra.app.plugin.core.clipboard.CodeBrowserClipboardProvider; import ghidra.app.plugin.core.clipboard.CodeBrowserClipboardProvider;
import ghidra.app.plugin.core.codebrowser.actions.*; 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 TITLE = "Listing: ";
private static final String OPERAND_OPTIONS_PREFIX = GhidraOptions.OPERAND_GROUP_TITLE + ".";
private static final Icon LISTING_FORMAT_EXPAND_ICON = private static final Icon LISTING_FORMAT_EXPAND_ICON =
ResourceManager.loadImage("images/field.header.down.png"); ResourceManager.loadImage("images/field.header.down.png");
private static final Icon LISTING_FORMAT_COLLAPSE_ICON = private static final Icon LISTING_FORMAT_COLLAPSE_ICON =
@@ -93,9 +90,6 @@ public class CodeViewerProvider extends NavigatableComponentProviderAdapter
private ProgramDropProvider curDropProvider; private ProgramDropProvider curDropProvider;
private ToggleDockingAction toggleHoverAction; private ToggleDockingAction toggleHoverAction;
//TODO - Need to improve CodeUnit.getRepresentation format options interface before adding this
//TODO private ToggleOperandMarkupAction[] toggleOperandMarkupActions;
private ProgramLocation currentLocation; private ProgramLocation currentLocation;
private ListingPanel otherPanel; private ListingPanel otherPanel;
@@ -976,9 +970,9 @@ public class CodeViewerProvider extends NavigatableComponentProviderAdapter
} }
} }
class ToggleHoverAction extends ToggleDockingAction { private class ToggleHoverAction extends ToggleDockingAction {
ToggleHoverAction() { ToggleHoverAction() {
super("Toggle Mouse Hover Popups", CodeViewerProvider.this.getName()); super("Toggle Mouse Hover Popups", CodeViewerProvider.this.getOwner());
setEnabled(true); setEnabled(true);
setToolBarData(new ToolBarData(HOVER_ON_ICON, "yyyz")); setToolBarData(new ToolBarData(HOVER_ON_ICON, "yyyz"));
setSelected(true); 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 * A class that allows clients to install transient highlighters while keeping the
* middle-mouse highlighting on at the same time. * middle-mouse highlighting on at the same time.
@@ -39,7 +39,7 @@ public class CollapseAllDataAction extends ProgramLocationContextAction {
private CodeViewerProvider provider; private CodeViewerProvider provider;
public CollapseAllDataAction(CodeViewerProvider provider) { public CollapseAllDataAction(CodeViewerProvider provider) {
super("Collapse All Data", provider.getName()); super("Collapse All Data", provider.getOwner());
this.provider = provider; this.provider = provider;
setPopupMenuData(new MenuData(new String[] { "Collapse All Data" }, null, "Structure")); setPopupMenuData(new MenuData(new String[] { "Collapse All Data" }, null, "Structure"));
@@ -95,8 +95,7 @@ public class CollapseAllDataAction extends ProgramLocationContextAction {
ProgramLocation location = context.getLocation(); ProgramLocation location = context.getLocation();
Data data = getTopLevelComponentData(location); Data data = getTopLevelComponentData(location);
TaskLauncher.launchModal("Collapse Data", TaskLauncher.launchModal("Collapse Data", monitor -> model.closeAllData(data, monitor));
monitor -> model.closeAllData(data, monitor));
} }
private ListingModel getModel() { private ListingModel getModel() {
@@ -36,7 +36,7 @@ public class ExpandAllDataAction extends ProgramLocationContextAction {
private CodeViewerProvider provider; private CodeViewerProvider provider;
public ExpandAllDataAction(CodeViewerProvider provider) { public ExpandAllDataAction(CodeViewerProvider provider) {
super("Expand All Data", provider.getName()); super("Expand All Data", provider.getOwner());
this.provider = provider; this.provider = provider;
setPopupMenuData(new MenuData(new String[] { "Expand All Data" }, null, "Structure")); setPopupMenuData(new MenuData(new String[] { "Expand All Data" }, null, "Structure"));
@@ -39,7 +39,7 @@ public class ToggleExpandCollapseDataAction extends ProgramLocationContextAction
private CodeViewerProvider provider; private CodeViewerProvider provider;
public ToggleExpandCollapseDataAction(CodeViewerProvider provider) { public ToggleExpandCollapseDataAction(CodeViewerProvider provider) {
super("Toggle Expand/Collapse Data", provider.getName()); super("Toggle Expand/Collapse Data", provider.getOwner());
this.provider = provider; this.provider = provider;
setPopupMenuData( setPopupMenuData(
@@ -466,7 +466,6 @@ class GhidraScriptActionManager {
if (action == null) { if (action == null) {
action = new ScriptAction(plugin, script); action = new ScriptAction(plugin, script);
actionMap.put(script, action); actionMap.put(script, action);
plugin.getTool().addAction(action);
} }
return action; return action;
} }
@@ -347,7 +347,7 @@ public class SymbolTablePlugin extends Plugin implements DomainObjectListener {
private void createSymActions() { private void createSymActions() {
String popupGroup = "1"; String popupGroup = "1";
openRefsAction = new DockingAction("Symbol References", getName()) { openRefsAction = new DockingAction("Symbol References", getName(), KeyBindingType.SHARED) {
@Override @Override
public void actionPerformed(ActionContext context) { public void actionPerformed(ActionContext context) {
refProvider.open(); refProvider.open();
@@ -359,7 +359,7 @@ public class SymbolTablePlugin extends Plugin implements DomainObjectListener {
new MenuData(new String[] { "Symbol References" }, icon, popupGroup)); new MenuData(new String[] { "Symbol References" }, icon, popupGroup));
openRefsAction.setToolBarData(new ToolBarData(icon)); openRefsAction.setToolBarData(new ToolBarData(icon));
openRefsAction.setDescription("Symbol References"); openRefsAction.setDescription("Display Symbol References");
tool.addLocalAction(symProvider, openRefsAction); tool.addLocalAction(symProvider, openRefsAction);
deleteAction = new DockingAction("Delete Symbols", getName()) { deleteAction = new DockingAction("Delete Symbols", getName()) {
@@ -62,7 +62,7 @@ public interface PluginConstants {
*/ */
char ANYSINGLECHAR_WILDCARD_CHAR = '?'; char ANYSINGLECHAR_WILDCARD_CHAR = '?';
String CODE_BROWSER = "CodeBrowserPlugin"; String CODE_BROWSER = "Listing";
String MEMORY_MAP = "Memory Map"; String MEMORY_MAP = "Memory Map";
String BYTE_VIEWER = "ByteViewerPlugin"; String BYTE_VIEWER = "ByteViewerPlugin";
String BOOKMARKS = "Bookmarks"; String BOOKMARKS = "Bookmarks";
@@ -159,6 +159,25 @@ public class ComponentProviderActionsTest extends AbstractGhidraHeadedIntegratio
assertMenuItemHasKeyStroke(newKs); 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 @Test
public void testSetKeyBinding_ViaOptions_WithoutToolbarAction() { 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 // Private Methods
//================================================================================================== //==================================================================================================
@@ -279,7 +306,7 @@ public class ComponentProviderActionsTest extends AbstractGhidraHeadedIntegratio
.stream() .stream()
.filter(a -> a.getOwner().equals(DockingWindowManager.DOCKING_WINDOWS_OWNER)) .filter(a -> a.getOwner().equals(DockingWindowManager.DOCKING_WINDOWS_OWNER))
.findFirst() .findFirst()
.get() .orElseGet(() -> null)
; ;
//@formatter:on //@formatter:on
}); });
@@ -310,7 +337,7 @@ public class ComponentProviderActionsTest extends AbstractGhidraHeadedIntegratio
} }
private void assertNoToolbarAction() { private void assertNoToolbarAction() {
assertNotNull("No toolbar action found for provider", getToolbarShowProviderAction()); assertNull("No toolbar action found for provider", getToolbarShowProviderAction());
} }
private void assertToolbarAction() { private void assertToolbarAction() {
@@ -341,6 +368,13 @@ public class ComponentProviderActionsTest extends AbstractGhidraHeadedIntegratio
expected, action.getMenuBarData().getMenuIcon()); 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() { private void assertCannotShowKeyBindingDialog_FromWindowsMenu() {
// simulate the user mousing over the 'Window' menu's action // simulate the user mousing over the 'Window' menu's action
DockingActionIf windowMenuAction = getWindowMenuShowProviderAction(); DockingActionIf windowMenuAction = getWindowMenuShowProviderAction();
@@ -367,6 +401,24 @@ public class ComponentProviderActionsTest extends AbstractGhidraHeadedIntegratio
assertFalse("Invalid key stroke: " + ks, runSwing(() -> dialog.isVisible())); 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) { private void assertMenuItemHasKeyStroke(KeyStroke expected) {
DockingActionIf action = getWindowMenuShowProviderAction(); DockingActionIf action = getWindowMenuShowProviderAction();
@@ -415,6 +467,21 @@ public class ComponentProviderActionsTest extends AbstractGhidraHeadedIntegratio
public JComponent getComponent() { public JComponent getComponent() {
return component; 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;
}
} }
} }
@@ -18,6 +18,7 @@ package docking.action;
import static org.junit.Assert.*; import static org.junit.Assert.*;
import java.awt.event.KeyEvent; import java.awt.event.KeyEvent;
import java.util.Map;
import javax.swing.*; import javax.swing.*;
@@ -25,6 +26,7 @@ import org.junit.*;
import docking.*; import docking.*;
import docking.actions.KeyEntryDialog; import docking.actions.KeyEntryDialog;
import docking.actions.ToolActions;
import ghidra.app.plugin.core.codebrowser.CodeBrowserPlugin; import ghidra.app.plugin.core.codebrowser.CodeBrowserPlugin;
import ghidra.app.plugin.core.data.DataPlugin; import ghidra.app.plugin.core.data.DataPlugin;
import ghidra.app.plugin.core.function.FunctionPlugin; import ghidra.app.plugin.core.function.FunctionPlugin;
@@ -186,20 +188,26 @@ public class KeyEntryDialogTest extends AbstractGhidraHeadedIntegrationTest {
} }
public DockingAction getKeyBindingAction() { public DockingAction getKeyBindingAction() {
DockingWindowManager dwm = DockingWindowManager.getInstance(tool.getToolFrame());
ActionToGuiMapper dockingActionManager = ToolActions toolActions = tool.getToolActions();
(ActionToGuiMapper) getInstanceField("actionManager", dwm); KeyBindingsManager kbm =
return (DockingAction) getInstanceField("keyBindingsAction", dockingActionManager); (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 { private void showDialog(final DockingAction actionToEdit) throws Exception {
final DockingAction keyBindingAction = getKeyBindingAction(); DockingAction keyBindingAction = getKeyBindingAction();
executeOnSwingWithoutBlocking(() -> { executeOnSwingWithoutBlocking(() -> {
DockingWindowManager.setMouseOverAction(actionToEdit); DockingWindowManager.setMouseOverAction(actionToEdit);
performAction(keyBindingAction, false); performAction(keyBindingAction, false);
}); });
keyEntryDialog = waitForDialogComponent(tool.getToolFrame(), KeyEntryDialog.class, 2000); keyEntryDialog = waitForDialogComponent(KeyEntryDialog.class);
assertNotNull(keyEntryDialog); assertNotNull(keyEntryDialog);
collisionPane = (JTextPane) getInstanceField("collisionPane", keyEntryDialog); collisionPane = (JTextPane) getInstanceField("collisionPane", keyEntryDialog);
@@ -718,7 +718,7 @@ public class BookmarkPluginTest extends AbstractGhidraHeadedIntegrationTest {
} }
private void showBookmarkProvider() throws Exception { private void showBookmarkProvider() throws Exception {
DockingActionIf action = getAction(plugin, "Show Bookmarks"); DockingActionIf action = getAction(plugin, "Bookmarks");
performAction(action, true); performAction(action, true);
table = plugin.getBookmarkTable(); table = plugin.getBookmarkTable();
waitForTable(); waitForTable();
@@ -46,7 +46,6 @@ import ghidra.framework.plugintool.PluginTool;
import ghidra.program.database.ProgramBuilder; import ghidra.program.database.ProgramBuilder;
import ghidra.program.database.ProgramDB; import ghidra.program.database.ProgramDB;
import ghidra.program.model.address.Address; import ghidra.program.model.address.Address;
import ghidra.program.model.address.AddressFactory;
import ghidra.program.model.data.DataType; import ghidra.program.model.data.DataType;
import ghidra.program.model.data.PointerDataType; import ghidra.program.model.data.PointerDataType;
import ghidra.program.model.listing.Function; import ghidra.program.model.listing.Function;
@@ -62,7 +61,6 @@ public class CallTreePluginTest extends AbstractGhidraHeadedIntegrationTest {
private TestEnv env; private TestEnv env;
private CodeBrowserPlugin codeBrowserPlugin; private CodeBrowserPlugin codeBrowserPlugin;
private PluginTool tool; private PluginTool tool;
private ProgramDB program;
private CallTreePlugin callTreePlugin; private CallTreePlugin callTreePlugin;
private CallTreeProvider provider; private CallTreeProvider provider;
private List<CallTreeProvider> providers; private List<CallTreeProvider> providers;
@@ -70,14 +68,10 @@ public class CallTreePluginTest extends AbstractGhidraHeadedIntegrationTest {
private GTree incomingTree; private GTree incomingTree;
private GTree outgoingTree; private GTree outgoingTree;
private DockingAction showProviderAction; private ProgramBuilder builder;
private ProgramDB program;
private GoToService goToService; private GoToService goToService;
private AddressFactory addressFactory;
public CallTreePluginTest() {
super();
}
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
// cast to list // cast to list
@@ -91,7 +85,6 @@ public class CallTreePluginTest extends AbstractGhidraHeadedIntegrationTest {
callTreePlugin = env.getPlugin(CallTreePlugin.class); callTreePlugin = env.getPlugin(CallTreePlugin.class);
providers = (List<CallTreeProvider>) getInstanceField("providers", callTreePlugin); providers = (List<CallTreeProvider>) getInstanceField("providers", callTreePlugin);
showProviderAction = (DockingAction) getInstanceField("showProviderAction", callTreePlugin);
GoToServicePlugin goToPlugin = env.getPlugin(GoToServicePlugin.class); GoToServicePlugin goToPlugin = env.getPlugin(GoToServicePlugin.class);
goToService = (GoToService) invokeInstanceMethod("getGotoService", goToPlugin); goToService = (GoToService) invokeInstanceMethod("getGotoService", goToPlugin);
@@ -100,20 +93,18 @@ public class CallTreePluginTest extends AbstractGhidraHeadedIntegrationTest {
env.showTool(); env.showTool();
program = createProgram(); program = createProgram();
addressFactory = program.getAddressFactory();
ProgramManager pm = tool.getService(ProgramManager.class); ProgramManager pm = tool.getService(ProgramManager.class);
pm.openProgram(program.getDomainFile()); pm.openProgram(program.getDomainFile());
// setup a good start location // setup a good start location
goTo(addr("5000")); goTo(addr("5000"));
provider = getProvider(); provider = callTreePlugin.getPrimaryProvider();
tool.showComponentProvider(provider, true);
incomingTree = (GTree) getInstanceField("incomingTree", provider); incomingTree = (GTree) getInstanceField("incomingTree", provider);
outgoingTree = (GTree) getInstanceField("outgoingTree", provider); outgoingTree = (GTree) getInstanceField("outgoingTree", provider);
} }
ProgramBuilder builder;
private ProgramDB createProgram() throws Exception { private ProgramDB createProgram() throws Exception {
builder = new ProgramBuilder("Call Trees", ProgramBuilder._TOY); 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", assertNotNull("Provider did not update its information when made visible",
providerFunction()); providerFunction());
final ToggleDockingAction navigateIncomingLoctionsAction = ToggleDockingAction navigateIncomingLoctionsAction =
(ToggleDockingAction) getAction("Navigation Incoming Location Changes"); (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(), assertEquals("Provider's location does not match that of the listing.", currentFunction(),
providerFunction()); providerFunction());
goTo(addr("0x6000")); goTo(addr("0x6000"));
assertTrue("Provider's location matches that of the listing when not following " + assertNotEquals("Provider's location matches that of the listing when not following " +
"location changes.", !currentFunction().equals(providerFunction())); "location changes", currentFunction(), providerFunction());
performAction(navigateIncomingLoctionsAction, true); 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()); providerFunction());
} }
@@ -779,21 +770,6 @@ public class CallTreePluginTest extends AbstractGhidraHeadedIntegrationTest {
return functionManager.getFunctionAt(address); 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) { private CallTreeProvider getProvider(final String address) {
final CallTreeProvider[] providerBox = new CallTreeProvider[1]; final CallTreeProvider[] providerBox = new CallTreeProvider[1];
@@ -939,13 +915,13 @@ public class CallTreePluginTest extends AbstractGhidraHeadedIntegrationTest {
} }
private void fullyExpandIncomingNode(GTreeNode node) { 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); performAction(expandAction, new ActionContext(provider, incomingTree), false);
waitForTree(node.getTree()); waitForTree(node.getTree());
} }
private void fullyExpandOutgoingNode(GTreeNode node) { 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); performAction(expandAction, new ActionContext(provider, outgoingTree), false);
waitForTree(node.getTree()); waitForTree(node.getTree());
} }
@@ -1054,11 +1030,11 @@ public class CallTreePluginTest extends AbstractGhidraHeadedIntegrationTest {
String name = child.getName(); String name = child.getName();
Integer integer = map.get(name); Integer integer = map.get(name);
if (integer == null) { if (integer == null) {
integer = new Integer(0); integer = 0;
} }
int asInt = integer; int asInt = integer;
asInt++; asInt++;
map.put(name, new Integer(asInt)); map.put(name, asInt);
} }
return map; return map;
} }
@@ -1088,10 +1064,7 @@ public class CallTreePluginTest extends AbstractGhidraHeadedIntegrationTest {
} }
private DockingActionIf getAction(String actionName) { private DockingActionIf getAction(String actionName) {
// make sure there is a provider from which to get actions DockingActionIf action = getLocalAction(provider, actionName);
getProvider();
DockingActionIf action = getAction(tool, "CallTreePlugin", actionName);
return action; 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. * Shows and returns a provider for the specified address.
*/ */
private CallTreeProvider showProvider(String address) { private CallTreeProvider showProvider(String address) {
goTo(addr(address)); goTo(addr(address));
performAction(showProviderAction, true);
DockingAction action = callTreePlugin.getShowCallTreeFromMenuAction();
performAction(action);
return getProvider(address); return getProvider(address);
} }
@@ -61,6 +61,9 @@ public class CodeBrowserScreenMovementTest extends AbstractProgramBasedTest {
@Before @Before
public void setUp() throws Exception { 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(); initialize();
fp = codeBrowser.getFieldPanel(); fp = codeBrowser.getFieldPanel();
@@ -115,6 +118,9 @@ public class CodeBrowserScreenMovementTest extends AbstractProgramBasedTest {
@Test @Test
public void testBasicControls() throws Exception { 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(); fp = codeBrowser.getFieldPanel();
ListingPanel panel = codeBrowser.getListingPanel(); ListingPanel panel = codeBrowser.getListingPanel();
JScrollBar scrollbar = panel.getVerticalScrollBar(); JScrollBar scrollbar = panel.getVerticalScrollBar();
@@ -68,7 +68,7 @@ public class ExpandCollapseDataActionsTest extends AbstractGhidraHeadedIntegrati
pm.openProgram(program.getDomainFile()); pm.openProgram(program.getDomainFile());
addrFactory = program.getAddressFactory(); addrFactory = program.getAddressFactory();
env.showTool(); env.showTool();
provider = (CodeViewerProvider) tool.getComponentProvider("CodeBrowserPlugin"); provider = (CodeViewerProvider) tool.getComponentProvider("Listing");
listingModel = provider.getListingPanel().getListingModel(); listingModel = provider.getListingPanel().getListingModel();
CodeBrowserPlugin plugin = getPlugin(tool, CodeBrowserPlugin.class); CodeBrowserPlugin plugin = getPlugin(tool, CodeBrowserPlugin.class);
toggleExpand = getAction(plugin, "Toggle Expand/Collapse Data"); toggleExpand = getAction(plugin, "Toggle Expand/Collapse Data");
@@ -62,7 +62,7 @@ public class StructureEditorArchiveTest extends AbstractStructureEditorTest {
tool.addPlugin(DataTypeManagerPlugin.class.getName()); tool.addPlugin(DataTypeManagerPlugin.class.getName());
dtmService = tool.getService(DataTypeManagerService.class); dtmService = tool.getService(DataTypeManagerService.class);
plugin = (DataTypeManagerPlugin) dtmService; plugin = (DataTypeManagerPlugin) dtmService;
manageDts = getAction(plugin, "Data Type Manager"); manageDts = getAction(plugin, "DataTypes Provider");
DataTypesProvider dataTypesProvider = plugin.getProvider(); DataTypesProvider dataTypesProvider = plugin.getProvider();
dtTree = dataTypesProvider.getGTree(); dtTree = dataTypesProvider.getGTree();
@@ -55,14 +55,6 @@ public class ArchiveRemappedHeadedTest extends AbstractGhidraHeadedIntegrationTe
private File vs12ArchiveFile; private File vs12ArchiveFile;
private File vs9ArchiveFile; private File vs9ArchiveFile;
/**
* Constructor for ArchiveRemappedTest.
* @param testName
*/
public ArchiveRemappedHeadedTest() {
super();
}
@Before @Before
public void setUp() throws Exception { public void setUp() throws Exception {
@@ -97,10 +89,9 @@ public class ArchiveRemappedHeadedTest extends AbstractGhidraHeadedIntegrationTe
env.showTool(); env.showTool();
tool.showComponentProvider(provider, true);
waitForPostedSwingRunnables();
provider = plugin.getProvider(); provider = plugin.getProvider();
tool.showComponentProvider(provider, true);
tree = provider.getGTree(); tree = provider.getGTree();
waitForTree(tree); waitForTree(tree);
} }
@@ -87,7 +87,7 @@ public class MemoryMapPluginTest extends AbstractGhidraHeadedIntegrationTest {
@Test @Test
public void testActionEnabled() { public void testActionEnabled() {
DockingActionIf action = getAction(plugin, "View Memory Map"); DockingActionIf action = getAction(plugin, "Memory Map");
assertTrue(action.isEnabled()); assertTrue(action.isEnabled());
} }
@@ -99,7 +99,7 @@ public class MemoryMapPluginTest extends AbstractGhidraHeadedIntegrationTest {
Set<DockingActionIf> actions = getActionsByOwner(tool, plugin.getName()); Set<DockingActionIf> actions = getActionsByOwner(tool, plugin.getName());
for (DockingActionIf action : actions) { for (DockingActionIf action : actions) {
if (action.getName().equals("Add Block") || action.getName().equals("Set Image Base") || if (action.getName().equals("Add Block") || action.getName().equals("Set Image Base") ||
action.getName().equals("View Memory Map")) { action.getName().equals("Memory Map")) {
assertTrue(action.isEnabledForContext(provider.getActionContext(null))); assertTrue(action.isEnabledForContext(provider.getActionContext(null)));
} }
else { else {
@@ -116,7 +116,7 @@ public class MemoryMapPluginTest extends AbstractGhidraHeadedIntegrationTest {
assertEquals(0, table.getModel().getRowCount()); assertEquals(0, table.getModel().getRowCount());
Set<DockingActionIf> actions = getActionsByOwner(tool, plugin.getName()); Set<DockingActionIf> actions = getActionsByOwner(tool, plugin.getName());
for (DockingActionIf action : actions) { for (DockingActionIf action : actions) {
if (!action.getName().equals("View Memory Map")) { if (!action.getName().equals("Memory Map")) {
assertTrue(!action.isEnabledForContext(provider.getActionContext(null))); assertTrue(!action.isEnabledForContext(provider.getActionContext(null)));
} }
} }
@@ -297,7 +297,7 @@ public class MemoryMapPluginTest extends AbstractGhidraHeadedIntegrationTest {
///////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////
private void showProvider() { private void showProvider() {
DockingActionIf action = getAction(plugin, "View Memory Map"); DockingActionIf action = getAction(plugin, "Memory Map");
performAction(action, true); performAction(action, true);
provider = plugin.getMemoryMapProvider(); provider = plugin.getMemoryMapProvider();
} }
@@ -137,7 +137,7 @@ public class MemoryMapProvider1Test extends AbstractGhidraHeadedIntegrationTest
String name = action.getName(); String name = action.getName();
if (name.equals("Add Block") || name.equals("Merge Blocks") || if (name.equals("Add Block") || name.equals("Merge Blocks") ||
name.equals("Delete Block") || name.equals("Set Image Base") || name.equals("Delete Block") || name.equals("Set Image Base") ||
name.equals("View Memory Map")) { name.equals("Memory Map")) {
assertTrue(action.isEnabled()); assertTrue(action.isEnabled());
} }
else { else {
@@ -667,7 +667,7 @@ public class MemoryMapProvider1Test extends AbstractGhidraHeadedIntegrationTest
///////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////
private void showProvider() { private void showProvider() {
DockingActionIf action = getAction(plugin, "View Memory Map"); DockingActionIf action = getAction(plugin, "Memory Map");
performAction(action, true); performAction(action, true);
waitForPostedSwingRunnables(); waitForPostedSwingRunnables();
provider = plugin.getMemoryMapProvider(); provider = plugin.getMemoryMapProvider();
@@ -1332,7 +1332,7 @@ public class MemoryMapProvider2Test extends AbstractGhidraHeadedIntegrationTest
/////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////
private void showProvider() { private void showProvider() {
DockingActionIf action = getAction(plugin, "View Memory Map"); DockingActionIf action = getAction(plugin, "Memory Map");
performAction(action, true); performAction(action, true);
provider = plugin.getMemoryMapProvider(); provider = plugin.getMemoryMapProvider();
table = provider.getTable(); table = provider.getTable();
@@ -886,7 +886,7 @@ public class MemoryMapProvider3Test extends AbstractGhidraHeadedIntegrationTest
/////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////
private void showProvider() { private void showProvider() {
DockingActionIf action = getAction(plugin, "View Memory Map"); DockingActionIf action = getAction(plugin, "Memory Map");
performAction(action, true); performAction(action, true);
waitForPostedSwingRunnables(); waitForPostedSwingRunnables();
provider = plugin.getMemoryMapProvider(); provider = plugin.getMemoryMapProvider();
@@ -54,10 +54,6 @@ public class MemoryMapProvider4Test extends AbstractGhidraHeadedIntegrationTest
private JTable table; private JTable table;
private TableModel model; private TableModel model;
public MemoryMapProvider4Test() {
super();
}
private Program buildProgram(String programName) throws Exception { private Program buildProgram(String programName) throws Exception {
ProgramBuilder builder = new ProgramBuilder(programName, ProgramBuilder._TOY); ProgramBuilder builder = new ProgramBuilder(programName, ProgramBuilder._TOY);
builder.createMemory(".text", Long.toHexString(0x1001000), 0x6600); builder.createMemory(".text", Long.toHexString(0x1001000), 0x6600);
@@ -247,7 +243,7 @@ public class MemoryMapProvider4Test extends AbstractGhidraHeadedIntegrationTest
} }
private void showProvider() { private void showProvider() {
DockingActionIf action = getAction(plugin, "View Memory Map"); DockingActionIf action = getAction(plugin, "Memory Map");
performAction(action, true); performAction(action, true);
waitForPostedSwingRunnables(); waitForPostedSwingRunnables();
provider = plugin.getMemoryMapProvider(); provider = plugin.getMemoryMapProvider();
@@ -71,8 +71,7 @@ public class NextPrevAddressPluginTest extends AbstractGhidraHeadedIntegrationTe
NextPrevAddressPlugin plugin = env.getPlugin(NextPrevAddressPlugin.class); NextPrevAddressPlugin plugin = env.getPlugin(NextPrevAddressPlugin.class);
previousAction = previousAction =
(MultiActionDockingAction) TestUtils.getInstanceField("previousAction", plugin); (MultiActionDockingAction) TestUtils.getInstanceField("previousAction", plugin);
nextAction = nextAction = (MultiActionDockingAction) TestUtils.getInstanceField("nextAction", plugin);
(MultiActionDockingAction) TestUtils.getInstanceField("nextAction", plugin);
GoToAddressLabelPlugin goToPlugin = env.getPlugin(GoToAddressLabelPlugin.class); GoToAddressLabelPlugin goToPlugin = env.getPlugin(GoToAddressLabelPlugin.class);
dialog = goToPlugin.getDialog(); dialog = goToPlugin.getDialog();
@@ -355,9 +354,9 @@ public class NextPrevAddressPluginTest extends AbstractGhidraHeadedIntegrationTe
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
// let caution fly // let caution fly
private JButton findButtonForAction(DockingWindowManager windowManager, DockingAction action) { private JButton findButtonForAction(DockingWindowManager windowManager, DockingAction action) {
Object actionManager = TestUtils.getInstanceField("actionManager", windowManager); Object actionToGuiMapper = TestUtils.getInstanceField("actionToGuiMapper", windowManager);
Object menuAndToolBarManager = Object menuAndToolBarManager =
TestUtils.getInstanceField("menuAndToolBarManager", actionManager); TestUtils.getInstanceField("menuAndToolBarManager", actionToGuiMapper);
Map<WindowNode, WindowActionManager> map = Map<WindowNode, WindowActionManager> map =
(Map<WindowNode, WindowActionManager>) TestUtils.getInstanceField( (Map<WindowNode, WindowActionManager>) TestUtils.getInstanceField(
"windowToActionManagerMap", menuAndToolBarManager); "windowToActionManagerMap", menuAndToolBarManager);
@@ -37,12 +37,9 @@ import ghidra.program.util.ProgramSelection;
import ghidra.test.*; 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 TestEnv env;
private PluginTool tool; private PluginTool tool;
@@ -50,13 +47,6 @@ public class DeleteFunctionDefaultPlatesTest extends AbstractGhidraHeadedIntegra
private File script; private File script;
private ToyProgramBuilder builder; private ToyProgramBuilder builder;
public DeleteFunctionDefaultPlatesTest() {
super();
}
/*
* @see TestCase#setUp()
*/
@Before @Before
public void setUp() throws Exception { public void setUp() throws Exception {
env = new TestEnv(); env = new TestEnv();
@@ -71,11 +61,8 @@ public class DeleteFunctionDefaultPlatesTest extends AbstractGhidraHeadedIntegra
ProgramManager pm = tool.getService(ProgramManager.class); ProgramManager pm = tool.getService(ProgramManager.class);
pm.openProgram(program.getDomainFile()); pm.openProgram(program.getDomainFile());
//script =
// new File(Application.getApplicationRootDirectory().getFile(),
// "Features/Base/ghidra_scripts/DeleteFunctionDefaultPlates.java");
script = Application.getModuleFile("Base", script = Application.getModuleFile("Base",
"ghidra_scripts/DeleteFunctionDefaultPlates.java").getFile(true); "ghidra_scripts/DeleteFunctionDefaultPlatesScript.java").getFile(true);
env.showTool(); env.showTool();
} }
@@ -97,9 +84,6 @@ public class DeleteFunctionDefaultPlatesTest extends AbstractGhidraHeadedIntegra
return builder.getProgram(); return builder.getProgram();
} }
/*
* @see TestCase#tearDown()
*/
@After @After
public void tearDown() throws Exception { public void tearDown() throws Exception {
env.dispose(); env.dispose();
@@ -90,7 +90,7 @@ public class SymbolTreePlugin1Test extends AbstractGhidraHeadedIntegrationTest {
tool.addPlugin(SymbolTreePlugin.class.getName()); tool.addPlugin(SymbolTreePlugin.class.getName());
plugin = env.getPlugin(SymbolTreePlugin.class); plugin = env.getPlugin(SymbolTreePlugin.class);
symTreeAction = getAction(plugin, "Display Symbol Tree"); symTreeAction = getAction(plugin, "Symbol Tree");
cbPlugin = env.getPlugin(CodeBrowserPlugin.class); cbPlugin = env.getPlugin(CodeBrowserPlugin.class);
util = new SymbolTreeTestUtils(plugin); util = new SymbolTreeTestUtils(plugin);
@@ -107,15 +107,6 @@ public class SymbolTreePlugin1Test extends AbstractGhidraHeadedIntegrationTest {
env.dispose(); env.dispose();
} }
@Test
public void testActionEnabled() {
assertTrue(symTreeAction.isEnabledForContext(null));
util.openProgram();
assertTrue(symTreeAction.isEnabledForContext(null));
}
@Test @Test
public void testShowDisplay() throws Exception { public void testShowDisplay() throws Exception {
showSymbolTree(); showSymbolTree();
@@ -90,14 +90,14 @@ class SymbolTreeTestUtils {
this.plugin = plugin; this.plugin = plugin;
this.program = buildProgram(); this.program = buildProgram();
symTreeAction = getAction(plugin, "Display Symbol Tree"); symTreeAction = getAction(plugin, "Symbol Tree");
} }
SymbolTreeTestUtils(SymbolTreePlugin plugin, Program program) { SymbolTreeTestUtils(SymbolTreePlugin plugin, Program program) {
this.plugin = plugin; this.plugin = plugin;
this.program = program; this.program = program;
symTreeAction = getAction(plugin, "Display Symbol Tree"); symTreeAction = getAction(plugin, "Symbol Tree");
} }
public static Program buildProgram() throws Exception { public static Program buildProgram() throws Exception {
@@ -21,6 +21,7 @@ import java.awt.*;
import java.awt.event.*; import java.awt.event.*;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.Set;
import java.util.function.BiConsumer; import java.util.function.BiConsumer;
import javax.swing.*; import javax.swing.*;
@@ -59,6 +60,7 @@ import ghidra.util.table.GhidraTableFilterPanel;
import ghidra.util.table.ProgramTableModel; import ghidra.util.table.ProgramTableModel;
import ghidra.util.table.field.AddressBasedLocation; import ghidra.util.table.field.AddressBasedLocation;
import ghidra.util.xml.XmlUtilities; import ghidra.util.xml.XmlUtilities;
import util.CollectionUtils;
public class SymbolTablePluginTest extends AbstractGhidraHeadedIntegrationTest { public class SymbolTablePluginTest extends AbstractGhidraHeadedIntegrationTest {
@@ -93,8 +95,14 @@ public class SymbolTablePluginTest extends AbstractGhidraHeadedIntegrationTest {
plugin = env.getPlugin(SymbolTablePlugin.class); plugin = env.getPlugin(SymbolTablePlugin.class);
provider = (SymbolProvider) getInstanceField("symProvider", plugin); provider = (SymbolProvider) getInstanceField("symProvider", plugin);
viewSymAction = getAction(plugin, "View Symbol Table"); viewSymAction = getAction(plugin, "Symbol Table");
viewRefAction = getAction(plugin, "View Symbol References");
// 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"); deleteAction = getAction(plugin, "Delete Symbols");
makeSelectionAction = getAction(plugin, "Make Selection"); makeSelectionAction = getAction(plugin, "Make Selection");
setFilterAction = getAction(plugin, "Set Filter"); setFilterAction = getAction(plugin, "Set Filter");
@@ -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();
}
}
@@ -30,12 +30,12 @@ import org.junit.*;
import docking.ActionContext; import docking.ActionContext;
import docking.action.DockingActionIf; import docking.action.DockingActionIf;
import docking.action.ToggleDockingAction;
import docking.test.AbstractDockingTest; import docking.test.AbstractDockingTest;
import docking.widgets.OptionDialog; import docking.widgets.OptionDialog;
import docking.widgets.tree.GTreeNode; import docking.widgets.tree.GTreeNode;
import docking.widgets.tree.GTreeRootNode; import docking.widgets.tree.GTreeRootNode;
import docking.widgets.tree.support.GTreeDragNDropHandler; import docking.widgets.tree.support.*;
import docking.widgets.tree.support.GTreeNodeTransferable;
import ghidra.framework.data.DomainObjectAdapter; import ghidra.framework.data.DomainObjectAdapter;
import ghidra.framework.main.FrontEndTool; import ghidra.framework.main.FrontEndTool;
import ghidra.framework.model.DomainFile; import ghidra.framework.model.DomainFile;
@@ -46,11 +46,13 @@ import ghidra.program.model.listing.Program;
import ghidra.test.AbstractGhidraHeadedIntegrationTest; import ghidra.test.AbstractGhidraHeadedIntegrationTest;
import ghidra.test.TestEnv; import ghidra.test.TestEnv;
import ghidra.util.task.TaskMonitor; 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 FrontEndTool frontEndTool;
private TestEnv env; private TestEnv env;
@@ -58,10 +60,6 @@ public class ActionManager1Test extends AbstractGhidraHeadedIntegrationTest {
private DomainFolder rootFolder; private DomainFolder rootFolder;
private GTreeRootNode rootNode; private GTreeRootNode rootNode;
public ActionManager1Test() {
super();
}
@Before @Before
public void setUp() throws Exception { public void setUp() throws Exception {
@@ -533,10 +531,237 @@ public class ActionManager1Test extends AbstractGhidraHeadedIntegrationTest {
assertNull(getChild(rootNode, "tms")); 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 Methods
//================================================================================================== //==================================================================================================
private void setSelectionPath(final TreePath path) throws Exception {
tree.setSelectionPath(path);
waitForTree();
}
private void pressDelete() { private void pressDelete() {
DockingActionIf deleteAction = getAction("Delete"); DockingActionIf deleteAction = getAction("Delete");
performAction(deleteAction, getDomainFileActionContext(), false); performAction(deleteAction, getDomainFileActionContext(), false);
@@ -43,6 +43,11 @@ public class DummyToolActions implements DockingToolActions {
// stub // stub
} }
@Override
public DockingActionIf getLocalAction(ComponentProvider provider, String actionName) {
return null;
}
@Override @Override
public Set<DockingActionIf> getActions(String owner) { public Set<DockingActionIf> getActions(String owner) {
return null; return null;
@@ -62,5 +67,4 @@ public class DummyToolActions implements DockingToolActions {
public void removeActions(ComponentProvider provider) { public void removeActions(ComponentProvider provider) {
// stub // stub
} }
} }
@@ -26,7 +26,7 @@
</COMPONENT_NODE> </COMPONENT_NODE>
</SPLIT_NODE> </SPLIT_NODE>
<COMPONENT_NODE TOP_INFO="0"> <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> </COMPONENT_NODE>
</SPLIT_NODE> </SPLIT_NODE>
<SPLIT_NODE WIDTH="996" HEIGHT="491" DIVIDER_LOCATION="622" ORIENTATION="HORIZONTAL"> <SPLIT_NODE WIDTH="996" HEIGHT="491" DIVIDER_LOCATION="622" ORIENTATION="HORIZONTAL">
@@ -27,7 +27,7 @@ import org.junit.*;
import com.google.common.cache.*; import com.google.common.cache.*;
import docking.action.DockingAction; import docking.ComponentProvider;
import generic.test.TestUtils; import generic.test.TestUtils;
import ghidra.app.decompiler.DecompileResults; import ghidra.app.decompiler.DecompileResults;
import ghidra.app.plugin.core.codebrowser.CodeBrowserPlugin; import ghidra.app.plugin.core.codebrowser.CodeBrowserPlugin;
@@ -201,10 +201,8 @@ public class DecompilerCachingTest extends AbstractGhidraHeadedIntegrationTest {
} }
private void showDecompilerProvider() { private void showDecompilerProvider() {
DockingAction showDecompileAction = ComponentProvider decompiler = tool.getComponentProvider("Decompiler");
(DockingAction) TestUtils.getInstanceField("decompileAction", decompilePlugin); tool.showComponentProvider(decompiler, true);
performAction(showDecompileAction, true);
decompilerProvider = waitForComponentProvider(DecompilerProvider.class); decompilerProvider = waitForComponentProvider(DecompilerProvider.class);
} }
@@ -15,7 +15,7 @@
*/ */
package ghidra.app.plugin.core.functiongraph; 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 static org.junit.Assert.*;
import java.awt.*; import java.awt.*;
@@ -552,9 +552,9 @@ public abstract class AbstractFunctionGraphTest extends AbstractGhidraHeadedInte
} }
protected void showFunctionGraphProvider() { protected void showFunctionGraphProvider() {
DockingAction showGraphAction =
(DockingAction) TestUtils.getInstanceField("showFunctionGraphAction", graphPlugin); ComponentProvider provider = tool.getComponentProvider("Function Graph");
performAction(showGraphAction, true); tool.showComponentProvider(provider, true);
graphProvider = waitForComponentProvider(FGProvider.class); graphProvider = waitForComponentProvider(FGProvider.class);
assertNotNull("Graph not shown", graphProvider); assertNotNull("Graph not shown", graphProvider);
@@ -51,7 +51,7 @@ class DiffActionManager {
static final String IGNORE_DIFFS_NEXT_ACTION = "Ignore Selection and Goto Next Difference"; static final String IGNORE_DIFFS_NEXT_ACTION = "Ignore Selection and Goto Next Difference";
static final String NEXT_DIFF_ACTION = "Next Difference"; static final String NEXT_DIFF_ACTION = "Next Difference";
static final String PREVIOUS_DIFF_ACTION = "Previous 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 SHOW_DIFF_SETTINGS_ACTION = "Show Diff Apply Settings";
static final String GET_DIFFS_ACTION = "Get Differences"; static final String GET_DIFFS_ACTION = "Get Differences";
static final String SELECT_ALL_DIFFS_ACTION = "Select All Differences"; static final String SELECT_ALL_DIFFS_ACTION = "Select All Differences";
@@ -665,7 +665,7 @@ public class DiffTest extends DiffTestAdapter {
checkDiffAction("Ignore Selection and Goto Next Difference", true, false); checkDiffAction("Ignore Selection and Goto Next Difference", true, false);
checkDiffAction("Next Difference", true, true); checkDiffAction("Next Difference", true, true);
checkDiffAction("Previous Difference", true, false); 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("Show Diff Apply Settings", true, true);
checkDiffAction("Get Differences", true, true); checkDiffAction("Get Differences", true, true);
checkDiffAction("Select All 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("Ignore Selection and Goto Next Difference", false, false);
checkDiffAction("Next Difference", false, false); checkDiffAction("Next Difference", false, false);
checkDiffAction("Previous 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("Show Diff Apply Settings", false, false);
checkDiffAction("Get Differences", false, false); checkDiffAction("Get Differences", false, false);
checkDiffAction("Select All 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("Ignore Selection and Goto Next Difference", false, false);
checkDiffAction("Next Difference", false, false); checkDiffAction("Next Difference", false, false);
checkDiffAction("Previous 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("Show Diff Apply Settings", false, false);
checkDiffAction("Get Differences", false, false); checkDiffAction("Get Differences", false, false);
checkDiffAction("Select All 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("Ignore Selection and Goto Next Difference", true, false);
checkDiffAction("Next Difference", true, true); checkDiffAction("Next Difference", true, true);
checkDiffAction("Previous 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("Show Diff Apply Settings", true, true);
checkDiffAction("Get Differences", true, true); checkDiffAction("Get Differences", true, true);
checkDiffAction("Select All Differences", true, true); checkDiffAction("Select All Differences", true, true);
@@ -67,6 +67,7 @@ public abstract class AbstractDockingTool implements DockingTool {
@Override @Override
public void removeComponentProvider(ComponentProvider provider) { public void removeComponentProvider(ComponentProvider provider) {
Runnable r = () -> { Runnable r = () -> {
toolActions.removeGlobalAction(provider.getShowProviderAction());
toolActions.removeActions(provider); toolActions.removeActions(provider);
winMgr.removeComponent(provider); winMgr.removeComponent(provider);
}; };
@@ -168,7 +168,8 @@ class DockableToolBarManager {
private DockableComponent dockableComponent; private DockableComponent dockableComponent;
ToolBarCloseAction(DockableComponent dockableComponent) { ToolBarCloseAction(DockableComponent dockableComponent) {
super("Close Window", DockingWindowManager.DOCKING_WINDOWS_OWNER); super("Close Window", DockingWindowManager.DOCKING_WINDOWS_OWNER,
KeyBindingType.UNSUPPORTED);
this.dockableComponent = dockableComponent; this.dockableComponent = dockableComponent;
setDescription("Close Window"); setDescription("Close Window");
setToolBarData(new ToolBarData(closeIcon, null)); setToolBarData(new ToolBarData(closeIcon, null));
@@ -47,16 +47,14 @@ import util.CollectionUtils;
* Manages the "Docking" arrangement of a set of components and actions. The components can be "docked" * 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 * 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. * "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 * 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 * 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 * 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 * recreate a new one when the component is requested. When the user hides a component (by using
* the x button on the component area) a component, the docking window manager removes all * 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 * 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 * is again shown. The provider is also notified whenever a component is hidden and shown.
* 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.
*/ */
public class DockingWindowManager implements PropertyChangeListener, PlaceholderInstaller { public class DockingWindowManager implements PropertyChangeListener, PlaceholderInstaller {
@@ -712,8 +710,11 @@ public class DockingWindowManager implements PropertyChangeListener, Placeholder
ComponentPlaceholder placeholder = getActivePlaceholder(provider); ComponentPlaceholder placeholder = getActivePlaceholder(provider);
if (placeholder != null) { if (placeholder != null) {
showComponent(placeholder, visibleState, true); showComponent(placeholder, visibleState, true);
return;
} }
else {
if (visibleState) {
// a null placeholder implies the client is trying to show a provider that has not // a null placeholder implies the client is trying to show a provider that has not
// been added to the tool // been added to the tool
Msg.warn(this, "Attempting to show an unknown Component Provider '" + Msg.warn(this, "Attempting to show an unknown Component Provider '" +
@@ -76,11 +76,7 @@ class ShowComponentAction extends DockingAction implements Comparable<ShowCompon
// keybinding data used to show the binding in the menu // keybinding data used to show the binding in the menu
ComponentProvider provider = placeholder.getProvider(); ComponentProvider provider = placeholder.getProvider();
DockingActionIf action = provider.getShowProviderAction(); synchronizeKeyBinding(provider);
KeyBindingData kbData = action.getKeyBindingData();
if (kbData != null) {
setKeyBindingData(kbData);
}
// Use provider Help for this action // Use provider Help for this action
HelpLocation helpLocation = provider.getHelpLocation(); 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, private static KeyBindingType createKeyBindingType(boolean isTransient,
ComponentPlaceholder placeholder) { ComponentPlaceholder placeholder) {
@@ -55,6 +55,16 @@ public interface DockingActionIf extends HelpDescriptor {
*/ */
public String getOwner(); 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 * Returns a short description of this action. Generally used for a tooltip
* @return the description * @return the description
@@ -39,7 +39,7 @@ public class KeyBindingsManager implements PropertyChangeListener {
actionToProviderMap = new HashMap<>(); actionToProviderMap = new HashMap<>();
} }
public void addAction(DockingActionIf action, ComponentProvider optionalProvider) { public void addAction(ComponentProvider optionalProvider, DockingActionIf action) {
action.addPropertyChangeListener(this); action.addPropertyChangeListener(this);
if (optionalProvider != null) { if (optionalProvider != null) {
actionToProviderMap.put(action, optionalProvider); actionToProviderMap.put(action, optionalProvider);
@@ -48,7 +48,7 @@ public class KeyBindingsManager implements PropertyChangeListener {
KeyStroke keyBinding = action.getKeyBinding(); KeyStroke keyBinding = action.getKeyBinding();
if (keyBinding != null) { if (keyBinding != null) {
addKeyBinding(action, optionalProvider, keyBinding); addKeyBinding(optionalProvider, action, keyBinding);
} }
} }
@@ -67,7 +67,7 @@ public class KeyBindingsManager implements PropertyChangeListener {
removeKeyBinding(action.getKeyBinding(), action); removeKeyBinding(action.getKeyBinding(), action);
} }
private void addKeyBinding(DockingActionIf action, ComponentProvider provider, private void addKeyBinding(ComponentProvider provider, DockingActionIf action,
KeyStroke keyStroke) { KeyStroke keyStroke) {
if (ReservedKeyBindings.isReservedKeystroke(keyStroke)) { if (ReservedKeyBindings.isReservedKeystroke(keyStroke)) {
throw new AssertException("Cannot assign action to a reserved keystroke. " + throw new AssertException("Cannot assign action to a reserved keystroke. " +
@@ -145,7 +145,7 @@ public class KeyBindingsManager implements PropertyChangeListener {
if (newKeyData != null) { if (newKeyData != null) {
KeyStroke ks = newKeyData.getKeyBinding(); KeyStroke ks = newKeyData.getKeyBinding();
if (ks != null) { if (ks != null) {
addKeyBinding(action, actionToProviderMap.get(action), ks); addKeyBinding(actionToProviderMap.get(action), action, ks);
} }
} }
} }
@@ -63,6 +63,7 @@ public class MultipleKeyAction extends DockingKeyBindingAction {
throw new IllegalArgumentException( throw new IllegalArgumentException(
"KeyStrokes don't match - was: " + keyStroke + " new: " + keyBinding); "KeyStrokes don't match - was: " + keyStroke + " new: " + keyBinding);
} }
actions.add(new ActionData(action, provider)); actions.add(new ActionData(action, provider));
} }
@@ -273,5 +274,10 @@ public class MultipleKeyAction extends DockingKeyBindingAction {
boolean isMyProvider(ComponentProvider otherProvider) { boolean isMyProvider(ComponentProvider otherProvider) {
return provider == otherProvider; return provider == otherProvider;
} }
@Override
public String toString() {
return provider.toString() + " - " + action;
}
} }
} }
@@ -34,6 +34,15 @@ public interface DockingToolActions {
*/ */
public void addLocalAction(ComponentProvider provider, DockingActionIf action); 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 * Removes the given provider's local action
* *
@@ -155,6 +155,7 @@ public class KeyEntryDialog extends DialogComponentProvider {
KeyStroke existingKeyStroke = action.getKeyBinding(); KeyStroke existingKeyStroke = action.getKeyBinding();
if (Objects.equals(existingKeyStroke, newKeyStroke)) { if (Objects.equals(existingKeyStroke, newKeyStroke)) {
setStatusText("Key binding unchanged");
return; return;
} }
@@ -177,11 +178,18 @@ public class KeyEntryDialog extends DialogComponentProvider {
} }
private void updateCollisionPane(KeyStroke ks) { private void updateCollisionPane(KeyStroke ks) {
clearStatusText();
collisionPane.setText(""); collisionPane.setText("");
if (ks == null) { if (ks == null) {
return; return;
} }
KeyStroke existingKeyStroke = action.getKeyBinding();
if (Objects.equals(existingKeyStroke, ks)) {
setStatusText("Key binding unchanged");
return;
}
List<DockingActionIf> list = getManagedActionsForKeyStroke(ks); List<DockingActionIf> list = getManagedActionsForKeyStroke(ks);
if (list.size() == 0) { if (list.size() == 0) {
return; return;
@@ -193,7 +201,7 @@ public class KeyEntryDialog extends DialogComponentProvider {
for (int i = 0; i < list.size(); i++) { for (int i = 0; i < list.size(); i++) {
DockingActionIf a = list.get(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(); int offset = doc.getLength();
doc.insertString(offset, collisionStr, textAttrSet); doc.insertString(offset, collisionStr, textAttrSet);
doc.setParagraphAttributes(offset, 1, tabAttrSet, false); doc.setParagraphAttributes(offset, 1, tabAttrSet, false);
@@ -211,6 +219,7 @@ public class KeyEntryDialog extends DialogComponentProvider {
if (multiAction == null) { if (multiAction == null) {
return Collections.emptyList(); return Collections.emptyList();
} }
List<DockingActionIf> list = multiAction.getActions(); List<DockingActionIf> list = multiAction.getActions();
Map<String, DockingActionIf> nameMap = new HashMap<>(list.size()); Map<String, DockingActionIf> nameMap = new HashMap<>(list.size());
@@ -85,13 +85,14 @@ public class SharedStubKeyBindingAction extends DockingAction implements Options
updateActionKeyStrokeFromOptions(action, defaultKs); updateActionKeyStrokeFromOptions(action, defaultKs);
} }
public String getOwnersDescription() { @Override
public String getOwnerDescription() {
List<String> owners = getDistinctOwners(); List<String> owners = getDistinctOwners();
Collections.sort(owners); Collections.sort(owners);
if (owners.size() == 1) { if (owners.size() == 1) {
return owners.get(0); return owners.get(0);
} }
return '(' + StringUtils.join(owners, ", ") + ')'; return StringUtils.join(owners, ", ");
} }
private List<String> getDistinctOwners() { private List<String> getDistinctOwners() {
@@ -99,6 +100,11 @@ public class SharedStubKeyBindingAction extends DockingAction implements Options
Set<DockingActionIf> actions = clientActions.keySet(); Set<DockingActionIf> actions = clientActions.keySet();
for (DockingActionIf action : actions) { for (DockingActionIf action : actions) {
String owner = action.getOwner(); 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)) { if (!results.contains(owner)) {
results.add(owner); results.add(owner);
} }
@@ -139,12 +145,16 @@ public class SharedStubKeyBindingAction extends DockingAction implements Options
private void updateActionKeyStrokeFromOptions(DockingActionIf action, KeyStroke defaultKs) { private void updateActionKeyStrokeFromOptions(DockingActionIf action, KeyStroke defaultKs) {
KeyStroke stubKs = defaultKs;
KeyStroke optionsKs = getKeyStrokeFromOptions(defaultKs); KeyStroke optionsKs = getKeyStrokeFromOptions(defaultKs);
if (!Objects.equals(defaultKs, optionsKs)) { if (!Objects.equals(defaultKs, optionsKs)) {
// we use the 'unvalidated' call since this value is provided by the user--we assume // 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 // that user input is correct; we only validate programmer input
action.setUnvalidatedKeyBindingData(new KeyBindingData(optionsKs)); action.setUnvalidatedKeyBindingData(new KeyBindingData(optionsKs));
stubKs = optionsKs;
} }
setUnvalidatedKeyBindingData(new KeyBindingData(stubKs));
} }
private KeyStroke getKeyStrokeFromOptions(KeyStroke validatedKeyStroke) { private KeyStroke getKeyStrokeFromOptions(KeyStroke validatedKeyStroke) {
@@ -115,27 +115,21 @@ public class ToolActions implements DockingToolActions, PropertyChangeListener {
action.addPropertyChangeListener(this); action.addPropertyChangeListener(this);
addActionToMap(action); addActionToMap(action);
setKeyBindingOption(action); initializeKeyBinding(provider, action);
keyBindingsManager.addAction(action, provider);
actionGuiHelper.addLocalAction(provider, action); actionGuiHelper.addLocalAction(provider, action);
} }
/**
* Adds the action to the tool.
* @param action the action to be added.
*/
@Override @Override
public synchronized void addGlobalAction(DockingActionIf action) { public synchronized void addGlobalAction(DockingActionIf action) {
checkForAlreadyAddedAction(null, action); checkForAlreadyAddedAction(null, action);
action.addPropertyChangeListener(this); action.addPropertyChangeListener(this);
addActionToMap(action); addActionToMap(action);
setKeyBindingOption(action); initializeKeyBinding(null, action);
keyBindingsManager.addAction(action, null);
actionGuiHelper.addToolAction(action); actionGuiHelper.addToolAction(action);
} }
private void setKeyBindingOption(DockingActionIf action) { private void initializeKeyBinding(ComponentProvider provider, DockingActionIf action) {
KeyBindingType type = action.getKeyBindingType(); KeyBindingType type = action.getKeyBindingType();
if (!type.supportsKeyBindings()) { if (!type.supportsKeyBindings()) {
@@ -143,7 +137,7 @@ public class ToolActions implements DockingToolActions, PropertyChangeListener {
} }
if (type.isShared()) { if (type.isShared()) {
installSharedKeyBinding(action); installSharedKeyBinding(provider, action);
return; return;
} }
@@ -154,9 +148,11 @@ public class ToolActions implements DockingToolActions, PropertyChangeListener {
if (!Objects.equals(ks, newKs)) { if (!Objects.equals(ks, newKs)) {
action.setUnvalidatedKeyBindingData(new KeyBindingData(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(); String name = action.getName();
KeyStroke defaultKeyStroke = action.getKeyBinding(); KeyStroke defaultKeyStroke = action.getKeyBinding();
@@ -172,6 +168,9 @@ public class ToolActions implements DockingToolActions, PropertyChangeListener {
}); });
stub.addClientAction(action); 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) { for (DockingActionIf action : set) {
removeLocalAction(provider, action); removeLocalAction(provider, action);
} }
} }
private void removeAction(DockingActionIf action) { private void removeAction(DockingActionIf action) {
keyBindingsManager.removeAction(action);
getActionStorage(action).remove(action); getActionStorage(action).remove(action);
if (!action.getKeyBindingType().isShared()) { if (!action.getKeyBindingType().isShared()) {
return; 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) { public Action getAction(KeyStroke ks) {
return keyBindingsManager.getDockingKeyAction(ks); return keyBindingsManager.getDockingKeyAction(ks);
} }
@@ -43,6 +43,7 @@ import com.google.common.collect.Sets;
import docking.*; import docking.*;
import docking.action.DockingActionIf; import docking.action.DockingActionIf;
import docking.action.ToggleDockingActionIf; import docking.action.ToggleDockingActionIf;
import docking.actions.DockingToolActions;
import docking.dnd.GClipboard; import docking.dnd.GClipboard;
import docking.framework.DockingApplicationConfiguration; import docking.framework.DockingApplicationConfiguration;
import docking.menu.DockingToolbarButton; import docking.menu.DockingToolbarButton;
@@ -1195,8 +1196,18 @@ public abstract class AbstractDockingTest extends AbstractGenericTest {
return CollectionUtils.any(actions); 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) { 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 tool the tool in which the provider lives
* @param name the name of the provider to show * @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); ComponentProvider provider = tool.getComponentProvider(name);
tool.showComponentProvider(provider, true); tool.showComponentProvider(provider, true);
return provider;
} }
/** /**
@@ -32,7 +32,6 @@ import docking.KeyEntryTextField;
import docking.action.DockingActionIf; import docking.action.DockingActionIf;
import docking.action.KeyBindingData; import docking.action.KeyBindingData;
import docking.actions.KeyBindingUtils; import docking.actions.KeyBindingUtils;
import docking.actions.SharedStubKeyBindingAction;
import docking.tool.util.DockingToolConstants; import docking.tool.util.DockingToolConstants;
import docking.widgets.MultiLineLabel; import docking.widgets.MultiLineLabel;
import docking.widgets.OptionDialog; import docking.widgets.OptionDialog;
@@ -708,18 +707,11 @@ public class KeyBindingsPanel extends JPanel {
} }
return ""; return "";
case PLUGIN_NAME: case PLUGIN_NAME:
return getOwner(action); return action.getOwnerDescription();
} }
return "Unknown Column!"; return "Unknown Column!";
} }
private String getOwner(DockingActionIf action) {
if (action instanceof SharedStubKeyBindingAction) {
return ((SharedStubKeyBindingAction) action).getOwnersDescription();
}
return action.getOwner();
}
@Override @Override
public List<DockingActionIf> getModelData() { public List<DockingActionIf> getModelData() {
return tableActions; return tableActions;