mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2024-11-25 21:51:47 +00:00
GT-2925 - Key Bindings - Support Window Menu Provider Key Bindings -
test and review fixes
This commit is contained in:
parent
10621008e0
commit
6015650079
@ -1,6 +1,5 @@
|
||||
/* ###
|
||||
* IP: GHIDRA
|
||||
* REVIEWED: YES
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@ -23,20 +22,18 @@ import ghidra.program.model.address.AddressSetView;
|
||||
import ghidra.program.model.listing.Function;
|
||||
import ghidra.program.model.listing.FunctionIterator;
|
||||
|
||||
public class DeleteFunctionDefaultPlates extends GhidraScript {
|
||||
public class DeleteFunctionDefaultPlatesScript extends GhidraScript {
|
||||
|
||||
private static String DEFAULT_PLATE = " FUNCTION";
|
||||
/* (non-Javadoc)
|
||||
* @see ghidra.app.script.GhidraScript#run()
|
||||
*/
|
||||
|
||||
@Override
|
||||
public void run() throws Exception {
|
||||
public void run() throws Exception {
|
||||
|
||||
AddressSetView set = currentProgram.getMemory();
|
||||
if (currentSelection != null && !currentSelection.isEmpty()) {
|
||||
set = currentSelection;
|
||||
}
|
||||
int updateCount=0;
|
||||
int updateCount = 0;
|
||||
FunctionIterator iter = currentProgram.getFunctionManager().getFunctions(set, true);
|
||||
while (iter.hasNext()) {
|
||||
Function function = iter.next();
|
||||
@ -47,7 +44,7 @@ public class DeleteFunctionDefaultPlates extends GhidraScript {
|
||||
}
|
||||
}
|
||||
if (updateCount > 0) {
|
||||
String cmt = updateCount > 1? "comments" : "comment";
|
||||
String cmt = updateCount > 1 ? "comments" : "comment";
|
||||
println("Removed " + updateCount + " default plate " + cmt + ".");
|
||||
}
|
||||
else {
|
@ -148,6 +148,14 @@ public class CallTreePlugin extends ProgramPlugin {
|
||||
tool.showComponentProvider(provider, true);
|
||||
}
|
||||
|
||||
CallTreeProvider getPrimaryProvider() {
|
||||
return primaryProvider;
|
||||
}
|
||||
|
||||
DockingAction getShowCallTreeFromMenuAction() {
|
||||
return showCallTreeFromMenuAction;
|
||||
}
|
||||
|
||||
ProgramLocation getCurrentLocation() {
|
||||
return currentLocation;
|
||||
}
|
||||
|
@ -876,6 +876,7 @@ public class CallTreeProvider extends ComponentProviderAdapter implements Domain
|
||||
// changes, which means we will get here while setting the location, but our program
|
||||
// will have been null'ed out.
|
||||
currentProgram = plugin.getCurrentProgram();
|
||||
currentProgram.addListener(this);
|
||||
}
|
||||
|
||||
Function function = plugin.getFunction(location);
|
||||
|
@ -915,18 +915,13 @@ public class CodeBrowserPlugin extends Plugin
|
||||
}
|
||||
};
|
||||
|
||||
// note: this action gets added later when the TableService is added
|
||||
tableFromSelectionAction.setEnabled(false);
|
||||
tableFromSelectionAction.setMenuBarData(new MenuData(
|
||||
new String[] { ToolConstants.MENU_SELECTION, "Create Table From Selection" }, null,
|
||||
"SelectUtils"));
|
||||
tableFromSelectionAction
|
||||
.setHelpLocation(new HelpLocation("CodeBrowserPlugin", "Selection_Table"));
|
||||
|
||||
// don't add the actions initially if the service isn't there
|
||||
TableService tableService = tool.getService(TableService.class);
|
||||
if (tableService != null) {
|
||||
tool.addAction(tableFromSelectionAction);
|
||||
}
|
||||
tableFromSelectionAction.setHelpLocation(
|
||||
new HelpLocation("CodeBrowserPlugin", "Selection_Table"));
|
||||
}
|
||||
|
||||
private GhidraProgramTableModel<Address> createTableModel(CodeUnitIterator iterator,
|
||||
@ -1001,8 +996,8 @@ public class CodeBrowserPlugin extends Plugin
|
||||
public boolean goToField(Address a, String fieldName, int occurrence, int row, int col,
|
||||
boolean scroll) {
|
||||
|
||||
boolean result = SystemUtilities
|
||||
.runSwingNow(() -> doGoToField(a, fieldName, occurrence, row, col, scroll));
|
||||
boolean result = SystemUtilities.runSwingNow(
|
||||
() -> doGoToField(a, fieldName, occurrence, row, col, scroll));
|
||||
return result;
|
||||
}
|
||||
|
||||
|
@ -36,7 +36,6 @@ import docking.widgets.fieldpanel.FieldPanel;
|
||||
import docking.widgets.fieldpanel.HoverHandler;
|
||||
import docking.widgets.fieldpanel.internal.FieldPanelCoordinator;
|
||||
import docking.widgets.fieldpanel.support.*;
|
||||
import ghidra.GhidraOptions;
|
||||
import ghidra.app.nav.*;
|
||||
import ghidra.app.plugin.core.clipboard.CodeBrowserClipboardProvider;
|
||||
import ghidra.app.plugin.core.codebrowser.actions.*;
|
||||
@ -63,8 +62,6 @@ public class CodeViewerProvider extends NavigatableComponentProviderAdapter
|
||||
|
||||
private static final String TITLE = "Listing: ";
|
||||
|
||||
private static final String OPERAND_OPTIONS_PREFIX = GhidraOptions.OPERAND_GROUP_TITLE + ".";
|
||||
|
||||
private static final Icon LISTING_FORMAT_EXPAND_ICON =
|
||||
ResourceManager.loadImage("images/field.header.down.png");
|
||||
private static final Icon LISTING_FORMAT_COLLAPSE_ICON =
|
||||
@ -93,9 +90,6 @@ public class CodeViewerProvider extends NavigatableComponentProviderAdapter
|
||||
private ProgramDropProvider curDropProvider;
|
||||
private ToggleDockingAction toggleHoverAction;
|
||||
|
||||
//TODO - Need to improve CodeUnit.getRepresentation format options interface before adding this
|
||||
//TODO private ToggleOperandMarkupAction[] toggleOperandMarkupActions;
|
||||
|
||||
private ProgramLocation currentLocation;
|
||||
|
||||
private ListingPanel otherPanel;
|
||||
@ -976,9 +970,9 @@ public class CodeViewerProvider extends NavigatableComponentProviderAdapter
|
||||
}
|
||||
}
|
||||
|
||||
class ToggleHoverAction extends ToggleDockingAction {
|
||||
private class ToggleHoverAction extends ToggleDockingAction {
|
||||
ToggleHoverAction() {
|
||||
super("Toggle Mouse Hover Popups", CodeViewerProvider.this.getName());
|
||||
super("Toggle Mouse Hover Popups", CodeViewerProvider.this.getOwner());
|
||||
setEnabled(true);
|
||||
setToolBarData(new ToolBarData(HOVER_ON_ICON, "yyyz"));
|
||||
setSelected(true);
|
||||
@ -998,31 +992,6 @@ public class CodeViewerProvider extends NavigatableComponentProviderAdapter
|
||||
}
|
||||
}
|
||||
|
||||
class ToggleOperandMarkupAction extends ToggleDockingAction {
|
||||
final String optionName;
|
||||
|
||||
ToggleOperandMarkupAction(String operandOption) {
|
||||
super(operandOption, CodeViewerProvider.this.getName());
|
||||
this.optionName = OPERAND_OPTIONS_PREFIX + operandOption;
|
||||
boolean state =
|
||||
tool.getOptions(GhidraOptions.CATEGORY_BROWSER_FIELDS).getBoolean(optionName, true);
|
||||
setMenuBarData(new MenuData(new String[] { operandOption }));
|
||||
setSelected(state);
|
||||
setEnabled(true);
|
||||
setHelpLocation(new HelpLocation("CodeBrowserPlugin", "Operands_Field"));
|
||||
}
|
||||
|
||||
public Object getOptionName() {
|
||||
return optionName;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void actionPerformed(ActionContext context) {
|
||||
boolean state = isSelected();
|
||||
tool.getOptions(GhidraOptions.CATEGORY_BROWSER_FIELDS).setBoolean(optionName, state);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A class that allows clients to install transient highlighters while keeping the
|
||||
* middle-mouse highlighting on at the same time.
|
||||
|
@ -39,7 +39,7 @@ public class CollapseAllDataAction extends ProgramLocationContextAction {
|
||||
private CodeViewerProvider provider;
|
||||
|
||||
public CollapseAllDataAction(CodeViewerProvider provider) {
|
||||
super("Collapse All Data", provider.getName());
|
||||
super("Collapse All Data", provider.getOwner());
|
||||
this.provider = provider;
|
||||
|
||||
setPopupMenuData(new MenuData(new String[] { "Collapse All Data" }, null, "Structure"));
|
||||
@ -95,8 +95,7 @@ public class CollapseAllDataAction extends ProgramLocationContextAction {
|
||||
|
||||
ProgramLocation location = context.getLocation();
|
||||
Data data = getTopLevelComponentData(location);
|
||||
TaskLauncher.launchModal("Collapse Data",
|
||||
monitor -> model.closeAllData(data, monitor));
|
||||
TaskLauncher.launchModal("Collapse Data", monitor -> model.closeAllData(data, monitor));
|
||||
}
|
||||
|
||||
private ListingModel getModel() {
|
||||
|
@ -36,7 +36,7 @@ public class ExpandAllDataAction extends ProgramLocationContextAction {
|
||||
private CodeViewerProvider provider;
|
||||
|
||||
public ExpandAllDataAction(CodeViewerProvider provider) {
|
||||
super("Expand All Data", provider.getName());
|
||||
super("Expand All Data", provider.getOwner());
|
||||
this.provider = provider;
|
||||
|
||||
setPopupMenuData(new MenuData(new String[] { "Expand All Data" }, null, "Structure"));
|
||||
|
@ -39,7 +39,7 @@ public class ToggleExpandCollapseDataAction extends ProgramLocationContextAction
|
||||
private CodeViewerProvider provider;
|
||||
|
||||
public ToggleExpandCollapseDataAction(CodeViewerProvider provider) {
|
||||
super("Toggle Expand/Collapse Data", provider.getName());
|
||||
super("Toggle Expand/Collapse Data", provider.getOwner());
|
||||
this.provider = provider;
|
||||
|
||||
setPopupMenuData(
|
||||
|
@ -466,7 +466,6 @@ class GhidraScriptActionManager {
|
||||
if (action == null) {
|
||||
action = new ScriptAction(plugin, script);
|
||||
actionMap.put(script, action);
|
||||
plugin.getTool().addAction(action);
|
||||
}
|
||||
return action;
|
||||
}
|
||||
|
@ -347,7 +347,7 @@ public class SymbolTablePlugin extends Plugin implements DomainObjectListener {
|
||||
private void createSymActions() {
|
||||
String popupGroup = "1";
|
||||
|
||||
openRefsAction = new DockingAction("Symbol References", getName()) {
|
||||
openRefsAction = new DockingAction("Symbol References", getName(), KeyBindingType.SHARED) {
|
||||
@Override
|
||||
public void actionPerformed(ActionContext context) {
|
||||
refProvider.open();
|
||||
@ -359,7 +359,7 @@ public class SymbolTablePlugin extends Plugin implements DomainObjectListener {
|
||||
new MenuData(new String[] { "Symbol References" }, icon, popupGroup));
|
||||
openRefsAction.setToolBarData(new ToolBarData(icon));
|
||||
|
||||
openRefsAction.setDescription("Symbol References");
|
||||
openRefsAction.setDescription("Display Symbol References");
|
||||
tool.addLocalAction(symProvider, openRefsAction);
|
||||
|
||||
deleteAction = new DockingAction("Delete Symbols", getName()) {
|
||||
|
@ -62,7 +62,7 @@ public interface PluginConstants {
|
||||
*/
|
||||
char ANYSINGLECHAR_WILDCARD_CHAR = '?';
|
||||
|
||||
String CODE_BROWSER = "CodeBrowserPlugin";
|
||||
String CODE_BROWSER = "Listing";
|
||||
String MEMORY_MAP = "Memory Map";
|
||||
String BYTE_VIEWER = "ByteViewerPlugin";
|
||||
String BOOKMARKS = "Bookmarks";
|
||||
|
@ -159,6 +159,25 @@ public class ComponentProviderActionsTest extends AbstractGhidraHeadedIntegratio
|
||||
assertMenuItemHasKeyStroke(newKs);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSetKeyBinding_ViaDialog_FromWindowMenu_ToAlreadyBoundAction() {
|
||||
|
||||
//
|
||||
// Test the conflicting key binding use case
|
||||
//
|
||||
|
||||
HasDefaultKeyBindingComponentProvider otherProvider =
|
||||
new HasDefaultKeyBindingComponentProvider(tool);
|
||||
otherProvider.setVisible(true);
|
||||
|
||||
showProvider();
|
||||
|
||||
KeyStroke newKs = CONTROL_T;
|
||||
applyBindingToDialog_FromWindowsMenu(newKs);
|
||||
|
||||
assertCollisionsWithKeyStroke();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSetKeyBinding_ViaOptions_WithoutToolbarAction() {
|
||||
|
||||
@ -235,6 +254,14 @@ public class ComponentProviderActionsTest extends AbstractGhidraHeadedIntegratio
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDefaultKeyBindingAppearsInWindowMenu() {
|
||||
|
||||
provider.setDefaultKeyBinding(new KeyBindingData(CONTROL_T));
|
||||
showProvider();
|
||||
assertWindowMenuActionHasKeyBinding(CONTROL_T);
|
||||
}
|
||||
|
||||
//==================================================================================================
|
||||
// Private Methods
|
||||
//==================================================================================================
|
||||
@ -279,7 +306,7 @@ public class ComponentProviderActionsTest extends AbstractGhidraHeadedIntegratio
|
||||
.stream()
|
||||
.filter(a -> a.getOwner().equals(DockingWindowManager.DOCKING_WINDOWS_OWNER))
|
||||
.findFirst()
|
||||
.get()
|
||||
.orElseGet(() -> null)
|
||||
;
|
||||
//@formatter:on
|
||||
});
|
||||
@ -310,7 +337,7 @@ public class ComponentProviderActionsTest extends AbstractGhidraHeadedIntegratio
|
||||
}
|
||||
|
||||
private void assertNoToolbarAction() {
|
||||
assertNotNull("No toolbar action found for provider", getToolbarShowProviderAction());
|
||||
assertNull("No toolbar action found for provider", getToolbarShowProviderAction());
|
||||
}
|
||||
|
||||
private void assertToolbarAction() {
|
||||
@ -341,6 +368,13 @@ public class ComponentProviderActionsTest extends AbstractGhidraHeadedIntegratio
|
||||
expected, action.getMenuBarData().getMenuIcon());
|
||||
}
|
||||
|
||||
private void assertWindowMenuActionHasKeyBinding(KeyStroke ks) {
|
||||
DockingActionIf action = getWindowMenuShowProviderAction();
|
||||
assertEquals(
|
||||
"Windows menu key bindings for provider does not match the value set on the provider",
|
||||
ks, action.getKeyBinding());
|
||||
}
|
||||
|
||||
private void assertCannotShowKeyBindingDialog_FromWindowsMenu() {
|
||||
// simulate the user mousing over the 'Window' menu's action
|
||||
DockingActionIf windowMenuAction = getWindowMenuShowProviderAction();
|
||||
@ -367,6 +401,24 @@ public class ComponentProviderActionsTest extends AbstractGhidraHeadedIntegratio
|
||||
assertFalse("Invalid key stroke: " + ks, runSwing(() -> dialog.isVisible()));
|
||||
}
|
||||
|
||||
private void applyBindingToDialog_FromWindowsMenu(KeyStroke ks) {
|
||||
DockingActionIf windowMenuAction = getWindowMenuShowProviderAction();
|
||||
DockingWindowManager.setMouseOverAction(windowMenuAction);
|
||||
|
||||
performLaunchKeyStrokeDialogAction();
|
||||
KeyEntryDialog dialog = waitForDialogComponent(KeyEntryDialog.class);
|
||||
|
||||
runSwing(() -> dialog.setKeyStroke(ks));
|
||||
}
|
||||
|
||||
private void assertCollisionsWithKeyStroke() {
|
||||
KeyEntryDialog dialog = waitForDialogComponent(KeyEntryDialog.class);
|
||||
|
||||
JTextPane collisionPane = (JTextPane) getInstanceField("collisionPane", dialog);
|
||||
String collisionText = runSwing(() -> collisionPane.getText());
|
||||
assertTrue(collisionText.contains("Actions mapped to"));
|
||||
}
|
||||
|
||||
private void assertMenuItemHasKeyStroke(KeyStroke expected) {
|
||||
|
||||
DockingActionIf action = getWindowMenuShowProviderAction();
|
||||
@ -415,6 +467,21 @@ public class ComponentProviderActionsTest extends AbstractGhidraHeadedIntegratio
|
||||
public JComponent getComponent() {
|
||||
return component;
|
||||
}
|
||||
}
|
||||
|
||||
private class HasDefaultKeyBindingComponentProvider extends ComponentProvider {
|
||||
private JComponent component = new JTextField("Hey!");
|
||||
|
||||
HasDefaultKeyBindingComponentProvider(DockingTool tool) {
|
||||
super(tool, HasDefaultKeyBindingComponentProvider.class.getSimpleName(),
|
||||
"Fooberry Plugin");
|
||||
|
||||
setDefaultKeyBinding(new KeyBindingData(CONTROL_T));
|
||||
}
|
||||
|
||||
@Override
|
||||
public JComponent getComponent() {
|
||||
return component;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -18,6 +18,7 @@ package docking.action;
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
import java.awt.event.KeyEvent;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.swing.*;
|
||||
|
||||
@ -25,6 +26,7 @@ import org.junit.*;
|
||||
|
||||
import docking.*;
|
||||
import docking.actions.KeyEntryDialog;
|
||||
import docking.actions.ToolActions;
|
||||
import ghidra.app.plugin.core.codebrowser.CodeBrowserPlugin;
|
||||
import ghidra.app.plugin.core.data.DataPlugin;
|
||||
import ghidra.app.plugin.core.function.FunctionPlugin;
|
||||
@ -186,20 +188,26 @@ public class KeyEntryDialogTest extends AbstractGhidraHeadedIntegrationTest {
|
||||
}
|
||||
|
||||
public DockingAction getKeyBindingAction() {
|
||||
DockingWindowManager dwm = DockingWindowManager.getInstance(tool.getToolFrame());
|
||||
ActionToGuiMapper dockingActionManager =
|
||||
(ActionToGuiMapper) getInstanceField("actionManager", dwm);
|
||||
return (DockingAction) getInstanceField("keyBindingsAction", dockingActionManager);
|
||||
|
||||
ToolActions toolActions = tool.getToolActions();
|
||||
KeyBindingsManager kbm =
|
||||
(KeyBindingsManager) getInstanceField("keyBindingsManager", toolActions);
|
||||
Map<KeyStroke, DockingKeyBindingAction> dockingKeyMap =
|
||||
(Map<KeyStroke, DockingKeyBindingAction>) getInstanceField("dockingKeyMap", kbm);
|
||||
KeyStroke ks = KeyStroke.getKeyStroke(KeyEvent.VK_F4, 0);
|
||||
DockingKeyBindingAction dockingAction = dockingKeyMap.get(ks);
|
||||
DockingAction f4Action = (DockingAction) getInstanceField("docakbleAction", dockingAction);
|
||||
return f4Action;
|
||||
}
|
||||
|
||||
private void showDialog(final DockingAction actionToEdit) throws Exception {
|
||||
final DockingAction keyBindingAction = getKeyBindingAction();
|
||||
DockingAction keyBindingAction = getKeyBindingAction();
|
||||
executeOnSwingWithoutBlocking(() -> {
|
||||
DockingWindowManager.setMouseOverAction(actionToEdit);
|
||||
performAction(keyBindingAction, false);
|
||||
});
|
||||
|
||||
keyEntryDialog = waitForDialogComponent(tool.getToolFrame(), KeyEntryDialog.class, 2000);
|
||||
keyEntryDialog = waitForDialogComponent(KeyEntryDialog.class);
|
||||
assertNotNull(keyEntryDialog);
|
||||
|
||||
collisionPane = (JTextPane) getInstanceField("collisionPane", keyEntryDialog);
|
||||
|
@ -718,7 +718,7 @@ public class BookmarkPluginTest extends AbstractGhidraHeadedIntegrationTest {
|
||||
}
|
||||
|
||||
private void showBookmarkProvider() throws Exception {
|
||||
DockingActionIf action = getAction(plugin, "Show Bookmarks");
|
||||
DockingActionIf action = getAction(plugin, "Bookmarks");
|
||||
performAction(action, true);
|
||||
table = plugin.getBookmarkTable();
|
||||
waitForTable();
|
||||
|
@ -46,7 +46,6 @@ import ghidra.framework.plugintool.PluginTool;
|
||||
import ghidra.program.database.ProgramBuilder;
|
||||
import ghidra.program.database.ProgramDB;
|
||||
import ghidra.program.model.address.Address;
|
||||
import ghidra.program.model.address.AddressFactory;
|
||||
import ghidra.program.model.data.DataType;
|
||||
import ghidra.program.model.data.PointerDataType;
|
||||
import ghidra.program.model.listing.Function;
|
||||
@ -62,7 +61,6 @@ public class CallTreePluginTest extends AbstractGhidraHeadedIntegrationTest {
|
||||
private TestEnv env;
|
||||
private CodeBrowserPlugin codeBrowserPlugin;
|
||||
private PluginTool tool;
|
||||
private ProgramDB program;
|
||||
private CallTreePlugin callTreePlugin;
|
||||
private CallTreeProvider provider;
|
||||
private List<CallTreeProvider> providers;
|
||||
@ -70,14 +68,10 @@ public class CallTreePluginTest extends AbstractGhidraHeadedIntegrationTest {
|
||||
private GTree incomingTree;
|
||||
private GTree outgoingTree;
|
||||
|
||||
private DockingAction showProviderAction;
|
||||
private ProgramBuilder builder;
|
||||
private ProgramDB program;
|
||||
|
||||
private GoToService goToService;
|
||||
private AddressFactory addressFactory;
|
||||
|
||||
public CallTreePluginTest() {
|
||||
super();
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
// cast to list
|
||||
@ -91,7 +85,6 @@ public class CallTreePluginTest extends AbstractGhidraHeadedIntegrationTest {
|
||||
|
||||
callTreePlugin = env.getPlugin(CallTreePlugin.class);
|
||||
providers = (List<CallTreeProvider>) getInstanceField("providers", callTreePlugin);
|
||||
showProviderAction = (DockingAction) getInstanceField("showProviderAction", callTreePlugin);
|
||||
|
||||
GoToServicePlugin goToPlugin = env.getPlugin(GoToServicePlugin.class);
|
||||
goToService = (GoToService) invokeInstanceMethod("getGotoService", goToPlugin);
|
||||
@ -100,20 +93,18 @@ public class CallTreePluginTest extends AbstractGhidraHeadedIntegrationTest {
|
||||
env.showTool();
|
||||
|
||||
program = createProgram();
|
||||
addressFactory = program.getAddressFactory();
|
||||
ProgramManager pm = tool.getService(ProgramManager.class);
|
||||
pm.openProgram(program.getDomainFile());
|
||||
|
||||
// setup a good start location
|
||||
goTo(addr("5000"));
|
||||
|
||||
provider = getProvider();
|
||||
provider = callTreePlugin.getPrimaryProvider();
|
||||
tool.showComponentProvider(provider, true);
|
||||
incomingTree = (GTree) getInstanceField("incomingTree", provider);
|
||||
outgoingTree = (GTree) getInstanceField("outgoingTree", provider);
|
||||
}
|
||||
|
||||
ProgramBuilder builder;
|
||||
|
||||
private ProgramDB createProgram() throws Exception {
|
||||
|
||||
builder = new ProgramBuilder("Call Trees", ProgramBuilder._TOY);
|
||||
@ -385,21 +376,21 @@ public class CallTreePluginTest extends AbstractGhidraHeadedIntegrationTest {
|
||||
assertNotNull("Provider did not update its information when made visible",
|
||||
providerFunction());
|
||||
|
||||
final ToggleDockingAction navigateIncomingLoctionsAction =
|
||||
ToggleDockingAction navigateIncomingLoctionsAction =
|
||||
(ToggleDockingAction) getAction("Navigation Incoming Location Changes");
|
||||
assertTrue(!navigateIncomingLoctionsAction.isSelected());
|
||||
setToggleActionSelected(navigateIncomingLoctionsAction, provider.getActionContext(null),
|
||||
false);
|
||||
|
||||
assertEquals("Provider's location does not match that of the listing.", currentFunction(),
|
||||
providerFunction());
|
||||
|
||||
goTo(addr("0x6000"));
|
||||
|
||||
assertTrue("Provider's location matches that of the listing when not following " +
|
||||
"location changes.", !currentFunction().equals(providerFunction()));
|
||||
|
||||
assertNotEquals("Provider's location matches that of the listing when not following " +
|
||||
"location changes", currentFunction(), providerFunction());
|
||||
performAction(navigateIncomingLoctionsAction, true);
|
||||
|
||||
assertEquals("Provider's location does not match that of the listing.", currentFunction(),
|
||||
assertEquals("Provider's location does not match that of the listing", currentFunction(),
|
||||
providerFunction());
|
||||
}
|
||||
|
||||
@ -779,21 +770,6 @@ public class CallTreePluginTest extends AbstractGhidraHeadedIntegrationTest {
|
||||
return functionManager.getFunctionAt(address);
|
||||
}
|
||||
|
||||
private CallTreeProvider getProvider() {
|
||||
final AtomicReference<CallTreeProvider> ref = new AtomicReference<>();
|
||||
|
||||
// run in swing, as two threads are accessing/manipulating a variable
|
||||
runSwing(() -> {
|
||||
if (providers.size() == 0) {
|
||||
ref.set(showProvider());
|
||||
}
|
||||
else {
|
||||
ref.set(providers.get(0));
|
||||
}
|
||||
});
|
||||
return ref.get();
|
||||
}
|
||||
|
||||
private CallTreeProvider getProvider(final String address) {
|
||||
final CallTreeProvider[] providerBox = new CallTreeProvider[1];
|
||||
|
||||
@ -939,13 +915,13 @@ public class CallTreePluginTest extends AbstractGhidraHeadedIntegrationTest {
|
||||
}
|
||||
|
||||
private void fullyExpandIncomingNode(GTreeNode node) {
|
||||
DockingActionIf expandAction = getAction(callTreePlugin, "Fully Expand Selected Nodes");
|
||||
DockingActionIf expandAction = getLocalAction(provider, "Fully Expand Selected Nodes");
|
||||
performAction(expandAction, new ActionContext(provider, incomingTree), false);
|
||||
waitForTree(node.getTree());
|
||||
}
|
||||
|
||||
private void fullyExpandOutgoingNode(GTreeNode node) {
|
||||
DockingActionIf expandAction = getAction(callTreePlugin, "Fully Expand Selected Nodes");
|
||||
DockingActionIf expandAction = getLocalAction(provider, "Fully Expand Selected Nodes");
|
||||
performAction(expandAction, new ActionContext(provider, outgoingTree), false);
|
||||
waitForTree(node.getTree());
|
||||
}
|
||||
@ -1054,11 +1030,11 @@ public class CallTreePluginTest extends AbstractGhidraHeadedIntegrationTest {
|
||||
String name = child.getName();
|
||||
Integer integer = map.get(name);
|
||||
if (integer == null) {
|
||||
integer = new Integer(0);
|
||||
integer = 0;
|
||||
}
|
||||
int asInt = integer;
|
||||
asInt++;
|
||||
map.put(name, new Integer(asInt));
|
||||
map.put(name, asInt);
|
||||
}
|
||||
return map;
|
||||
}
|
||||
@ -1088,10 +1064,7 @@ public class CallTreePluginTest extends AbstractGhidraHeadedIntegrationTest {
|
||||
}
|
||||
|
||||
private DockingActionIf getAction(String actionName) {
|
||||
// make sure there is a provider from which to get actions
|
||||
getProvider();
|
||||
|
||||
DockingActionIf action = getAction(tool, "CallTreePlugin", actionName);
|
||||
DockingActionIf action = getLocalAction(provider, actionName);
|
||||
return action;
|
||||
}
|
||||
|
||||
@ -1121,20 +1094,14 @@ public class CallTreePluginTest extends AbstractGhidraHeadedIntegrationTest {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Shows and returns a provider for the current address.
|
||||
*/
|
||||
private CallTreeProvider showProvider() {
|
||||
performAction(showProviderAction, true);
|
||||
return getProvider();
|
||||
}
|
||||
|
||||
/**
|
||||
* Shows and returns a provider for the specified address.
|
||||
*/
|
||||
private CallTreeProvider showProvider(String address) {
|
||||
goTo(addr(address));
|
||||
performAction(showProviderAction, true);
|
||||
|
||||
DockingAction action = callTreePlugin.getShowCallTreeFromMenuAction();
|
||||
performAction(action);
|
||||
return getProvider(address);
|
||||
}
|
||||
|
||||
|
@ -61,6 +61,9 @@ public class CodeBrowserScreenMovementTest extends AbstractProgramBasedTest {
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
|
||||
// warning: this test is sensitive to size and layout of the visible component providers;
|
||||
// any layout changes may affect the values being tested below
|
||||
|
||||
initialize();
|
||||
|
||||
fp = codeBrowser.getFieldPanel();
|
||||
@ -115,6 +118,9 @@ public class CodeBrowserScreenMovementTest extends AbstractProgramBasedTest {
|
||||
@Test
|
||||
public void testBasicControls() throws Exception {
|
||||
|
||||
// warning: this test is sensitive to size and layout of the visible component providers;
|
||||
// any layout changes may affect the values being tested below
|
||||
|
||||
fp = codeBrowser.getFieldPanel();
|
||||
ListingPanel panel = codeBrowser.getListingPanel();
|
||||
JScrollBar scrollbar = panel.getVerticalScrollBar();
|
||||
|
@ -68,7 +68,7 @@ public class ExpandCollapseDataActionsTest extends AbstractGhidraHeadedIntegrati
|
||||
pm.openProgram(program.getDomainFile());
|
||||
addrFactory = program.getAddressFactory();
|
||||
env.showTool();
|
||||
provider = (CodeViewerProvider) tool.getComponentProvider("CodeBrowserPlugin");
|
||||
provider = (CodeViewerProvider) tool.getComponentProvider("Listing");
|
||||
listingModel = provider.getListingPanel().getListingModel();
|
||||
CodeBrowserPlugin plugin = getPlugin(tool, CodeBrowserPlugin.class);
|
||||
toggleExpand = getAction(plugin, "Toggle Expand/Collapse Data");
|
||||
|
@ -62,7 +62,7 @@ public class StructureEditorArchiveTest extends AbstractStructureEditorTest {
|
||||
tool.addPlugin(DataTypeManagerPlugin.class.getName());
|
||||
dtmService = tool.getService(DataTypeManagerService.class);
|
||||
plugin = (DataTypeManagerPlugin) dtmService;
|
||||
manageDts = getAction(plugin, "Data Type Manager");
|
||||
manageDts = getAction(plugin, "DataTypes Provider");
|
||||
DataTypesProvider dataTypesProvider = plugin.getProvider();
|
||||
dtTree = dataTypesProvider.getGTree();
|
||||
|
||||
|
@ -55,14 +55,6 @@ public class ArchiveRemappedHeadedTest extends AbstractGhidraHeadedIntegrationTe
|
||||
private File vs12ArchiveFile;
|
||||
private File vs9ArchiveFile;
|
||||
|
||||
/**
|
||||
* Constructor for ArchiveRemappedTest.
|
||||
* @param testName
|
||||
*/
|
||||
public ArchiveRemappedHeadedTest() {
|
||||
super();
|
||||
}
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
|
||||
@ -97,10 +89,9 @@ public class ArchiveRemappedHeadedTest extends AbstractGhidraHeadedIntegrationTe
|
||||
|
||||
env.showTool();
|
||||
|
||||
tool.showComponentProvider(provider, true);
|
||||
waitForPostedSwingRunnables();
|
||||
|
||||
provider = plugin.getProvider();
|
||||
tool.showComponentProvider(provider, true);
|
||||
|
||||
tree = provider.getGTree();
|
||||
waitForTree(tree);
|
||||
}
|
||||
|
@ -87,7 +87,7 @@ public class MemoryMapPluginTest extends AbstractGhidraHeadedIntegrationTest {
|
||||
|
||||
@Test
|
||||
public void testActionEnabled() {
|
||||
DockingActionIf action = getAction(plugin, "View Memory Map");
|
||||
DockingActionIf action = getAction(plugin, "Memory Map");
|
||||
assertTrue(action.isEnabled());
|
||||
}
|
||||
|
||||
@ -99,7 +99,7 @@ public class MemoryMapPluginTest extends AbstractGhidraHeadedIntegrationTest {
|
||||
Set<DockingActionIf> actions = getActionsByOwner(tool, plugin.getName());
|
||||
for (DockingActionIf action : actions) {
|
||||
if (action.getName().equals("Add Block") || action.getName().equals("Set Image Base") ||
|
||||
action.getName().equals("View Memory Map")) {
|
||||
action.getName().equals("Memory Map")) {
|
||||
assertTrue(action.isEnabledForContext(provider.getActionContext(null)));
|
||||
}
|
||||
else {
|
||||
@ -116,7 +116,7 @@ public class MemoryMapPluginTest extends AbstractGhidraHeadedIntegrationTest {
|
||||
assertEquals(0, table.getModel().getRowCount());
|
||||
Set<DockingActionIf> actions = getActionsByOwner(tool, plugin.getName());
|
||||
for (DockingActionIf action : actions) {
|
||||
if (!action.getName().equals("View Memory Map")) {
|
||||
if (!action.getName().equals("Memory Map")) {
|
||||
assertTrue(!action.isEnabledForContext(provider.getActionContext(null)));
|
||||
}
|
||||
}
|
||||
@ -297,7 +297,7 @@ public class MemoryMapPluginTest extends AbstractGhidraHeadedIntegrationTest {
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
|
||||
private void showProvider() {
|
||||
DockingActionIf action = getAction(plugin, "View Memory Map");
|
||||
DockingActionIf action = getAction(plugin, "Memory Map");
|
||||
performAction(action, true);
|
||||
provider = plugin.getMemoryMapProvider();
|
||||
}
|
||||
|
@ -137,7 +137,7 @@ public class MemoryMapProvider1Test extends AbstractGhidraHeadedIntegrationTest
|
||||
String name = action.getName();
|
||||
if (name.equals("Add Block") || name.equals("Merge Blocks") ||
|
||||
name.equals("Delete Block") || name.equals("Set Image Base") ||
|
||||
name.equals("View Memory Map")) {
|
||||
name.equals("Memory Map")) {
|
||||
assertTrue(action.isEnabled());
|
||||
}
|
||||
else {
|
||||
@ -667,7 +667,7 @@ public class MemoryMapProvider1Test extends AbstractGhidraHeadedIntegrationTest
|
||||
/////////////////////////////////////////////////////////////////////
|
||||
|
||||
private void showProvider() {
|
||||
DockingActionIf action = getAction(plugin, "View Memory Map");
|
||||
DockingActionIf action = getAction(plugin, "Memory Map");
|
||||
performAction(action, true);
|
||||
waitForPostedSwingRunnables();
|
||||
provider = plugin.getMemoryMapProvider();
|
||||
|
@ -1332,7 +1332,7 @@ public class MemoryMapProvider2Test extends AbstractGhidraHeadedIntegrationTest
|
||||
///////////////////////////////////////////////////////////////////
|
||||
|
||||
private void showProvider() {
|
||||
DockingActionIf action = getAction(plugin, "View Memory Map");
|
||||
DockingActionIf action = getAction(plugin, "Memory Map");
|
||||
performAction(action, true);
|
||||
provider = plugin.getMemoryMapProvider();
|
||||
table = provider.getTable();
|
||||
|
@ -886,7 +886,7 @@ public class MemoryMapProvider3Test extends AbstractGhidraHeadedIntegrationTest
|
||||
///////////////////////////////////////////////////////////////////
|
||||
|
||||
private void showProvider() {
|
||||
DockingActionIf action = getAction(plugin, "View Memory Map");
|
||||
DockingActionIf action = getAction(plugin, "Memory Map");
|
||||
performAction(action, true);
|
||||
waitForPostedSwingRunnables();
|
||||
provider = plugin.getMemoryMapProvider();
|
||||
|
@ -54,10 +54,6 @@ public class MemoryMapProvider4Test extends AbstractGhidraHeadedIntegrationTest
|
||||
private JTable table;
|
||||
private TableModel model;
|
||||
|
||||
public MemoryMapProvider4Test() {
|
||||
super();
|
||||
}
|
||||
|
||||
private Program buildProgram(String programName) throws Exception {
|
||||
ProgramBuilder builder = new ProgramBuilder(programName, ProgramBuilder._TOY);
|
||||
builder.createMemory(".text", Long.toHexString(0x1001000), 0x6600);
|
||||
@ -247,7 +243,7 @@ public class MemoryMapProvider4Test extends AbstractGhidraHeadedIntegrationTest
|
||||
}
|
||||
|
||||
private void showProvider() {
|
||||
DockingActionIf action = getAction(plugin, "View Memory Map");
|
||||
DockingActionIf action = getAction(plugin, "Memory Map");
|
||||
performAction(action, true);
|
||||
waitForPostedSwingRunnables();
|
||||
provider = plugin.getMemoryMapProvider();
|
||||
|
@ -71,8 +71,7 @@ public class NextPrevAddressPluginTest extends AbstractGhidraHeadedIntegrationTe
|
||||
NextPrevAddressPlugin plugin = env.getPlugin(NextPrevAddressPlugin.class);
|
||||
previousAction =
|
||||
(MultiActionDockingAction) TestUtils.getInstanceField("previousAction", plugin);
|
||||
nextAction =
|
||||
(MultiActionDockingAction) TestUtils.getInstanceField("nextAction", plugin);
|
||||
nextAction = (MultiActionDockingAction) TestUtils.getInstanceField("nextAction", plugin);
|
||||
|
||||
GoToAddressLabelPlugin goToPlugin = env.getPlugin(GoToAddressLabelPlugin.class);
|
||||
dialog = goToPlugin.getDialog();
|
||||
@ -355,9 +354,9 @@ public class NextPrevAddressPluginTest extends AbstractGhidraHeadedIntegrationTe
|
||||
@SuppressWarnings("unchecked")
|
||||
// let caution fly
|
||||
private JButton findButtonForAction(DockingWindowManager windowManager, DockingAction action) {
|
||||
Object actionManager = TestUtils.getInstanceField("actionManager", windowManager);
|
||||
Object actionToGuiMapper = TestUtils.getInstanceField("actionToGuiMapper", windowManager);
|
||||
Object menuAndToolBarManager =
|
||||
TestUtils.getInstanceField("menuAndToolBarManager", actionManager);
|
||||
TestUtils.getInstanceField("menuAndToolBarManager", actionToGuiMapper);
|
||||
Map<WindowNode, WindowActionManager> map =
|
||||
(Map<WindowNode, WindowActionManager>) TestUtils.getInstanceField(
|
||||
"windowToActionManagerMap", menuAndToolBarManager);
|
||||
|
@ -37,12 +37,9 @@ import ghidra.program.util.ProgramSelection;
|
||||
import ghidra.test.*;
|
||||
|
||||
/**
|
||||
* Test for deleting default plate comments on a function.
|
||||
*
|
||||
*
|
||||
*
|
||||
* Test for deleting default plate comments on a function
|
||||
*/
|
||||
public class DeleteFunctionDefaultPlatesTest extends AbstractGhidraHeadedIntegrationTest {
|
||||
public class DeleteFunctionDefaultPlatesScriptTest extends AbstractGhidraHeadedIntegrationTest {
|
||||
|
||||
private TestEnv env;
|
||||
private PluginTool tool;
|
||||
@ -50,13 +47,6 @@ public class DeleteFunctionDefaultPlatesTest extends AbstractGhidraHeadedIntegra
|
||||
private File script;
|
||||
private ToyProgramBuilder builder;
|
||||
|
||||
public DeleteFunctionDefaultPlatesTest() {
|
||||
super();
|
||||
}
|
||||
|
||||
/*
|
||||
* @see TestCase#setUp()
|
||||
*/
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
env = new TestEnv();
|
||||
@ -71,11 +61,8 @@ public class DeleteFunctionDefaultPlatesTest extends AbstractGhidraHeadedIntegra
|
||||
|
||||
ProgramManager pm = tool.getService(ProgramManager.class);
|
||||
pm.openProgram(program.getDomainFile());
|
||||
//script =
|
||||
// new File(Application.getApplicationRootDirectory().getFile(),
|
||||
// "Features/Base/ghidra_scripts/DeleteFunctionDefaultPlates.java");
|
||||
script = Application.getModuleFile("Base",
|
||||
"ghidra_scripts/DeleteFunctionDefaultPlates.java").getFile(true);
|
||||
"ghidra_scripts/DeleteFunctionDefaultPlatesScript.java").getFile(true);
|
||||
env.showTool();
|
||||
}
|
||||
|
||||
@ -97,9 +84,6 @@ public class DeleteFunctionDefaultPlatesTest extends AbstractGhidraHeadedIntegra
|
||||
return builder.getProgram();
|
||||
}
|
||||
|
||||
/*
|
||||
* @see TestCase#tearDown()
|
||||
*/
|
||||
@After
|
||||
public void tearDown() throws Exception {
|
||||
env.dispose();
|
@ -90,7 +90,7 @@ public class SymbolTreePlugin1Test extends AbstractGhidraHeadedIntegrationTest {
|
||||
tool.addPlugin(SymbolTreePlugin.class.getName());
|
||||
plugin = env.getPlugin(SymbolTreePlugin.class);
|
||||
|
||||
symTreeAction = getAction(plugin, "Display Symbol Tree");
|
||||
symTreeAction = getAction(plugin, "Symbol Tree");
|
||||
cbPlugin = env.getPlugin(CodeBrowserPlugin.class);
|
||||
|
||||
util = new SymbolTreeTestUtils(plugin);
|
||||
@ -107,15 +107,6 @@ public class SymbolTreePlugin1Test extends AbstractGhidraHeadedIntegrationTest {
|
||||
env.dispose();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testActionEnabled() {
|
||||
assertTrue(symTreeAction.isEnabledForContext(null));
|
||||
|
||||
util.openProgram();
|
||||
|
||||
assertTrue(symTreeAction.isEnabledForContext(null));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testShowDisplay() throws Exception {
|
||||
showSymbolTree();
|
||||
|
@ -90,14 +90,14 @@ class SymbolTreeTestUtils {
|
||||
this.plugin = plugin;
|
||||
this.program = buildProgram();
|
||||
|
||||
symTreeAction = getAction(plugin, "Display Symbol Tree");
|
||||
symTreeAction = getAction(plugin, "Symbol Tree");
|
||||
}
|
||||
|
||||
SymbolTreeTestUtils(SymbolTreePlugin plugin, Program program) {
|
||||
this.plugin = plugin;
|
||||
this.program = program;
|
||||
|
||||
symTreeAction = getAction(plugin, "Display Symbol Tree");
|
||||
symTreeAction = getAction(plugin, "Symbol Tree");
|
||||
}
|
||||
|
||||
public static Program buildProgram() throws Exception {
|
||||
|
@ -21,6 +21,7 @@ import java.awt.*;
|
||||
import java.awt.event.*;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.function.BiConsumer;
|
||||
|
||||
import javax.swing.*;
|
||||
@ -59,6 +60,7 @@ import ghidra.util.table.GhidraTableFilterPanel;
|
||||
import ghidra.util.table.ProgramTableModel;
|
||||
import ghidra.util.table.field.AddressBasedLocation;
|
||||
import ghidra.util.xml.XmlUtilities;
|
||||
import util.CollectionUtils;
|
||||
|
||||
public class SymbolTablePluginTest extends AbstractGhidraHeadedIntegrationTest {
|
||||
|
||||
@ -93,8 +95,14 @@ public class SymbolTablePluginTest extends AbstractGhidraHeadedIntegrationTest {
|
||||
plugin = env.getPlugin(SymbolTablePlugin.class);
|
||||
provider = (SymbolProvider) getInstanceField("symProvider", plugin);
|
||||
|
||||
viewSymAction = getAction(plugin, "View Symbol Table");
|
||||
viewRefAction = getAction(plugin, "View Symbol References");
|
||||
viewSymAction = getAction(plugin, "Symbol Table");
|
||||
|
||||
// this action is actually in the tool twice: once for the provider and once as a
|
||||
// local action in the Symbol Table header, so we must pick one
|
||||
Set<DockingActionIf> symbolReferencesActions =
|
||||
getActionsByOwnerAndName(tool, plugin.getName(), "Symbol References");
|
||||
viewRefAction = CollectionUtils.any(symbolReferencesActions);
|
||||
|
||||
deleteAction = getAction(plugin, "Delete Symbols");
|
||||
makeSelectionAction = getAction(plugin, "Make Selection");
|
||||
setFilterAction = getAction(plugin, "Set Filter");
|
||||
|
@ -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.action.DockingActionIf;
|
||||
import docking.action.ToggleDockingAction;
|
||||
import docking.test.AbstractDockingTest;
|
||||
import docking.widgets.OptionDialog;
|
||||
import docking.widgets.tree.GTreeNode;
|
||||
import docking.widgets.tree.GTreeRootNode;
|
||||
import docking.widgets.tree.support.GTreeDragNDropHandler;
|
||||
import docking.widgets.tree.support.GTreeNodeTransferable;
|
||||
import docking.widgets.tree.support.*;
|
||||
import ghidra.framework.data.DomainObjectAdapter;
|
||||
import ghidra.framework.main.FrontEndTool;
|
||||
import ghidra.framework.model.DomainFile;
|
||||
@ -46,11 +46,13 @@ import ghidra.program.model.listing.Program;
|
||||
import ghidra.test.AbstractGhidraHeadedIntegrationTest;
|
||||
import ghidra.test.TestEnv;
|
||||
import ghidra.util.task.TaskMonitor;
|
||||
import resources.MultiIcon;
|
||||
import resources.ResourceManager;
|
||||
|
||||
/**
|
||||
* Tests for actions in the front end (Ghidra project window).
|
||||
* Tests for actions in the front end (Ghidra project window)
|
||||
*/
|
||||
public class ActionManager1Test extends AbstractGhidraHeadedIntegrationTest {
|
||||
public class FrontEndPluginActionsTest extends AbstractGhidraHeadedIntegrationTest {
|
||||
|
||||
private FrontEndTool frontEndTool;
|
||||
private TestEnv env;
|
||||
@ -58,10 +60,6 @@ public class ActionManager1Test extends AbstractGhidraHeadedIntegrationTest {
|
||||
private DomainFolder rootFolder;
|
||||
private GTreeRootNode rootNode;
|
||||
|
||||
public ActionManager1Test() {
|
||||
super();
|
||||
}
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
|
||||
@ -533,10 +531,237 @@ public class ActionManager1Test extends AbstractGhidraHeadedIntegrationTest {
|
||||
assertNull(getChild(rootNode, "tms"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRenameFolder() throws Exception {
|
||||
rootFolder.createFolder("myFolder");
|
||||
waitForSwing();
|
||||
|
||||
final GTreeNode myNode = rootNode.getChild("myFolder");
|
||||
setSelectionPath(myNode.getTreePath());
|
||||
|
||||
DockingActionIf renameAction = getAction("Rename");
|
||||
performAction(renameAction, getDomainFileActionContext(), true);
|
||||
waitForTree();
|
||||
|
||||
// select "Rename" action
|
||||
SwingUtilities.invokeAndWait(() -> {
|
||||
int row = tree.getRowForPath(myNode.getTreePath());
|
||||
JTree jTree = (JTree) getInstanceField("tree", tree);
|
||||
DefaultTreeCellEditor cellEditor = (DefaultTreeCellEditor) tree.getCellEditor();
|
||||
Container container = (Container) cellEditor.getTreeCellEditorComponent(jTree, myNode,
|
||||
true, true, false, row);
|
||||
JTextField textField = (JTextField) container.getComponent(0);
|
||||
|
||||
textField.setText("MyNewFolder");
|
||||
tree.stopEditing();
|
||||
});
|
||||
waitForSwing();
|
||||
assertNotNull(rootNode.getChild("MyNewFolder"));
|
||||
assertNull(rootNode.getChild("myFolder"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRenameFile() throws Exception {
|
||||
final GTreeNode npNode = rootNode.getChild("notepad");
|
||||
setSelectionPath(npNode.getTreePath());
|
||||
|
||||
DockingActionIf renameAction = getAction("Rename");
|
||||
performAction(renameAction, getDomainFileActionContext(), true);
|
||||
waitForTree();
|
||||
|
||||
// select "Rename" action
|
||||
SwingUtilities.invokeAndWait(() -> {
|
||||
int row = tree.getRowForPath(npNode.getTreePath());
|
||||
DefaultTreeCellEditor cellEditor = (DefaultTreeCellEditor) tree.getCellEditor();
|
||||
JTree jTree = (JTree) getInstanceField("tree", tree);
|
||||
Container container = (Container) cellEditor.getTreeCellEditorComponent(jTree, npNode,
|
||||
true, true, false, row);
|
||||
JTextField textField = (JTextField) container.getComponent(0);
|
||||
|
||||
textField.setText("My_notepad");
|
||||
tree.stopEditing();
|
||||
});
|
||||
waitForSwing();
|
||||
assertNotNull(rootNode.getChild("My_notepad"));
|
||||
assertNull(rootNode.getChild("notepad"));
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRenameFileInUse() throws Exception {
|
||||
final GTreeNode npNode = rootNode.getChild("notepad");
|
||||
DomainFile df = ((DomainFileNode) npNode).getDomainFile();
|
||||
|
||||
setInUse(df);
|
||||
|
||||
setSelectionPath(npNode.getTreePath());
|
||||
|
||||
DockingActionIf renameAction = getAction("Rename");
|
||||
executeOnSwingWithoutBlocking(
|
||||
() -> performAction(renameAction, getDomainFileActionContext(), true));
|
||||
waitForSwing();
|
||||
OptionDialog dlg = waitForDialogComponent(OptionDialog.class);
|
||||
assertEquals("Rename Not Allowed", dlg.getTitle());
|
||||
pressButtonByText(dlg.getComponent(), "OK");
|
||||
assertNotNull(rootNode.getChild("notepad"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRenameFolderInUse() throws Exception {
|
||||
// folder contains a file that is in use
|
||||
DomainFolder f = rootFolder.createFolder("myFolder");
|
||||
f = f.createFolder("A");
|
||||
f = f.createFolder("B");
|
||||
f = f.createFolder("C");
|
||||
|
||||
Program p = createDefaultProgram("new", ProgramBuilder._TOY, this);
|
||||
|
||||
DomainFile df = f.createFile("notepad", p, TaskMonitor.DUMMY);
|
||||
waitForSwing();
|
||||
|
||||
final GTreeNode myNode = rootNode.getChild("myFolder");
|
||||
((DomainFolderNode) myNode).getDomainFolder().createFile("notepad", p, TaskMonitor.DUMMY);
|
||||
p.release(this);
|
||||
|
||||
waitForSwing();
|
||||
tree.expandPath(myNode.getTreePath());
|
||||
assertNotNull(myNode.getChild("notepad"));
|
||||
|
||||
setInUse(df, "/myFolder/notepad");
|
||||
|
||||
setSelectionPath(myNode.getTreePath());
|
||||
|
||||
final DockingActionIf renameAction = getAction("Rename");
|
||||
performAction(renameAction, getDomainFileActionContext(), true);
|
||||
waitForTree();
|
||||
|
||||
// attempt to rename "myFolder"
|
||||
SwingUtilities.invokeLater(() -> {
|
||||
int row = tree.getRowForPath(myNode.getTreePath());
|
||||
DefaultTreeCellEditor cellEditor = (DefaultTreeCellEditor) tree.getCellEditor();
|
||||
JTree jTree = (JTree) getInstanceField("tree", tree);
|
||||
Container container = (Container) cellEditor.getTreeCellEditorComponent(jTree, myNode,
|
||||
true, true, false, row);
|
||||
JTextField textField = (JTextField) container.getComponent(0);
|
||||
|
||||
textField.setText("My_Newfolder");
|
||||
tree.stopEditing();
|
||||
});
|
||||
|
||||
waitForSwing();
|
||||
|
||||
OptionDialog d = waitForDialogComponent(OptionDialog.class);
|
||||
assertNotNull(d);
|
||||
assertEquals("Rename Failed", d.getTitle());
|
||||
pressButtonByText(d.getComponent(), "OK");
|
||||
assertNotNull(rootNode.getChild("myFolder"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testExpandAll() throws Exception {
|
||||
DomainFolder f = rootFolder.createFolder("myFolder");
|
||||
f = f.createFolder("A");
|
||||
f = f.createFolder("B");
|
||||
f = f.createFolder("C");
|
||||
waitForSwing();
|
||||
|
||||
GTreeNode myNode = rootNode.getChild("myFolder");
|
||||
setSelectionPath(rootNode.getTreePath());
|
||||
DockingActionIf expandAction = getAction("Expand All");
|
||||
performAction(expandAction, getDomainFileActionContext(), true);
|
||||
GTreeNode aNode = myNode.getChild("A");
|
||||
assertNotNull(aNode);
|
||||
GTreeNode bNode = aNode.getChild("B");
|
||||
assertNotNull(bNode);
|
||||
GTreeNode cNode = bNode.getChild("C");
|
||||
assertNotNull(cNode);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCollapseAll() throws Exception {
|
||||
DomainFolder f = rootFolder.createFolder("myFolder");
|
||||
f = f.createFolder("A");
|
||||
f = f.createFolder("B");
|
||||
f = f.createFolder("C");
|
||||
waitForSwing();
|
||||
|
||||
GTreeNode myNode = rootNode.getChild("myFolder");
|
||||
setSelectionPath(myNode.getTreePath());
|
||||
DockingActionIf expandAction = getAction("Expand All");
|
||||
performAction(expandAction, getDomainFileActionContext(), true);
|
||||
waitForTree();
|
||||
|
||||
DockingActionIf collapseAction = getAction("Collapse All");
|
||||
performAction(collapseAction, getDomainFileActionContext(), true);
|
||||
waitForTree();
|
||||
assertTrue(!tree.isExpanded(myNode.getTreePath()));
|
||||
GTreeNode aNode = myNode.getChild("A");
|
||||
assertTrue(!tree.isExpanded(aNode.getTreePath()));
|
||||
GTreeNode bNode = aNode.getChild("B");
|
||||
assertTrue(!tree.isExpanded(bNode.getTreePath()));
|
||||
GTreeNode cNode = bNode.getChild("C");
|
||||
assertNotNull(cNode);
|
||||
assertTrue(!tree.isExpanded(cNode.getTreePath()));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSelectAll() throws Exception {
|
||||
DomainFolder f = rootFolder.createFolder("myFolder");
|
||||
f = f.createFolder("A");
|
||||
f = f.createFolder("B");
|
||||
f = f.createFolder("C");
|
||||
waitForSwing();
|
||||
|
||||
setSelectionPath(rootNode.getTreePath());
|
||||
DockingActionIf selectAction = getAction("Select All");
|
||||
performAction(selectAction, getDomainFileActionContext(), true);
|
||||
waitForTree();
|
||||
|
||||
BreadthFirstIterator it = new BreadthFirstIterator(tree, rootNode);
|
||||
while (it.hasNext()) {
|
||||
GTreeNode node = it.next();
|
||||
assertTrue(tree.isPathSelected(node.getTreePath()));
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSetReadOnly() throws Exception {
|
||||
GTreeNode npNode = rootNode.getChild("notepad");
|
||||
setSelectionPath(npNode.getTreePath());
|
||||
ToggleDockingAction readOnlyAction = (ToggleDockingAction) getAction("Read-Only");
|
||||
readOnlyAction.setSelected(true);
|
||||
performAction(readOnlyAction, getDomainFileActionContext(), true);
|
||||
|
||||
assertTrue(((DomainFileNode) npNode).getDomainFile().isReadOnly());
|
||||
ImageIcon icon = ResourceManager.loadImage("fileIcons/ProgramReadOnly.gif");
|
||||
icon = ResourceManager.getScaledIcon(icon, 16, 16);
|
||||
|
||||
assertTrue(npNode.getIcon(false) instanceof MultiIcon);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSetReadOnlyInUse() throws Exception {
|
||||
GTreeNode npNode = rootNode.getChild("notepad");
|
||||
DomainFile df = ((DomainFileNode) npNode).getDomainFile();
|
||||
setInUse(df);
|
||||
|
||||
setSelectionPath(npNode.getTreePath());
|
||||
ToggleDockingAction readOnlyAction = (ToggleDockingAction) getAction("Read-Only");
|
||||
readOnlyAction.setSelected(true);
|
||||
performAction(readOnlyAction, getDomainFileActionContext(), true);
|
||||
|
||||
assertTrue(((DomainFileNode) npNode).getDomainFile().isReadOnly());
|
||||
}
|
||||
|
||||
//==================================================================================================
|
||||
// Private Methods
|
||||
//==================================================================================================
|
||||
|
||||
private void setSelectionPath(final TreePath path) throws Exception {
|
||||
tree.setSelectionPath(path);
|
||||
waitForTree();
|
||||
}
|
||||
|
||||
private void pressDelete() {
|
||||
DockingActionIf deleteAction = getAction("Delete");
|
||||
performAction(deleteAction, getDomainFileActionContext(), false);
|
@ -43,6 +43,11 @@ public class DummyToolActions implements DockingToolActions {
|
||||
// stub
|
||||
}
|
||||
|
||||
@Override
|
||||
public DockingActionIf getLocalAction(ComponentProvider provider, String actionName) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<DockingActionIf> getActions(String owner) {
|
||||
return null;
|
||||
@ -62,5 +67,4 @@ public class DummyToolActions implements DockingToolActions {
|
||||
public void removeActions(ComponentProvider provider) {
|
||||
// stub
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -26,7 +26,7 @@
|
||||
</COMPONENT_NODE>
|
||||
</SPLIT_NODE>
|
||||
<COMPONENT_NODE TOP_INFO="0">
|
||||
<COMPONENT_INFO NAME="ConsolePlugin" OWNER="ConsolePlugin" TITLE="Console" ACTIVE="false" GROUP="Default" INSTANCE_ID="2999653489311119719" />
|
||||
<COMPONENT_INFO NAME="Console" OWNER="ConsolePlugin" TITLE="Console" ACTIVE="false" GROUP="Default" INSTANCE_ID="2999653489311119719" />
|
||||
</COMPONENT_NODE>
|
||||
</SPLIT_NODE>
|
||||
<SPLIT_NODE WIDTH="996" HEIGHT="491" DIVIDER_LOCATION="622" ORIENTATION="HORIZONTAL">
|
||||
|
@ -27,7 +27,7 @@ import org.junit.*;
|
||||
|
||||
import com.google.common.cache.*;
|
||||
|
||||
import docking.action.DockingAction;
|
||||
import docking.ComponentProvider;
|
||||
import generic.test.TestUtils;
|
||||
import ghidra.app.decompiler.DecompileResults;
|
||||
import ghidra.app.plugin.core.codebrowser.CodeBrowserPlugin;
|
||||
@ -201,10 +201,8 @@ public class DecompilerCachingTest extends AbstractGhidraHeadedIntegrationTest {
|
||||
}
|
||||
|
||||
private void showDecompilerProvider() {
|
||||
DockingAction showDecompileAction =
|
||||
(DockingAction) TestUtils.getInstanceField("decompileAction", decompilePlugin);
|
||||
performAction(showDecompileAction, true);
|
||||
|
||||
ComponentProvider decompiler = tool.getComponentProvider("Decompiler");
|
||||
tool.showComponentProvider(decompiler, true);
|
||||
decompilerProvider = waitForComponentProvider(DecompilerProvider.class);
|
||||
}
|
||||
|
||||
|
@ -15,7 +15,7 @@
|
||||
*/
|
||||
package ghidra.app.plugin.core.functiongraph;
|
||||
|
||||
import static ghidra.graph.viewer.GraphViewerUtils.*;
|
||||
import static ghidra.graph.viewer.GraphViewerUtils.getGraphScale;
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
import java.awt.*;
|
||||
@ -552,9 +552,9 @@ public abstract class AbstractFunctionGraphTest extends AbstractGhidraHeadedInte
|
||||
}
|
||||
|
||||
protected void showFunctionGraphProvider() {
|
||||
DockingAction showGraphAction =
|
||||
(DockingAction) TestUtils.getInstanceField("showFunctionGraphAction", graphPlugin);
|
||||
performAction(showGraphAction, true);
|
||||
|
||||
ComponentProvider provider = tool.getComponentProvider("Function Graph");
|
||||
tool.showComponentProvider(provider, true);
|
||||
|
||||
graphProvider = waitForComponentProvider(FGProvider.class);
|
||||
assertNotNull("Graph not shown", graphProvider);
|
||||
|
@ -51,7 +51,7 @@ class DiffActionManager {
|
||||
static final String IGNORE_DIFFS_NEXT_ACTION = "Ignore Selection and Goto Next Difference";
|
||||
static final String NEXT_DIFF_ACTION = "Next Difference";
|
||||
static final String PREVIOUS_DIFF_ACTION = "Previous Difference";
|
||||
static final String DIFF_DETAILS_ACTION = "Diff Location Details";
|
||||
static final String DIFF_DETAILS_ACTION = "Show Diff Location Details";
|
||||
static final String SHOW_DIFF_SETTINGS_ACTION = "Show Diff Apply Settings";
|
||||
static final String GET_DIFFS_ACTION = "Get Differences";
|
||||
static final String SELECT_ALL_DIFFS_ACTION = "Select All Differences";
|
||||
|
@ -665,7 +665,7 @@ public class DiffTest extends DiffTestAdapter {
|
||||
checkDiffAction("Ignore Selection and Goto Next Difference", true, false);
|
||||
checkDiffAction("Next Difference", true, true);
|
||||
checkDiffAction("Previous Difference", true, false);
|
||||
checkDiffAction("Diff Location Details", true, true);
|
||||
checkDiffAction("Show Diff Location Details", true, true);
|
||||
checkDiffAction("Show Diff Apply Settings", true, true);
|
||||
checkDiffAction("Get Differences", true, true);
|
||||
checkDiffAction("Select All Differences", true, true);
|
||||
@ -699,7 +699,7 @@ public class DiffTest extends DiffTestAdapter {
|
||||
checkDiffAction("Ignore Selection and Goto Next Difference", false, false);
|
||||
checkDiffAction("Next Difference", false, false);
|
||||
checkDiffAction("Previous Difference", false, false);
|
||||
checkDiffAction("Diff Location Details", false, false);
|
||||
checkDiffAction("Show Diff Location Details", false, false);
|
||||
checkDiffAction("Show Diff Apply Settings", false, false);
|
||||
checkDiffAction("Get Differences", false, false);
|
||||
checkDiffAction("Select All Differences", false, false);
|
||||
@ -715,7 +715,7 @@ public class DiffTest extends DiffTestAdapter {
|
||||
checkDiffAction("Ignore Selection and Goto Next Difference", false, false);
|
||||
checkDiffAction("Next Difference", false, false);
|
||||
checkDiffAction("Previous Difference", false, false);
|
||||
checkDiffAction("Diff Location Details", false, false);
|
||||
checkDiffAction("Show Diff Location Details", false, false);
|
||||
checkDiffAction("Show Diff Apply Settings", false, false);
|
||||
checkDiffAction("Get Differences", false, false);
|
||||
checkDiffAction("Select All Differences", false, false);
|
||||
@ -732,7 +732,7 @@ public class DiffTest extends DiffTestAdapter {
|
||||
checkDiffAction("Ignore Selection and Goto Next Difference", true, false);
|
||||
checkDiffAction("Next Difference", true, true);
|
||||
checkDiffAction("Previous Difference", true, true);
|
||||
checkDiffAction("Diff Location Details", true, true);
|
||||
checkDiffAction("Show Diff Location Details", true, true);
|
||||
checkDiffAction("Show Diff Apply Settings", true, true);
|
||||
checkDiffAction("Get Differences", true, true);
|
||||
checkDiffAction("Select All Differences", true, true);
|
||||
|
@ -67,6 +67,7 @@ public abstract class AbstractDockingTool implements DockingTool {
|
||||
@Override
|
||||
public void removeComponentProvider(ComponentProvider provider) {
|
||||
Runnable r = () -> {
|
||||
toolActions.removeGlobalAction(provider.getShowProviderAction());
|
||||
toolActions.removeActions(provider);
|
||||
winMgr.removeComponent(provider);
|
||||
};
|
||||
|
@ -168,7 +168,8 @@ class DockableToolBarManager {
|
||||
private DockableComponent dockableComponent;
|
||||
|
||||
ToolBarCloseAction(DockableComponent dockableComponent) {
|
||||
super("Close Window", DockingWindowManager.DOCKING_WINDOWS_OWNER);
|
||||
super("Close Window", DockingWindowManager.DOCKING_WINDOWS_OWNER,
|
||||
KeyBindingType.UNSUPPORTED);
|
||||
this.dockableComponent = dockableComponent;
|
||||
setDescription("Close Window");
|
||||
setToolBarData(new ToolBarData(closeIcon, null));
|
||||
|
@ -47,16 +47,14 @@ import util.CollectionUtils;
|
||||
* Manages the "Docking" arrangement of a set of components and actions. The components can be "docked"
|
||||
* together or exist in their own window. Actions can be associated with components so they
|
||||
* "move" with the component as it moved from one location to another.
|
||||
*
|
||||
* <P>
|
||||
* Components are added via ComponentProviders. A ComponentProvider is an interface for getting
|
||||
* a component and its related information. The docking window manager will get the component
|
||||
* from the provider as needed. It is up to the provider if it wants to reuse the component or
|
||||
* recreate a new one when the component is requested. When the user "hides" (by using
|
||||
* the x button on the component area) a component, the docking window manager removes all
|
||||
* recreate a new one when the component is requested. When the user hides a component (by using
|
||||
* the x button on the component header), the docking window manager removes all
|
||||
* knowledge of the component and will request it again from the provider if the component
|
||||
* becomes "unhidden". The provider is also notified whenever a component is hidden. Some
|
||||
* providers will use the notification to remove the provider from the docking window manager so
|
||||
* that the can not "unhide" the component using the built-in window menu.
|
||||
* is again shown. The provider is also notified whenever a component is hidden and shown.
|
||||
*/
|
||||
public class DockingWindowManager implements PropertyChangeListener, PlaceholderInstaller {
|
||||
|
||||
@ -712,8 +710,11 @@ public class DockingWindowManager implements PropertyChangeListener, Placeholder
|
||||
ComponentPlaceholder placeholder = getActivePlaceholder(provider);
|
||||
if (placeholder != null) {
|
||||
showComponent(placeholder, visibleState, true);
|
||||
return;
|
||||
}
|
||||
else {
|
||||
|
||||
if (visibleState) {
|
||||
|
||||
// a null placeholder implies the client is trying to show a provider that has not
|
||||
// been added to the tool
|
||||
Msg.warn(this, "Attempting to show an unknown Component Provider '" +
|
||||
|
@ -76,11 +76,7 @@ class ShowComponentAction extends DockingAction implements Comparable<ShowCompon
|
||||
|
||||
// keybinding data used to show the binding in the menu
|
||||
ComponentProvider provider = placeholder.getProvider();
|
||||
DockingActionIf action = provider.getShowProviderAction();
|
||||
KeyBindingData kbData = action.getKeyBindingData();
|
||||
if (kbData != null) {
|
||||
setKeyBindingData(kbData);
|
||||
}
|
||||
synchronizeKeyBinding(provider);
|
||||
|
||||
// Use provider Help for this action
|
||||
HelpLocation helpLocation = provider.getHelpLocation();
|
||||
@ -94,6 +90,21 @@ class ShowComponentAction extends DockingAction implements Comparable<ShowCompon
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Ensures that the given provider's key binding matches this class's key binding
|
||||
* @param provider the provider
|
||||
*/
|
||||
private void synchronizeKeyBinding(ComponentProvider provider) {
|
||||
DockingActionIf action = provider.getShowProviderAction();
|
||||
KeyBindingData defaultBinding = action.getDefaultKeyBindingData();
|
||||
setKeyBindingData(defaultBinding);
|
||||
|
||||
KeyBindingData kbData = action.getKeyBindingData();
|
||||
if (kbData != null) {
|
||||
setUnvalidatedKeyBindingData(kbData);
|
||||
}
|
||||
}
|
||||
|
||||
private static KeyBindingType createKeyBindingType(boolean isTransient,
|
||||
ComponentPlaceholder placeholder) {
|
||||
|
||||
|
@ -55,6 +55,16 @@ public interface DockingActionIf extends HelpDescriptor {
|
||||
*/
|
||||
public String getOwner();
|
||||
|
||||
/**
|
||||
* Returns a description of this actions owner. For most actions this will return the
|
||||
* same value as {@link #getOwner()}.
|
||||
*
|
||||
* @return the description
|
||||
*/
|
||||
public default String getOwnerDescription() {
|
||||
return getOwner();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a short description of this action. Generally used for a tooltip
|
||||
* @return the description
|
||||
|
@ -39,7 +39,7 @@ public class KeyBindingsManager implements PropertyChangeListener {
|
||||
actionToProviderMap = new HashMap<>();
|
||||
}
|
||||
|
||||
public void addAction(DockingActionIf action, ComponentProvider optionalProvider) {
|
||||
public void addAction(ComponentProvider optionalProvider, DockingActionIf action) {
|
||||
action.addPropertyChangeListener(this);
|
||||
if (optionalProvider != null) {
|
||||
actionToProviderMap.put(action, optionalProvider);
|
||||
@ -48,7 +48,7 @@ public class KeyBindingsManager implements PropertyChangeListener {
|
||||
KeyStroke keyBinding = action.getKeyBinding();
|
||||
|
||||
if (keyBinding != null) {
|
||||
addKeyBinding(action, optionalProvider, keyBinding);
|
||||
addKeyBinding(optionalProvider, action, keyBinding);
|
||||
}
|
||||
}
|
||||
|
||||
@ -67,7 +67,7 @@ public class KeyBindingsManager implements PropertyChangeListener {
|
||||
removeKeyBinding(action.getKeyBinding(), action);
|
||||
}
|
||||
|
||||
private void addKeyBinding(DockingActionIf action, ComponentProvider provider,
|
||||
private void addKeyBinding(ComponentProvider provider, DockingActionIf action,
|
||||
KeyStroke keyStroke) {
|
||||
if (ReservedKeyBindings.isReservedKeystroke(keyStroke)) {
|
||||
throw new AssertException("Cannot assign action to a reserved keystroke. " +
|
||||
@ -145,7 +145,7 @@ public class KeyBindingsManager implements PropertyChangeListener {
|
||||
if (newKeyData != null) {
|
||||
KeyStroke ks = newKeyData.getKeyBinding();
|
||||
if (ks != null) {
|
||||
addKeyBinding(action, actionToProviderMap.get(action), ks);
|
||||
addKeyBinding(actionToProviderMap.get(action), action, ks);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -63,6 +63,7 @@ public class MultipleKeyAction extends DockingKeyBindingAction {
|
||||
throw new IllegalArgumentException(
|
||||
"KeyStrokes don't match - was: " + keyStroke + " new: " + keyBinding);
|
||||
}
|
||||
|
||||
actions.add(new ActionData(action, provider));
|
||||
}
|
||||
|
||||
@ -273,5 +274,10 @@ public class MultipleKeyAction extends DockingKeyBindingAction {
|
||||
boolean isMyProvider(ComponentProvider otherProvider) {
|
||||
return provider == otherProvider;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return provider.toString() + " - " + action;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -34,6 +34,15 @@ public interface DockingToolActions {
|
||||
*/
|
||||
public void addLocalAction(ComponentProvider provider, DockingActionIf action);
|
||||
|
||||
/**
|
||||
* Gets the provider action by the given name
|
||||
*
|
||||
* @param provider the provider
|
||||
* @param actionName the action name
|
||||
* @return the action
|
||||
*/
|
||||
public DockingActionIf getLocalAction(ComponentProvider provider, String actionName);
|
||||
|
||||
/**
|
||||
* Removes the given provider's local action
|
||||
*
|
||||
|
@ -155,6 +155,7 @@ public class KeyEntryDialog extends DialogComponentProvider {
|
||||
|
||||
KeyStroke existingKeyStroke = action.getKeyBinding();
|
||||
if (Objects.equals(existingKeyStroke, newKeyStroke)) {
|
||||
setStatusText("Key binding unchanged");
|
||||
return;
|
||||
}
|
||||
|
||||
@ -177,11 +178,18 @@ public class KeyEntryDialog extends DialogComponentProvider {
|
||||
}
|
||||
|
||||
private void updateCollisionPane(KeyStroke ks) {
|
||||
clearStatusText();
|
||||
collisionPane.setText("");
|
||||
if (ks == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
KeyStroke existingKeyStroke = action.getKeyBinding();
|
||||
if (Objects.equals(existingKeyStroke, ks)) {
|
||||
setStatusText("Key binding unchanged");
|
||||
return;
|
||||
}
|
||||
|
||||
List<DockingActionIf> list = getManagedActionsForKeyStroke(ks);
|
||||
if (list.size() == 0) {
|
||||
return;
|
||||
@ -193,7 +201,7 @@ public class KeyEntryDialog extends DialogComponentProvider {
|
||||
for (int i = 0; i < list.size(); i++) {
|
||||
DockingActionIf a = list.get(i);
|
||||
|
||||
String collisionStr = "\t" + a.getName() + " (" + a.getOwner() + ")\n";
|
||||
String collisionStr = "\t" + a.getName() + " (" + a.getOwnerDescription() + ")\n";
|
||||
int offset = doc.getLength();
|
||||
doc.insertString(offset, collisionStr, textAttrSet);
|
||||
doc.setParagraphAttributes(offset, 1, tabAttrSet, false);
|
||||
@ -211,6 +219,7 @@ public class KeyEntryDialog extends DialogComponentProvider {
|
||||
if (multiAction == null) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
List<DockingActionIf> list = multiAction.getActions();
|
||||
Map<String, DockingActionIf> nameMap = new HashMap<>(list.size());
|
||||
|
||||
|
@ -85,13 +85,14 @@ public class SharedStubKeyBindingAction extends DockingAction implements Options
|
||||
updateActionKeyStrokeFromOptions(action, defaultKs);
|
||||
}
|
||||
|
||||
public String getOwnersDescription() {
|
||||
@Override
|
||||
public String getOwnerDescription() {
|
||||
List<String> owners = getDistinctOwners();
|
||||
Collections.sort(owners);
|
||||
if (owners.size() == 1) {
|
||||
return owners.get(0);
|
||||
}
|
||||
return '(' + StringUtils.join(owners, ", ") + ')';
|
||||
return StringUtils.join(owners, ", ");
|
||||
}
|
||||
|
||||
private List<String> getDistinctOwners() {
|
||||
@ -99,6 +100,11 @@ public class SharedStubKeyBindingAction extends DockingAction implements Options
|
||||
Set<DockingActionIf> actions = clientActions.keySet();
|
||||
for (DockingActionIf action : actions) {
|
||||
String owner = action.getOwner();
|
||||
if (DockingWindowManager.DOCKING_WINDOWS_OWNER.equals(owner)) {
|
||||
// special case: this is the owner for special system-level actions
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!results.contains(owner)) {
|
||||
results.add(owner);
|
||||
}
|
||||
@ -139,12 +145,16 @@ public class SharedStubKeyBindingAction extends DockingAction implements Options
|
||||
|
||||
private void updateActionKeyStrokeFromOptions(DockingActionIf action, KeyStroke defaultKs) {
|
||||
|
||||
KeyStroke stubKs = defaultKs;
|
||||
KeyStroke optionsKs = getKeyStrokeFromOptions(defaultKs);
|
||||
if (!Objects.equals(defaultKs, optionsKs)) {
|
||||
// we use the 'unvalidated' call since this value is provided by the user--we assume
|
||||
// that user input is correct; we only validate programmer input
|
||||
action.setUnvalidatedKeyBindingData(new KeyBindingData(optionsKs));
|
||||
stubKs = optionsKs;
|
||||
}
|
||||
|
||||
setUnvalidatedKeyBindingData(new KeyBindingData(stubKs));
|
||||
}
|
||||
|
||||
private KeyStroke getKeyStrokeFromOptions(KeyStroke validatedKeyStroke) {
|
||||
|
@ -115,27 +115,21 @@ public class ToolActions implements DockingToolActions, PropertyChangeListener {
|
||||
|
||||
action.addPropertyChangeListener(this);
|
||||
addActionToMap(action);
|
||||
setKeyBindingOption(action);
|
||||
keyBindingsManager.addAction(action, provider);
|
||||
initializeKeyBinding(provider, action);
|
||||
actionGuiHelper.addLocalAction(provider, action);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds the action to the tool.
|
||||
* @param action the action to be added.
|
||||
*/
|
||||
@Override
|
||||
public synchronized void addGlobalAction(DockingActionIf action) {
|
||||
checkForAlreadyAddedAction(null, action);
|
||||
|
||||
action.addPropertyChangeListener(this);
|
||||
addActionToMap(action);
|
||||
setKeyBindingOption(action);
|
||||
keyBindingsManager.addAction(action, null);
|
||||
initializeKeyBinding(null, action);
|
||||
actionGuiHelper.addToolAction(action);
|
||||
}
|
||||
|
||||
private void setKeyBindingOption(DockingActionIf action) {
|
||||
private void initializeKeyBinding(ComponentProvider provider, DockingActionIf action) {
|
||||
|
||||
KeyBindingType type = action.getKeyBindingType();
|
||||
if (!type.supportsKeyBindings()) {
|
||||
@ -143,7 +137,7 @@ public class ToolActions implements DockingToolActions, PropertyChangeListener {
|
||||
}
|
||||
|
||||
if (type.isShared()) {
|
||||
installSharedKeyBinding(action);
|
||||
installSharedKeyBinding(provider, action);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -154,9 +148,11 @@ public class ToolActions implements DockingToolActions, PropertyChangeListener {
|
||||
if (!Objects.equals(ks, newKs)) {
|
||||
action.setUnvalidatedKeyBindingData(new KeyBindingData(newKs));
|
||||
}
|
||||
|
||||
keyBindingsManager.addAction(provider, action);
|
||||
}
|
||||
|
||||
private void installSharedKeyBinding(DockingActionIf action) {
|
||||
private void installSharedKeyBinding(ComponentProvider provider, DockingActionIf action) {
|
||||
String name = action.getName();
|
||||
KeyStroke defaultKeyStroke = action.getKeyBinding();
|
||||
|
||||
@ -172,6 +168,9 @@ public class ToolActions implements DockingToolActions, PropertyChangeListener {
|
||||
});
|
||||
|
||||
stub.addClientAction(action);
|
||||
|
||||
// note: only put the stub in the manager, not the actual action
|
||||
keyBindingsManager.addAction(provider, stub);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -318,10 +317,12 @@ public class ToolActions implements DockingToolActions, PropertyChangeListener {
|
||||
for (DockingActionIf action : set) {
|
||||
removeLocalAction(provider, action);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private void removeAction(DockingActionIf action) {
|
||||
|
||||
keyBindingsManager.removeAction(action);
|
||||
|
||||
getActionStorage(action).remove(action);
|
||||
if (!action.getKeyBindingType().isShared()) {
|
||||
return;
|
||||
@ -370,6 +371,19 @@ public class ToolActions implements DockingToolActions, PropertyChangeListener {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public DockingActionIf getLocalAction(ComponentProvider provider, String actionName) {
|
||||
|
||||
Iterator<DockingActionIf> it = actionGuiHelper.getComponentActions(provider);
|
||||
while (it.hasNext()) {
|
||||
DockingActionIf action = it.next();
|
||||
if (action.getName().equals(actionName)) {
|
||||
return action;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public Action getAction(KeyStroke ks) {
|
||||
return keyBindingsManager.getDockingKeyAction(ks);
|
||||
}
|
||||
|
@ -43,6 +43,7 @@ import com.google.common.collect.Sets;
|
||||
import docking.*;
|
||||
import docking.action.DockingActionIf;
|
||||
import docking.action.ToggleDockingActionIf;
|
||||
import docking.actions.DockingToolActions;
|
||||
import docking.dnd.GClipboard;
|
||||
import docking.framework.DockingApplicationConfiguration;
|
||||
import docking.menu.DockingToolbarButton;
|
||||
@ -1195,8 +1196,18 @@ public abstract class AbstractDockingTest extends AbstractGenericTest {
|
||||
return CollectionUtils.any(actions);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the action by the given name that belongs to the given provider
|
||||
*
|
||||
* @param provider the provider
|
||||
* @param actionName the action name
|
||||
* @return the action
|
||||
*/
|
||||
public static DockingActionIf getLocalAction(ComponentProvider provider, String actionName) {
|
||||
return getAction(provider.getTool(), provider.getName(), actionName);
|
||||
DockingTool tool = provider.getTool();
|
||||
DockingToolActions toolActions = tool.getToolActions();
|
||||
DockingActionIf action = toolActions.getLocalAction(provider, actionName);
|
||||
return action;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1850,10 +1861,12 @@ public abstract class AbstractDockingTest extends AbstractGenericTest {
|
||||
*
|
||||
* @param tool the tool in which the provider lives
|
||||
* @param name the name of the provider to show
|
||||
* @return the newly shown provider
|
||||
*/
|
||||
public void showProvider(DockingTool tool, String name) {
|
||||
public ComponentProvider showProvider(DockingTool tool, String name) {
|
||||
ComponentProvider provider = tool.getComponentProvider(name);
|
||||
tool.showComponentProvider(provider, true);
|
||||
return provider;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -32,7 +32,6 @@ import docking.KeyEntryTextField;
|
||||
import docking.action.DockingActionIf;
|
||||
import docking.action.KeyBindingData;
|
||||
import docking.actions.KeyBindingUtils;
|
||||
import docking.actions.SharedStubKeyBindingAction;
|
||||
import docking.tool.util.DockingToolConstants;
|
||||
import docking.widgets.MultiLineLabel;
|
||||
import docking.widgets.OptionDialog;
|
||||
@ -708,18 +707,11 @@ public class KeyBindingsPanel extends JPanel {
|
||||
}
|
||||
return "";
|
||||
case PLUGIN_NAME:
|
||||
return getOwner(action);
|
||||
return action.getOwnerDescription();
|
||||
}
|
||||
return "Unknown Column!";
|
||||
}
|
||||
|
||||
private String getOwner(DockingActionIf action) {
|
||||
if (action instanceof SharedStubKeyBindingAction) {
|
||||
return ((SharedStubKeyBindingAction) action).getOwnersDescription();
|
||||
}
|
||||
return action.getOwner();
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<DockingActionIf> getModelData() {
|
||||
return tableActions;
|
||||
|
Loading…
Reference in New Issue
Block a user