mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2025-10-04 10:19:23 +02:00
GT-2925 - Key Bindings - Support Window Menu Provider Key Bindings -
Step 7 - Untangled and removed the key binding management from the ActionToGuiMapper; fixed bugs and tests
This commit is contained in:
parent
d684ee3ce6
commit
3946a05ded
27 changed files with 515 additions and 345 deletions
|
@ -22,7 +22,6 @@ import javax.swing.ToolTipManager;
|
|||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
|
||||
import docking.DockingWindowManager;
|
||||
import docking.framework.SplashScreen;
|
||||
import ghidra.base.help.GhidraHelpService;
|
||||
import ghidra.framework.Application;
|
||||
|
@ -86,7 +85,6 @@ public class GhidraRun implements GhidraLaunchable {
|
|||
updateSplashScreenStatusMessage("Populating Ghidra help...");
|
||||
GhidraHelpService.install();
|
||||
|
||||
DockingWindowManager.enableDiagnosticActions(SystemUtilities.isInDevelopmentMode());
|
||||
ExtensionUtils.cleanupUninstalledExtensions();
|
||||
|
||||
// Allows handling of old content which did not have a content type property
|
||||
|
|
|
@ -32,7 +32,7 @@ public class TestTool extends GhidraTool {
|
|||
@Override
|
||||
protected DockingWindowManager createDockingWindowManager(boolean isDockable, boolean hasStatus,
|
||||
boolean isModal) {
|
||||
return new DockingWindowManager("EMPTY", null, this, isModal, isDockable, hasStatus, null);
|
||||
return new DockingWindowManager(this, null, this, isModal, isDockable, hasStatus, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -27,6 +27,7 @@ import org.junit.*;
|
|||
import docking.action.DockingActionIf;
|
||||
import docking.action.KeyBindingData;
|
||||
import docking.actions.KeyEntryDialog;
|
||||
import docking.actions.ToolActions;
|
||||
import docking.tool.util.DockingToolConstants;
|
||||
import ghidra.framework.options.ToolOptions;
|
||||
import ghidra.framework.plugintool.PluginTool;
|
||||
|
@ -235,15 +236,6 @@ public class ComponentProviderActionsTest extends AbstractGhidraHeadedIntegratio
|
|||
// Private Methods
|
||||
//==================================================================================================
|
||||
|
||||
private void assertShowProviderActionIsInToolbar() {
|
||||
assertNotNull("The 'Show Provider' action is not in the toolbar",
|
||||
getToolbarShowProviderAction());
|
||||
}
|
||||
|
||||
private void assertShowProviderActionNotInToolbar() {
|
||||
assertNull("The 'Show Provider' action is in the toolbar", getToolbarShowProviderAction());
|
||||
}
|
||||
|
||||
private void switchToTransientProvider() {
|
||||
provider.setTransient();
|
||||
}
|
||||
|
@ -390,9 +382,8 @@ public class ComponentProviderActionsTest extends AbstractGhidraHeadedIntegratio
|
|||
}
|
||||
|
||||
private void performLaunchKeyStrokeDialogAction() {
|
||||
DockingWindowManager dwm = tool.getWindowManager();
|
||||
ActionToGuiMapper actionMapper = dwm.getActionToGuiMapper();
|
||||
Action action = actionMapper.getDockingKeyAction(KeyStroke.getKeyStroke("F4"));
|
||||
ToolActions toolActions = ((AbstractDockingTool) tool).getToolActions();
|
||||
Action action = toolActions.getAction(KeyStroke.getKeyStroke("F4"));
|
||||
assertNotNull(action);
|
||||
runSwing(() -> action.actionPerformed(new ActionEvent(this, 0, "")), false);
|
||||
}
|
||||
|
|
|
@ -32,12 +32,11 @@ import org.junit.Test;
|
|||
import docking.test.AbstractDockingTest;
|
||||
import docking.widgets.label.GDLabel;
|
||||
import ghidra.framework.plugintool.ComponentProviderAdapter;
|
||||
import ghidra.test.DummyTool;
|
||||
|
||||
public class DockingWindowManagerTest extends AbstractDockingTest {
|
||||
|
||||
public DockingWindowManagerTest() {
|
||||
super();
|
||||
}
|
||||
private DockingTool tool = new DummyTool();
|
||||
|
||||
@Test
|
||||
public void testDefaultGroupWindowPosition() {
|
||||
|
@ -46,7 +45,7 @@ public class DockingWindowManagerTest extends AbstractDockingTest {
|
|||
// default window position.
|
||||
//
|
||||
|
||||
DockingWindowManager dwm = new DockingWindowManager("test", (List<Image>) null, null);
|
||||
DockingWindowManager dwm = new DockingWindowManager(tool, (List<Image>) null, null);
|
||||
|
||||
ComponentProvider providerA = addProvider(dwm, "A", "a", RIGHT);
|
||||
ComponentProvider providerB = addProvider(dwm, "B", "b", BOTTOM);
|
||||
|
@ -66,7 +65,7 @@ public class DockingWindowManagerTest extends AbstractDockingTest {
|
|||
// intragroup window position. Note: 'Stacked' is the default.
|
||||
//
|
||||
|
||||
DockingWindowManager dwm = new DockingWindowManager("test", (List<Image>) null, null);
|
||||
DockingWindowManager dwm = new DockingWindowManager(tool, (List<Image>) null, null);
|
||||
|
||||
ComponentProvider providerA1 = addProvider(dwm, "A1", "a", RIGHT, STACK);
|
||||
ComponentProvider providerA2 = addProvider(dwm, "A2", "a", BOTTOM, STACK);
|
||||
|
@ -84,7 +83,7 @@ public class DockingWindowManagerTest extends AbstractDockingTest {
|
|||
// intragroup window position.
|
||||
//
|
||||
|
||||
DockingWindowManager dwm = new DockingWindowManager("test", (List<Image>) null, null);
|
||||
DockingWindowManager dwm = new DockingWindowManager(tool, (List<Image>) null, null);
|
||||
|
||||
ComponentProvider providerA1 = addProvider(dwm, "A1", "a", RIGHT, STACK);
|
||||
ComponentProvider providerA2 = addProvider(dwm, "A2", "a", LEFT, BOTTOM);
|
||||
|
@ -101,7 +100,7 @@ public class DockingWindowManagerTest extends AbstractDockingTest {
|
|||
// intragroup window position.
|
||||
//
|
||||
|
||||
DockingWindowManager dwm = new DockingWindowManager("test", (List<Image>) null, null);
|
||||
DockingWindowManager dwm = new DockingWindowManager(tool, (List<Image>) null, null);
|
||||
|
||||
ComponentProvider providerA1 = addProvider(dwm, "A1", "a", RIGHT, WINDOW);
|
||||
ComponentProvider providerA2 = addProvider(dwm, "A2", "a", LEFT, WINDOW);
|
||||
|
@ -122,7 +121,7 @@ public class DockingWindowManagerTest extends AbstractDockingTest {
|
|||
//
|
||||
|
||||
// note: the positions specified here are for default positions, not intragroup positions
|
||||
DockingWindowManager dwm = new DockingWindowManager("test", (List<Image>) null, null);
|
||||
DockingWindowManager dwm = new DockingWindowManager(tool, (List<Image>) null, null);
|
||||
|
||||
ComponentProvider providerA = addProvider(dwm, "A", "a", RIGHT, STACK);
|
||||
ComponentProvider providerAB = addProvider(dwm, "AB", "a.b", BOTTOM, STACK);
|
||||
|
@ -143,7 +142,7 @@ public class DockingWindowManagerTest extends AbstractDockingTest {
|
|||
//
|
||||
|
||||
// note: the positions specified here are for default positions, not intragroup positions
|
||||
DockingWindowManager dwm = new DockingWindowManager("test", (List<Image>) null, null);
|
||||
DockingWindowManager dwm = new DockingWindowManager(tool, (List<Image>) null, null);
|
||||
|
||||
ComponentProvider providerA = addProvider(dwm, "A", "a", RIGHT, BOTTOM);
|
||||
ComponentProvider providerAB = addProvider(dwm, "AB", "a.b", BOTTOM, TOP);
|
||||
|
@ -181,8 +180,7 @@ public class DockingWindowManagerTest extends AbstractDockingTest {
|
|||
// Test that, for unrelated groups, the layout info stored in XML is re-used when providers
|
||||
// are shown after that XML is restored--even if the window positioning changes
|
||||
//
|
||||
final DockingWindowManager dwm1 =
|
||||
new DockingWindowManager("test", (List<Image>) null, null);
|
||||
final DockingWindowManager dwm1 = new DockingWindowManager(tool, (List<Image>) null, null);
|
||||
|
||||
ComponentProvider providerA = addProvider(dwm1, "A", "a", RIGHT);
|
||||
ComponentProvider providerB = addProvider(dwm1, "B", "b", BOTTOM);
|
||||
|
@ -217,7 +215,7 @@ public class DockingWindowManagerTest extends AbstractDockingTest {
|
|||
// Test that, for related groups, the layout info stored in XML is re-used when providers
|
||||
// are shown after that XML is restored--even if the window positioning changes
|
||||
//
|
||||
DockingWindowManager dwm1 = new DockingWindowManager("test", (List<Image>) null, null);
|
||||
DockingWindowManager dwm1 = new DockingWindowManager(tool, (List<Image>) null, null);
|
||||
|
||||
ComponentProvider providerA = addProvider(dwm1, "A", "a", RIGHT);
|
||||
ComponentProvider providerAB = addProvider(dwm1, "AB", "a.b", BOTTOM);
|
||||
|
@ -253,7 +251,7 @@ public class DockingWindowManagerTest extends AbstractDockingTest {
|
|||
// and that a subgroup 'a.b' will open relative to the parent. **Make sure that this
|
||||
// works when the parent is the first provider open.
|
||||
//
|
||||
DockingWindowManager dwm = new DockingWindowManager("test", (List<Image>) null, null);
|
||||
DockingWindowManager dwm = new DockingWindowManager(tool, (List<Image>) null, null);
|
||||
|
||||
ComponentProvider providerA = addProvider(dwm, "A", "a", TOP, RIGHT);
|
||||
ComponentProvider providerAB = addProvider(dwm, "AB", "a.b", RIGHT, BOTTOM);
|
||||
|
@ -270,7 +268,7 @@ public class DockingWindowManagerTest extends AbstractDockingTest {
|
|||
// and that a subgroup 'a.b' will open relative to the parent. **Make sure that this
|
||||
// works when the subgroup is the first provider open.
|
||||
//
|
||||
DockingWindowManager dwm = new DockingWindowManager("test", (List<Image>) null, null);
|
||||
DockingWindowManager dwm = new DockingWindowManager(tool, (List<Image>) null, null);
|
||||
|
||||
ComponentProvider providerAB = addProvider(dwm, "AB", "a.b", RIGHT, BOTTOM);
|
||||
ComponentProvider providerA = addProvider(dwm, "A", "a", TOP, RIGHT);
|
||||
|
@ -288,7 +286,7 @@ public class DockingWindowManagerTest extends AbstractDockingTest {
|
|||
// Test that two providers that don't share an owner (the plugin) can share a group and
|
||||
// open relative to each other.
|
||||
//
|
||||
DockingWindowManager dwm = new DockingWindowManager("test", (List<Image>) null, null);
|
||||
DockingWindowManager dwm = new DockingWindowManager(tool, (List<Image>) null, null);
|
||||
|
||||
ComponentProvider p1 = addProvider(dwm, "Owner_1", "Name_1", "group", TOP, TOP);
|
||||
ComponentProvider p2 = addProvider(dwm, "Owner_2", "Name_2", "group", BOTTOM, RIGHT);
|
||||
|
@ -337,7 +335,7 @@ public class DockingWindowManagerTest extends AbstractDockingTest {
|
|||
|
||||
*/
|
||||
|
||||
DockingWindowManager dwm = new DockingWindowManager("test", (List<Image>) null, null);
|
||||
DockingWindowManager dwm = new DockingWindowManager(tool, (List<Image>) null, null);
|
||||
|
||||
ComponentProvider pA = addProvider(dwm, "Owner_1", "A", "a", LEFT, LEFT);
|
||||
ComponentProvider pB = addProvider(dwm, "Owner_2", "B", "b", RIGHT, RIGHT);
|
||||
|
@ -410,7 +408,7 @@ public class DockingWindowManagerTest extends AbstractDockingTest {
|
|||
|
||||
private DockingWindowManager createNewDockingWindowManagerFromXML(final Element element) {
|
||||
final DockingWindowManager dwm2 =
|
||||
new DockingWindowManager("text2", (List<Image>) null, null);
|
||||
new DockingWindowManager(new DummyTool("Tool2"), (List<Image>) null, null);
|
||||
|
||||
runSwing(() -> {
|
||||
dwm2.setVisible(true);
|
||||
|
|
|
@ -30,10 +30,12 @@ import org.junit.Test;
|
|||
import docking.DockingWindowManager;
|
||||
import docking.test.AbstractDockingTest;
|
||||
import docking.widgets.textfield.IntegerTextField;
|
||||
import ghidra.test.DummyTool;
|
||||
|
||||
public class NumberInputDialogTest extends AbstractDockingTest {
|
||||
|
||||
private DockingWindowManager dwm = new DockingWindowManager("test", (List<Image>) null, null);
|
||||
private DockingWindowManager dwm =
|
||||
new DockingWindowManager(new DummyTool(), (List<Image>) null, null);
|
||||
private NumberInputDialog dialog;
|
||||
private JButton okButton;
|
||||
private JTextField textField;
|
||||
|
|
|
@ -28,6 +28,7 @@ import docking.widgets.filter.*;
|
|||
import docking.widgets.table.model.DirData;
|
||||
import docking.widgets.table.model.TestDataModel;
|
||||
import ghidra.test.AbstractGhidraHeadedIntegrationTest;
|
||||
import ghidra.test.DummyTool;
|
||||
import ghidra.util.table.GhidraTable;
|
||||
|
||||
public class GhidraTableFilterTest extends AbstractGhidraHeadedIntegrationTest {
|
||||
|
@ -50,7 +51,7 @@ public class GhidraTableFilterTest extends AbstractGhidraHeadedIntegrationTest {
|
|||
filteredModel = filterPanel.getTableFilterModel();
|
||||
table.setAutoLookupColumn(4);
|
||||
|
||||
winMgr = new DockingWindowManager("Tests", null, null);
|
||||
winMgr = new DockingWindowManager(new DummyTool(), null, null);
|
||||
winMgr.addComponent(new TestTableComponentProvider());
|
||||
winMgr.setVisible(true);
|
||||
}
|
||||
|
|
|
@ -28,6 +28,7 @@ import org.jdom.Element;
|
|||
|
||||
import docking.*;
|
||||
import docking.action.DockingActionIf;
|
||||
import docking.actions.DockingToolActions;
|
||||
import ghidra.framework.model.*;
|
||||
import ghidra.framework.options.ToolOptions;
|
||||
import ghidra.framework.plugintool.PluginEvent;
|
||||
|
@ -42,6 +43,8 @@ public class DummyTool implements Tool {
|
|||
private ToolIconURL iconURL;
|
||||
private Project project;
|
||||
|
||||
private DockingToolActions toolActions = new DummyToolActions();
|
||||
|
||||
public DummyTool() {
|
||||
this(DEFAULT_NAME);
|
||||
}
|
||||
|
@ -305,6 +308,11 @@ public class DummyTool implements Tool {
|
|||
return Collections.emptySet();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ComponentProvider getActiveComponentProvider() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void showComponentProvider(ComponentProvider componentProvider, boolean visible) {
|
||||
//do nothing
|
||||
|
@ -345,6 +353,11 @@ public class DummyTool implements Tool {
|
|||
//do nothing
|
||||
}
|
||||
|
||||
@Override
|
||||
public ActionContext getGlobalContext() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setStatusInfo(String text) {
|
||||
//do nothing
|
||||
|
@ -389,4 +402,9 @@ public class DummyTool implements Tool {
|
|||
public void removeContextListener(DockingContextListener listener) {
|
||||
//do nothing
|
||||
}
|
||||
|
||||
@Override
|
||||
public DockingToolActions getToolActions() {
|
||||
return toolActions;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,66 @@
|
|||
/* ###
|
||||
* 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.test;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
import docking.ComponentProvider;
|
||||
import docking.action.DockingActionIf;
|
||||
import docking.actions.DockingToolActions;
|
||||
|
||||
public class DummyToolActions implements DockingToolActions {
|
||||
|
||||
@Override
|
||||
public void addLocalAction(ComponentProvider provider, DockingActionIf action) {
|
||||
// stub
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addGlobalAction(DockingActionIf action) {
|
||||
// stub
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeGlobalAction(DockingActionIf action) {
|
||||
// stub
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeActions(String owner) {
|
||||
// stub
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<DockingActionIf> getActions(String owner) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<DockingActionIf> getAllActions() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeLocalAction(ComponentProvider provider, DockingActionIf action) {
|
||||
// stub
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeActions(ComponentProvider provider) {
|
||||
// stub
|
||||
}
|
||||
|
||||
}
|
|
@ -59,7 +59,7 @@ public abstract class AbstractDockingTool implements DockingTool {
|
|||
public void addComponentProvider(ComponentProvider provider, boolean show) {
|
||||
Runnable r = () -> {
|
||||
winMgr.addComponent(provider, show);
|
||||
toolActions.addToolAction(provider.getShowProviderAction());
|
||||
toolActions.addGlobalAction(provider.getShowProviderAction());
|
||||
};
|
||||
Swing.runNow(r);
|
||||
}
|
||||
|
@ -67,7 +67,7 @@ public abstract class AbstractDockingTool implements DockingTool {
|
|||
@Override
|
||||
public void removeComponentProvider(ComponentProvider provider) {
|
||||
Runnable r = () -> {
|
||||
toolActions.removeComponentActions(provider);
|
||||
toolActions.removeActions(provider);
|
||||
winMgr.removeComponent(provider);
|
||||
};
|
||||
Swing.runNow(r);
|
||||
|
@ -99,12 +99,12 @@ public abstract class AbstractDockingTool implements DockingTool {
|
|||
|
||||
@Override
|
||||
public void addAction(DockingActionIf action) {
|
||||
toolActions.addToolAction(action);
|
||||
toolActions.addGlobalAction(action);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeAction(DockingActionIf action) {
|
||||
toolActions.removeToolAction(action);
|
||||
toolActions.removeGlobalAction(action);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -114,15 +114,12 @@ public abstract class AbstractDockingTool implements DockingTool {
|
|||
|
||||
@Override
|
||||
public void removeLocalAction(ComponentProvider provider, DockingActionIf action) {
|
||||
toolActions.removeProviderAction(provider, action);
|
||||
toolActions.removeLocalAction(provider, action);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<DockingActionIf> getAllActions() {
|
||||
Set<DockingActionIf> actions = toolActions.getAllActions();
|
||||
ActionToGuiMapper am = winMgr.getActionToGuiMapper();
|
||||
actions.addAll(am.getAllActions());
|
||||
return actions;
|
||||
return toolActions.getAllActions();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -130,6 +127,11 @@ public abstract class AbstractDockingTool implements DockingTool {
|
|||
return toolActions.getActions(owner);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ComponentProvider getActiveComponentProvider() {
|
||||
return winMgr.getActiveComponentProvider();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void showComponentProvider(ComponentProvider provider, boolean visible) {
|
||||
Runnable r = () -> winMgr.showComponent(provider, visible);
|
||||
|
@ -176,6 +178,11 @@ public abstract class AbstractDockingTool implements DockingTool {
|
|||
winMgr.contextChanged(provider);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ActionContext getGlobalContext() {
|
||||
return winMgr.getGlobalContext();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addContextListener(DockingContextListener listener) {
|
||||
winMgr.addContextListener(listener);
|
||||
|
@ -200,4 +207,9 @@ public abstract class AbstractDockingTool implements DockingTool {
|
|||
public boolean hasConfigChanged() {
|
||||
return configChangedFlag;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ToolActions getToolActions() {
|
||||
return toolActions;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -18,7 +18,6 @@ package docking;
|
|||
import java.util.Iterator;
|
||||
|
||||
import docking.action.DockingActionIf;
|
||||
import docking.action.KeyBindingsManager;
|
||||
|
||||
/**
|
||||
* A class that exists primarily to provide access to action-related package-level methods of the
|
||||
|
@ -80,15 +79,6 @@ public class ActionToGuiHelper {
|
|||
windowManager.removeProviderAction(provider, action);
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes key bindings manager of docking window manager
|
||||
*
|
||||
* @param keyBindingsManager key bindings manager
|
||||
*/
|
||||
public void setKeyBindingsManager(KeyBindingsManager keyBindingsManager) {
|
||||
windowManager.setKeyBindingsManager(keyBindingsManager);
|
||||
}
|
||||
|
||||
/**
|
||||
* Call this method to signal that key bindings for one or more actions have changed
|
||||
*/
|
||||
|
|
|
@ -16,63 +16,38 @@
|
|||
package docking;
|
||||
|
||||
import java.awt.event.MouseEvent;
|
||||
import java.util.*;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.Set;
|
||||
|
||||
import javax.swing.*;
|
||||
import javax.swing.JComponent;
|
||||
import javax.swing.MenuSelectionManager;
|
||||
|
||||
import docking.action.*;
|
||||
import docking.action.DockingActionIf;
|
||||
import docking.menu.MenuGroupMap;
|
||||
import docking.menu.MenuHandler;
|
||||
import ghidra.util.*;
|
||||
import ghidra.util.HelpLocation;
|
||||
|
||||
/**
|
||||
* Manages the global actions for the menu and toolbar.
|
||||
*/
|
||||
public class ActionToGuiMapper {
|
||||
|
||||
private static boolean enableDiagnosticActions;
|
||||
|
||||
private Set<DockingActionIf> globalActions = new LinkedHashSet<>();
|
||||
|
||||
private MenuHandler menuBarMenuHandler;
|
||||
private MenuGroupMap menuGroupMap;
|
||||
|
||||
private KeyBindingsManager keyBindingsManager;
|
||||
private GlobalMenuAndToolBarManager menuAndToolBarManager;
|
||||
private PopupActionManager popupActionManager;
|
||||
|
||||
ActionToGuiMapper(DockingWindowManager winMgr, KeyBindingsManager keyBindingsManager) {
|
||||
this.keyBindingsManager = keyBindingsManager;
|
||||
ActionToGuiMapper(DockingWindowManager winMgr) {
|
||||
menuGroupMap = new MenuGroupMap();
|
||||
menuBarMenuHandler = new MenuBarMenuHandler(winMgr);
|
||||
menuAndToolBarManager =
|
||||
new GlobalMenuAndToolBarManager(winMgr, menuBarMenuHandler, menuGroupMap);
|
||||
popupActionManager = new PopupActionManager(winMgr, menuGroupMap);
|
||||
|
||||
initializeHelpActions();
|
||||
}
|
||||
|
||||
private void initializeHelpActions() {
|
||||
DockingWindowsContextSensitiveHelpListener.install();
|
||||
|
||||
keyBindingsManager.addReservedAction(new HelpAction(false, ReservedKeyBindings.HELP_KEY1));
|
||||
keyBindingsManager.addReservedAction(new HelpAction(false, ReservedKeyBindings.HELP_KEY2));
|
||||
keyBindingsManager.addReservedAction(
|
||||
new HelpAction(true, ReservedKeyBindings.HELP_INFO_KEY));
|
||||
|
||||
if (enableDiagnosticActions) {
|
||||
keyBindingsManager.addReservedAction(new ShowFocusInfoAction());
|
||||
keyBindingsManager.addReservedAction(new ShowFocusCycleAction());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A static initializer allowing additional diagnostic actions
|
||||
* to be added to all frame and dialog windows.
|
||||
* @param enable
|
||||
*/
|
||||
static void enableDiagnosticActions(boolean enable) {
|
||||
enableDiagnosticActions = enable;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -87,41 +62,12 @@ public class ActionToGuiMapper {
|
|||
DockingWindowManager.getHelpService().registerHelp(c, helpLocation);
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes all actions associated with the given owner
|
||||
* @param owner the owner of all actions to be removed.
|
||||
*/
|
||||
void removeAll(String owner) {
|
||||
Iterator<DockingActionIf> iter = new ArrayList<>(globalActions).iterator();
|
||||
List<DockingActionIf> removedList = new ArrayList<>();
|
||||
while (iter.hasNext()) {
|
||||
DockingActionIf action = iter.next();
|
||||
if (owner.equals(action.getOwner())) {
|
||||
keyBindingsManager.removeAction(action);
|
||||
menuAndToolBarManager.removeAction(action);
|
||||
popupActionManager.removeAction(action);
|
||||
removedList.add(action);
|
||||
}
|
||||
}
|
||||
|
||||
globalActions.removeAll(removedList);
|
||||
}
|
||||
|
||||
void addLocalAction(DockingActionIf action, ComponentProvider provider) {
|
||||
keyBindingsManager.addAction(action, provider);
|
||||
}
|
||||
|
||||
void removeLocalAction(DockingActionIf action) {
|
||||
keyBindingsManager.removeAction(action);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds the given Global action to the menu and/or toolbar.
|
||||
* @param action the action to be added.
|
||||
*/
|
||||
void addToolAction(DockingActionIf action) {
|
||||
if (globalActions.add(action)) {
|
||||
keyBindingsManager.addAction(action, null);
|
||||
popupActionManager.addAction(action);
|
||||
menuAndToolBarManager.addAction(action);
|
||||
}
|
||||
|
@ -132,24 +78,11 @@ public class ActionToGuiMapper {
|
|||
* @param action the action to be removed.
|
||||
*/
|
||||
void removeToolAction(DockingActionIf action) {
|
||||
keyBindingsManager.removeAction(action);
|
||||
popupActionManager.removeAction(action);
|
||||
menuAndToolBarManager.removeAction(action);
|
||||
globalActions.remove(action);
|
||||
}
|
||||
|
||||
public Set<DockingActionIf> getAllActions() {
|
||||
|
||||
// Note: this method is called by non-Swing test code. Synchronize access to the
|
||||
// data structures in this class in order to prevent concurrent mod exceptions.
|
||||
Set<DockingActionIf> actions = new HashSet<>();
|
||||
SystemUtilities.runSwingNow(() -> {
|
||||
actions.addAll(globalActions);
|
||||
actions.addAll(keyBindingsManager.getLocalActions());
|
||||
});
|
||||
return actions;
|
||||
}
|
||||
|
||||
Set<DockingActionIf> getGlobalActions() {
|
||||
return globalActions;
|
||||
}
|
||||
|
@ -162,28 +95,16 @@ public class ActionToGuiMapper {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Close all menus (includes popup menus)
|
||||
*/
|
||||
private void dismissMenus() {
|
||||
MenuSelectionManager.defaultManager().clearSelectedPath();
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the menu and toolbar to reflect any changes in the set of actions.
|
||||
*
|
||||
*/
|
||||
void update() {
|
||||
menuAndToolBarManager.update();
|
||||
contextChangedAll();
|
||||
}
|
||||
|
||||
/**
|
||||
* Releases all resources and makes this object unavailable for future use.
|
||||
*
|
||||
*/
|
||||
void dispose() {
|
||||
keyBindingsManager.dispose();
|
||||
popupActionManager.dispose();
|
||||
menuAndToolBarManager.dispose();
|
||||
globalActions.clear();
|
||||
|
@ -216,8 +137,4 @@ public class ActionToGuiMapper {
|
|||
public void showPopupMenu(ComponentPlaceholder componentInfo, MouseEvent e) {
|
||||
popupActionManager.popupMenu(componentInfo, e);
|
||||
}
|
||||
|
||||
Action getDockingKeyAction(KeyStroke keyStroke) {
|
||||
return keyBindingsManager.getDockingKeyAction(keyStroke);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -544,21 +544,6 @@ public abstract class ComponentProvider implements HelpDescriptor, ActionContext
|
|||
}
|
||||
|
||||
if (isInTool()) {
|
||||
|
||||
/*
|
||||
TODO
|
||||
|
||||
4) Wire default 'close' action to keybinding
|
||||
5) Add global action for (show last provider)
|
||||
--Navigation menu?
|
||||
8) Update help locations
|
||||
|
||||
Questions:
|
||||
|
||||
C) How to wire universal close action (it is focus-dependent)
|
||||
|
||||
*/
|
||||
|
||||
dockingTool.getWindowManager().setIcon(this, icon);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -27,17 +27,16 @@ import docking.actions.KeyBindingUtils;
|
|||
* A class that can be used as an interface for using actions associated with keybindings. This
|
||||
* class is meant to only by used by internal Ghidra key event processing.
|
||||
*/
|
||||
public class DockingKeyBindingAction extends AbstractAction {
|
||||
public abstract class DockingKeyBindingAction extends AbstractAction {
|
||||
|
||||
private DockingActionIf docakbleAction;
|
||||
|
||||
protected KeyStroke keyStroke;
|
||||
protected final DockingWindowManager winMgr;
|
||||
protected final KeyStroke keyStroke;
|
||||
protected final DockingTool tool;
|
||||
|
||||
public DockingKeyBindingAction(DockingWindowManager winMgr, DockingActionIf action,
|
||||
KeyStroke keyStroke) {
|
||||
public DockingKeyBindingAction(DockingTool tool, DockingActionIf action, KeyStroke keyStroke) {
|
||||
super(KeyBindingUtils.parseKeyStroke(keyStroke));
|
||||
this.winMgr = winMgr;
|
||||
this.tool = tool;
|
||||
this.docakbleAction = action;
|
||||
this.keyStroke = keyStroke;
|
||||
}
|
||||
|
@ -52,18 +51,16 @@ public class DockingKeyBindingAction extends AbstractAction {
|
|||
return true;
|
||||
}
|
||||
|
||||
public boolean isReservedKeybindingPrecedence() {
|
||||
return getKeyBindingPrecedence() == KeyBindingPrecedence.ReservedActionsLevel;
|
||||
}
|
||||
public abstract KeyBindingPrecedence getKeyBindingPrecedence();
|
||||
|
||||
public KeyBindingPrecedence getKeyBindingPrecedence() {
|
||||
return KeyBindingPrecedence.ReservedActionsLevel;
|
||||
public boolean isReservedKeybindingPrecedence() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void actionPerformed(final ActionEvent e) {
|
||||
winMgr.setStatusText("");
|
||||
ComponentProvider provider = winMgr.getActiveComponentProvider();
|
||||
tool.setStatusInfo("");
|
||||
ComponentProvider provider = tool.getActiveComponentProvider();
|
||||
ActionContext context = getLocalContext(provider);
|
||||
context.setSource(e.getSource());
|
||||
docakbleAction.actionPerformed(context);
|
||||
|
|
|
@ -21,6 +21,7 @@ import java.util.Set;
|
|||
import javax.swing.ImageIcon;
|
||||
|
||||
import docking.action.DockingActionIf;
|
||||
import docking.actions.DockingToolActions;
|
||||
import ghidra.framework.options.ToolOptions;
|
||||
|
||||
/**
|
||||
|
@ -151,6 +152,12 @@ public interface DockingTool {
|
|||
*/
|
||||
public Set<DockingActionIf> getDockingActionsByOwnerName(String owner);
|
||||
|
||||
/**
|
||||
* Returns the active component provider, that which has focus
|
||||
* @return the active provider
|
||||
*/
|
||||
public ComponentProvider getActiveComponentProvider();
|
||||
|
||||
/**
|
||||
* Shows or hides the component provider in the tool
|
||||
* @param componentProvider the provider to either show or hide.
|
||||
|
@ -209,6 +216,15 @@ public interface DockingTool {
|
|||
*/
|
||||
public void contextChanged(ComponentProvider provider);
|
||||
|
||||
/**
|
||||
* Returns this tool's notion of the current action context, which is based upon the active
|
||||
* {@link ComponentProvider}. If there is not active provider, then a generic context will
|
||||
* be returned.
|
||||
*
|
||||
* @return the context
|
||||
*/
|
||||
public ActionContext getGlobalContext();
|
||||
|
||||
/**
|
||||
* Adds the given context listener to this tool
|
||||
* @param listener the listener to add
|
||||
|
@ -246,4 +262,15 @@ public interface DockingTool {
|
|||
* @return true if the tool's configuration has changed
|
||||
*/
|
||||
public boolean hasConfigChanged();
|
||||
|
||||
/**
|
||||
* Returns the class that manages actions for the tool.
|
||||
*
|
||||
* <p>Most clients will not need to use this methods. Instead, actions should be added to
|
||||
* the tool via {@link #addAction(DockingActionIf)} and
|
||||
* {@link #addLocalAction(ComponentProvider, DockingActionIf)}.
|
||||
*
|
||||
* @return the action manager
|
||||
*/
|
||||
public DockingToolActions getToolActions();
|
||||
}
|
||||
|
|
|
@ -29,7 +29,8 @@ import javax.swing.*;
|
|||
import org.jdom.Element;
|
||||
|
||||
import docking.action.DockingActionIf;
|
||||
import docking.action.KeyBindingsManager;
|
||||
import docking.actions.DockingToolActions;
|
||||
import docking.actions.ToolActions;
|
||||
import docking.help.HelpService;
|
||||
import generic.util.WindowUtilities;
|
||||
import ghidra.framework.OperatingSystem;
|
||||
|
@ -73,6 +74,7 @@ public class DockingWindowManager implements PropertyChangeListener, Placeholder
|
|||
|
||||
private static List<DockingWindowManager> instanceList = new ArrayList<>();
|
||||
|
||||
private DockingTool tool;
|
||||
private RootNode root;
|
||||
|
||||
private PlaceholderManager placeholderManager;
|
||||
|
@ -105,18 +107,18 @@ public class DockingWindowManager implements PropertyChangeListener, Placeholder
|
|||
|
||||
/**
|
||||
* Constructs a new DockingWindowManager
|
||||
* @param toolName the name of the tool.
|
||||
* @param tool the tool
|
||||
* @param images the images to use for windows in this window manager
|
||||
* @param docListener the listener to be notified when the user closes the manager.
|
||||
* @param docListener the listener to be notified when the user closes the manager
|
||||
*/
|
||||
public DockingWindowManager(String toolName, List<Image> images, DockWinListener docListener) {
|
||||
this(toolName, images, docListener, false, true, true, null);
|
||||
public DockingWindowManager(DockingTool tool, List<Image> images, DockWinListener docListener) {
|
||||
this(tool, images, docListener, false, true, true, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a new DockingWindowManager
|
||||
*
|
||||
* @param toolName the name of the tool
|
||||
* @param tool the tool
|
||||
* @param images the list of icons to set on the window
|
||||
* @param docListener the listener to be notified when the user closes the manager
|
||||
* @param modal if true then the root window will be a modal dialog instead of a frame
|
||||
|
@ -125,11 +127,12 @@ public class DockingWindowManager implements PropertyChangeListener, Placeholder
|
|||
* @param hasStatusBar if true a status bar will be created for the main window
|
||||
* @param factory the drop target factory
|
||||
*/
|
||||
public DockingWindowManager(String toolName, List<Image> images, DockWinListener docListener,
|
||||
public DockingWindowManager(DockingTool tool, List<Image> images, DockWinListener docListener,
|
||||
boolean modal, boolean isDocking, boolean hasStatusBar, DropTargetFactory factory) {
|
||||
|
||||
KeyBindingOverrideKeyEventDispatcher.install();
|
||||
|
||||
this.tool = tool;
|
||||
this.docListener = docListener;
|
||||
this.isDocking = isDocking;
|
||||
this.hasStatusBar = hasStatusBar;
|
||||
|
@ -137,7 +140,7 @@ public class DockingWindowManager implements PropertyChangeListener, Placeholder
|
|||
images = new ArrayList<>();
|
||||
}
|
||||
|
||||
root = new RootNode(this, toolName, images, modal, factory);
|
||||
root = new RootNode(this, tool.getName(), images, modal, factory);
|
||||
|
||||
KeyboardFocusManager km = KeyboardFocusManager.getCurrentKeyboardFocusManager();
|
||||
km.addPropertyChangeListener("permanentFocusOwner", this);
|
||||
|
@ -145,6 +148,7 @@ public class DockingWindowManager implements PropertyChangeListener, Placeholder
|
|||
addInstance(this);
|
||||
|
||||
placeholderManager = new PlaceholderManager(this);
|
||||
actionToGuiMapper = new ActionToGuiMapper(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -152,15 +156,6 @@ public class DockingWindowManager implements PropertyChangeListener, Placeholder
|
|||
return "DockingWindowManager: " + root.getTitle();
|
||||
}
|
||||
|
||||
/**
|
||||
* A static initializer allowing additional diagnostic actions
|
||||
* to be enabled added to all frame and dialog windows.
|
||||
* @param enable
|
||||
*/
|
||||
public static void enableDiagnosticActions(boolean enable) {
|
||||
ActionToGuiMapper.enableDiagnosticActions(enable);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the help service for the all docking window managers.
|
||||
* @param helpSvc the help service to use.
|
||||
|
@ -310,17 +305,6 @@ public class DockingWindowManager implements PropertyChangeListener, Placeholder
|
|||
root.setIcon(icon);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns any action that is bound to the given keystroke for the tool associated with this
|
||||
* DockingWindowManager instance.
|
||||
* @param keyStroke The keystroke to check for key bindings.
|
||||
* @return The action that is bound to the keystroke, or null of there is no binding for the
|
||||
* given keystroke.
|
||||
*/
|
||||
Action getActionForKeyStroke(KeyStroke keyStroke) {
|
||||
return actionToGuiMapper.getDockingKeyAction(keyStroke);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if this manager contains the given provider.
|
||||
*
|
||||
|
@ -362,6 +346,13 @@ public class DockingWindowManager implements PropertyChangeListener, Placeholder
|
|||
defaultProvider = provider;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns this tool's notion of the current action context, which is based upon the active
|
||||
* {@link ComponentProvider}. If there is not active provider, then a generic context will
|
||||
* be returned.
|
||||
*
|
||||
* @return the context
|
||||
*/
|
||||
public ActionContext getGlobalContext() {
|
||||
if (defaultProvider != null) {
|
||||
ActionContext actionContext = defaultProvider.getActionContext(null);
|
||||
|
@ -640,24 +631,10 @@ public class DockingWindowManager implements PropertyChangeListener, Placeholder
|
|||
placeholderManager.removeComponent(provider);
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes all components and actions associated with the given owner.
|
||||
* @param owner the name of the owner whose associated component and actions should be removed.
|
||||
*/
|
||||
public void removeAll(String owner) {
|
||||
actionToGuiMapper.removeAll(owner);
|
||||
placeholderManager.removeAll(owner);
|
||||
scheduleUpdate();
|
||||
}
|
||||
|
||||
//==================================================================================================
|
||||
// Package-level Action Methods
|
||||
//==================================================================================================
|
||||
|
||||
void setKeyBindingsManager(KeyBindingsManager keyBindingsManager) {
|
||||
actionToGuiMapper = new ActionToGuiMapper(this, keyBindingsManager);
|
||||
}
|
||||
|
||||
Iterator<DockingActionIf> getComponentActions(ComponentProvider provider) {
|
||||
ComponentPlaceholder placeholder = getActivePlaceholder(provider);
|
||||
if (placeholder != null) {
|
||||
|
@ -671,7 +648,6 @@ public class DockingWindowManager implements PropertyChangeListener, Placeholder
|
|||
void removeProviderAction(ComponentProvider provider, DockingActionIf action) {
|
||||
ComponentPlaceholder placeholder = getActivePlaceholder(provider);
|
||||
if (placeholder != null) {
|
||||
actionToGuiMapper.removeLocalAction(action);
|
||||
placeholder.removeAction(action);
|
||||
}
|
||||
}
|
||||
|
@ -682,7 +658,6 @@ public class DockingWindowManager implements PropertyChangeListener, Placeholder
|
|||
throw new IllegalArgumentException("Unknown component provider: " + provider);
|
||||
}
|
||||
placeholder.addAction(action);
|
||||
actionToGuiMapper.addLocalAction(action, provider);
|
||||
}
|
||||
|
||||
void addToolAction(DockingActionIf action) {
|
||||
|
@ -695,9 +670,31 @@ public class DockingWindowManager implements PropertyChangeListener, Placeholder
|
|||
scheduleUpdate();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns any action that is bound to the given keystroke for the tool associated with this
|
||||
* DockingWindowManager instance.
|
||||
* @param keyStroke The keystroke to check for key bindings.
|
||||
* @return The action that is bound to the keystroke, or null of there is no binding for the
|
||||
* given keystroke.
|
||||
*/
|
||||
Action getActionForKeyStroke(KeyStroke keyStroke) {
|
||||
DockingToolActions toolActions = tool.getToolActions();
|
||||
if (toolActions instanceof ToolActions) {
|
||||
// Using a cast here; it didn't make sense to include this 'getAction' on the
|
||||
// DockingToolActions
|
||||
return ((ToolActions) toolActions).getAction(keyStroke);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
//==================================================================================================
|
||||
// End Package-level Methods
|
||||
//==================================================================================================
|
||||
//==================================================================================================
|
||||
|
||||
public void ownerRemoved(String owner) {
|
||||
placeholderManager.removeAll(owner);
|
||||
scheduleUpdate();
|
||||
}
|
||||
|
||||
/**
|
||||
* Hides or shows the component associated with the given provider.
|
||||
|
@ -1002,7 +999,7 @@ public class DockingWindowManager implements PropertyChangeListener, Placeholder
|
|||
Iterator<DockingActionIf> iter = placeholder.getActions();
|
||||
while (iter.hasNext()) {
|
||||
DockingActionIf action = iter.next();
|
||||
actionToGuiMapper.removeLocalAction(action);
|
||||
placeholder.removeAction(action);
|
||||
}
|
||||
|
||||
ComponentNode node = placeholder.getNode();
|
||||
|
@ -1093,7 +1090,7 @@ public class DockingWindowManager implements PropertyChangeListener, Placeholder
|
|||
return;
|
||||
}
|
||||
|
||||
actionToGuiMapper.removeAll(DOCKING_WINDOWS_OWNER);
|
||||
tool.getToolActions().removeActions(DOCKING_WINDOWS_OWNER);
|
||||
|
||||
Map<String, List<ComponentPlaceholder>> permanentMap = new HashMap<>();
|
||||
Map<String, List<ComponentPlaceholder>> transientMap = new HashMap<>();
|
||||
|
@ -1160,9 +1157,11 @@ public class DockingWindowManager implements PropertyChangeListener, Placeholder
|
|||
actionList.add(new ShowAllComponentsAction(this, placeholders, subMenuName));
|
||||
}
|
||||
}
|
||||
|
||||
DockingToolActions toolActions = tool.getToolActions();
|
||||
Collections.sort(actionList);
|
||||
for (ShowComponentAction action : actionList) {
|
||||
actionToGuiMapper.addToolAction(action);
|
||||
toolActions.addGlobalAction(action);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1198,9 +1197,10 @@ public class DockingWindowManager implements PropertyChangeListener, Placeholder
|
|||
}
|
||||
}
|
||||
|
||||
DockingToolActions toolActions = tool.getToolActions();
|
||||
Collections.sort(actions);
|
||||
for (ShowWindowAction action : actions) {
|
||||
actionToGuiMapper.addToolAction(action);
|
||||
toolActions.addGlobalAction(action);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1208,6 +1208,9 @@ public class DockingWindowManager implements PropertyChangeListener, Placeholder
|
|||
* Notifies the window manager that an update is needed
|
||||
*/
|
||||
void scheduleUpdate() {
|
||||
if (rebuildUpdater.isBusy()) {
|
||||
return;
|
||||
}
|
||||
rebuildUpdater.updateLater();
|
||||
}
|
||||
|
||||
|
@ -1225,7 +1228,6 @@ public class DockingWindowManager implements PropertyChangeListener, Placeholder
|
|||
}
|
||||
|
||||
root.update(); // do this before rebuilding the menu, as new windows may be opened
|
||||
|
||||
buildComponentMenu();
|
||||
SystemUtilities.runSwingLater(() -> updateFocus());
|
||||
}
|
||||
|
|
|
@ -36,7 +36,6 @@ class ShowComponentAction extends DockingAction implements Comparable<ShowCompon
|
|||
protected DockingWindowManager winMgr;
|
||||
private ComponentPlaceholder info;
|
||||
private String title;
|
||||
private boolean isTransient;
|
||||
|
||||
private static String truncateTitleAsNeeded(String title) {
|
||||
if (title.length() <= MAX_LENGTH) {
|
||||
|
@ -58,7 +57,6 @@ class ShowComponentAction extends DockingAction implements Comparable<ShowCompon
|
|||
this.info = placeholder;
|
||||
this.winMgr = winMgr;
|
||||
this.title = truncateTitleAsNeeded(placeholder.getTitle());
|
||||
this.isTransient = isTransient;
|
||||
String group = isTransient ? "Transient" : "Permanent";
|
||||
|
||||
Icon icon = placeholder.getIcon();
|
||||
|
@ -139,6 +137,10 @@ class ShowComponentAction extends DockingAction implements Comparable<ShowCompon
|
|||
|
||||
@Override
|
||||
public String getHelpInfo() {
|
||||
if (info == null) {
|
||||
return super.getHelpInfo();
|
||||
}
|
||||
|
||||
StringBuilder buffy = new StringBuilder(super.getHelpInfo());
|
||||
|
||||
ComponentProvider provider = info.getProvider();
|
||||
|
|
|
@ -17,7 +17,8 @@ package docking.action;
|
|||
|
||||
import java.beans.PropertyChangeEvent;
|
||||
import java.beans.PropertyChangeListener;
|
||||
import java.util.*;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.swing.Action;
|
||||
import javax.swing.KeyStroke;
|
||||
|
@ -30,11 +31,10 @@ public class KeyBindingsManager implements PropertyChangeListener {
|
|||
|
||||
protected Map<KeyStroke, DockingKeyBindingAction> dockingKeyMap;
|
||||
protected Map<DockingActionIf, ComponentProvider> actionToProviderMap;
|
||||
private DockingTool tool;
|
||||
|
||||
private DockingWindowManager winMgr;
|
||||
|
||||
public KeyBindingsManager(DockingWindowManager winMgr) {
|
||||
this.winMgr = winMgr;
|
||||
public KeyBindingsManager(DockingTool tool) {
|
||||
this.tool = tool;
|
||||
dockingKeyMap = new HashMap<>();
|
||||
actionToProviderMap = new HashMap<>();
|
||||
}
|
||||
|
@ -76,8 +76,7 @@ public class KeyBindingsManager implements PropertyChangeListener {
|
|||
|
||||
DockingKeyBindingAction existingAction = dockingKeyMap.get(keyStroke);
|
||||
if (existingAction == null) {
|
||||
dockingKeyMap.put(keyStroke,
|
||||
new MultipleKeyAction(winMgr, provider, action, keyStroke));
|
||||
dockingKeyMap.put(keyStroke, new MultipleKeyAction(tool, provider, action, keyStroke));
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -98,7 +97,7 @@ public class KeyBindingsManager implements PropertyChangeListener {
|
|||
|
||||
KeyBindingData binding = KeyBindingData.createReservedKeyBindingData(keyStroke);
|
||||
action.setKeyBindingData(binding);
|
||||
dockingKeyMap.put(keyStroke, new ReservedKeyBindingAction(winMgr, action, keyStroke));
|
||||
dockingKeyMap.put(keyStroke, new ReservedKeyBindingAction(tool, action, keyStroke));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -151,18 +150,12 @@ public class KeyBindingsManager implements PropertyChangeListener {
|
|||
}
|
||||
}
|
||||
|
||||
public List<DockingActionIf> getLocalActions() {
|
||||
return new ArrayList<>(actionToProviderMap.keySet());
|
||||
}
|
||||
|
||||
public Action getDockingKeyAction(KeyStroke keyStroke) {
|
||||
return dockingKeyMap.get(keyStroke);
|
||||
}
|
||||
|
||||
public void dispose() {
|
||||
winMgr = null;
|
||||
dockingKeyMap.clear();
|
||||
actionToProviderMap.clear();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -32,35 +32,17 @@ public class MultipleKeyAction extends DockingKeyBindingAction {
|
|||
|
||||
private ActionDialog dialog;
|
||||
|
||||
class ActionData {
|
||||
DockingActionIf action;
|
||||
ComponentProvider provider;
|
||||
|
||||
ActionData(DockingActionIf action, ComponentProvider provider) {
|
||||
this.action = action;
|
||||
this.provider = provider;
|
||||
}
|
||||
|
||||
boolean isGlobalAction() {
|
||||
return provider == null;
|
||||
}
|
||||
|
||||
boolean isMyProvider(ComponentProvider otherProvider) {
|
||||
return provider == otherProvider;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates new MultipleKeyAction
|
||||
*
|
||||
* @param winMgr window manager used to determine context.
|
||||
* @param tool used to determine context
|
||||
* @param provider the provider, if any, associated with the action
|
||||
* @param action action that will be added to the list of actions bound to a keystroke
|
||||
* @param keyStroke the keystroke, if any, associated with the action
|
||||
*/
|
||||
public MultipleKeyAction(DockingWindowManager winMgr, ComponentProvider provider,
|
||||
DockingActionIf action, KeyStroke keyStroke) {
|
||||
super(winMgr, action, keyStroke);
|
||||
public MultipleKeyAction(DockingTool tool, ComponentProvider provider, DockingActionIf action,
|
||||
KeyStroke keyStroke) {
|
||||
super(tool, action, keyStroke);
|
||||
addAction(provider, action);
|
||||
}
|
||||
|
||||
|
@ -134,11 +116,11 @@ public class MultipleKeyAction extends DockingKeyBindingAction {
|
|||
@Override
|
||||
public void actionPerformed(final ActionEvent event) {
|
||||
// Build list of actions which are valid in current context
|
||||
ComponentProvider localProvider = winMgr.getActiveComponentProvider();
|
||||
ComponentProvider localProvider = tool.getActiveComponentProvider();
|
||||
ActionContext localContext = getLocalContext(localProvider);
|
||||
localContext.setSource(event.getSource());
|
||||
|
||||
ActionContext globalContext = winMgr.getGlobalContext();
|
||||
ActionContext globalContext = tool.getGlobalContext();
|
||||
List<ExecutableKeyActionAdapter> list = getValidContextActions(localContext, globalContext);
|
||||
|
||||
// If menu active, disable all key bindings
|
||||
|
@ -163,12 +145,12 @@ public class MultipleKeyAction extends DockingKeyBindingAction {
|
|||
}
|
||||
else if (list.size() == 1) {
|
||||
final ExecutableKeyActionAdapter actionProxy = list.get(0);
|
||||
winMgr.setStatusText("");
|
||||
tool.setStatusInfo("");
|
||||
actionProxy.execute();
|
||||
}
|
||||
else {
|
||||
String name = (String) getValue(Action.NAME);
|
||||
winMgr.setStatusText("Action (" + name + ") not valid in this context!", true);
|
||||
tool.setStatusInfo("Action (" + name + ") not valid in this context!", true);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -230,9 +212,9 @@ public class MultipleKeyAction extends DockingKeyBindingAction {
|
|||
|
||||
@Override
|
||||
public KeyBindingPrecedence getKeyBindingPrecedence() {
|
||||
ComponentProvider localProvider = winMgr.getActiveComponentProvider();
|
||||
ComponentProvider localProvider = tool.getActiveComponentProvider();
|
||||
ActionContext localContext = getLocalContext(localProvider);
|
||||
ActionContext globalContext = winMgr.getGlobalContext();
|
||||
ActionContext globalContext = tool.getGlobalContext();
|
||||
List<ExecutableKeyActionAdapter> validActions =
|
||||
getValidContextActions(localContext, globalContext);
|
||||
|
||||
|
@ -274,4 +256,22 @@ public class MultipleKeyAction extends DockingKeyBindingAction {
|
|||
|
||||
return buildy.toString();
|
||||
}
|
||||
|
||||
private class ActionData {
|
||||
DockingActionIf action;
|
||||
ComponentProvider provider;
|
||||
|
||||
ActionData(DockingActionIf action, ComponentProvider provider) {
|
||||
this.action = action;
|
||||
this.provider = provider;
|
||||
}
|
||||
|
||||
boolean isGlobalAction() {
|
||||
return provider == null;
|
||||
}
|
||||
|
||||
boolean isMyProvider(ComponentProvider otherProvider) {
|
||||
return provider == otherProvider;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -17,18 +17,21 @@ package docking.action;
|
|||
|
||||
import javax.swing.KeyStroke;
|
||||
|
||||
import docking.DockingKeyBindingAction;
|
||||
import docking.DockingWindowManager;
|
||||
import docking.*;
|
||||
|
||||
class ReservedKeyBindingAction extends DockingKeyBindingAction {
|
||||
|
||||
ReservedKeyBindingAction(DockingWindowManager winMgr, DockingActionIf action,
|
||||
KeyStroke keyStroke) {
|
||||
super(winMgr, action, keyStroke);
|
||||
ReservedKeyBindingAction(DockingTool tool, DockingActionIf action, KeyStroke keyStroke) {
|
||||
super(tool, action, keyStroke);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isReservedKeybindingPrecedence() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public KeyBindingPrecedence getKeyBindingPrecedence() {
|
||||
return KeyBindingPrecedence.ReservedActionsLevel;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,86 @@
|
|||
/* ###
|
||||
* IP: GHIDRA
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package docking.actions;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
import docking.ComponentProvider;
|
||||
import docking.action.DockingActionIf;
|
||||
|
||||
/**
|
||||
* Represents the collection of actions registered with the tool, along with method for adding
|
||||
* and removing actions.
|
||||
*/
|
||||
public interface DockingToolActions {
|
||||
|
||||
/**
|
||||
* Adds the given action that enabled when the given provider is active
|
||||
*
|
||||
* @param provider the provider
|
||||
* @param action the action
|
||||
*/
|
||||
public void addLocalAction(ComponentProvider provider, DockingActionIf action);
|
||||
|
||||
/**
|
||||
* Removes the given provider's local action
|
||||
*
|
||||
* @param provider the provider
|
||||
* @param action the action
|
||||
*/
|
||||
public void removeLocalAction(ComponentProvider provider, DockingActionIf action);
|
||||
|
||||
/**
|
||||
* Adds the given action that is enabled, regardless of the active provider
|
||||
*
|
||||
* @param action the action
|
||||
*/
|
||||
public void addGlobalAction(DockingActionIf action);
|
||||
|
||||
/**
|
||||
* Removes the given global action
|
||||
* @param action the action
|
||||
*/
|
||||
public void removeGlobalAction(DockingActionIf action);
|
||||
|
||||
/**
|
||||
* Removes all global actions for the given owner
|
||||
*
|
||||
* @param owner the owner
|
||||
*/
|
||||
public void removeActions(String owner);
|
||||
|
||||
/**
|
||||
* Removes all local actions for the given provider
|
||||
*
|
||||
* @param provider the provider
|
||||
*/
|
||||
public void removeActions(ComponentProvider provider);
|
||||
|
||||
/**
|
||||
* Returns all actions with the given owner
|
||||
*
|
||||
* @param owner the owner
|
||||
* @return the actions
|
||||
*/
|
||||
public Set<DockingActionIf> getActions(String owner);
|
||||
|
||||
/**
|
||||
* Returns all actions known to the tool
|
||||
* @return the actions
|
||||
*/
|
||||
public Set<DockingActionIf> getAllActions();
|
||||
|
||||
}
|
|
@ -25,6 +25,7 @@ import java.util.*;
|
|||
|
||||
import javax.swing.*;
|
||||
|
||||
import org.apache.commons.collections4.map.LazyMap;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.jdom.*;
|
||||
|
@ -344,15 +345,21 @@ public class KeyBindingUtils {
|
|||
}
|
||||
|
||||
/**
|
||||
* A utility method to get all key binding actions. This method will remove duplicate
|
||||
* actions and will only return actions that support {@link KeyBindingType key bindings}.
|
||||
* A utility method to get all key binding actions. This method will
|
||||
* only return actions that support {@link KeyBindingType key bindings}.
|
||||
*
|
||||
* <p>The mapping returned provides a list of items because it is possible for there to
|
||||
* exists multiple actions with the same name and owner. (This can happen when multiple copies
|
||||
* of a component provider are shown, each with their own set of actions that share the
|
||||
* same name.)
|
||||
*
|
||||
* @param tool the tool containing the actions
|
||||
* @return the actions mapped by their full name (e.g., 'Name (OwnerName)')
|
||||
*/
|
||||
public static Map<String, DockingActionIf> getAllActionsByFullName(DockingTool tool) {
|
||||
public static Map<String, List<DockingActionIf>> getAllActionsByFullName(DockingTool tool) {
|
||||
|
||||
Map<String, DockingActionIf> deduper = new HashMap<>();
|
||||
Map<String, List<DockingActionIf>> result =
|
||||
LazyMap.lazyMap(new HashMap<>(), s -> new LinkedList<>());
|
||||
Set<DockingActionIf> actions = tool.getAllActions();
|
||||
for (DockingActionIf action : actions) {
|
||||
if (isIgnored(action)) {
|
||||
|
@ -362,10 +369,10 @@ public class KeyBindingUtils {
|
|||
continue;
|
||||
}
|
||||
|
||||
deduper.put(action.getFullName(), action);
|
||||
result.get(action.getFullName()).add(action);
|
||||
}
|
||||
|
||||
return deduper;
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -720,7 +727,7 @@ public class KeyBindingUtils {
|
|||
private static boolean isIgnored(DockingActionIf action) {
|
||||
// a shared keybinding implies that this action should not be in
|
||||
// the UI, as there will be a single proxy in place of all actions sharing that binding
|
||||
return action.getKeyBindingType().isShared();
|
||||
return !action.getKeyBindingType().isManaged();
|
||||
}
|
||||
|
||||
private static KeyStroke getKeyStroke(KeyBindingData data) {
|
||||
|
|
|
@ -33,13 +33,14 @@ import docking.action.*;
|
|||
import docking.tool.util.DockingToolConstants;
|
||||
import ghidra.framework.options.*;
|
||||
import ghidra.util.ReservedKeyBindings;
|
||||
import ghidra.util.SystemUtilities;
|
||||
import ghidra.util.exception.AssertException;
|
||||
import util.CollectionUtils;
|
||||
|
||||
/**
|
||||
* An class to manage actions registered with the tool
|
||||
*/
|
||||
public class ToolActions implements PropertyChangeListener {
|
||||
public class ToolActions implements DockingToolActions, PropertyChangeListener {
|
||||
|
||||
private ActionToGuiHelper actionGuiHelper;
|
||||
|
||||
|
@ -62,25 +63,38 @@ public class ToolActions implements PropertyChangeListener {
|
|||
* Construct an ActionManager
|
||||
*
|
||||
* @param tool tool using this ActionManager
|
||||
* @param windowManager manager of the "Docking" arrangement of a set of components
|
||||
* and actions in the tool
|
||||
* @param actionToGuiHelper the class that takes actions and maps them to GUI widgets
|
||||
*/
|
||||
public ToolActions(DockingTool tool, DockingWindowManager windowManager) {
|
||||
public ToolActions(DockingTool tool, ActionToGuiHelper actionToGuiHelper) {
|
||||
this.dockingTool = tool;
|
||||
this.actionGuiHelper = new ActionToGuiHelper(windowManager);
|
||||
this.keyBindingsManager = new KeyBindingsManager(windowManager);
|
||||
this.actionGuiHelper = actionToGuiHelper;
|
||||
this.keyBindingsManager = new KeyBindingsManager(tool);
|
||||
this.keyBindingOptions = tool.getOptions(DockingToolConstants.KEY_BINDINGS);
|
||||
|
||||
createReservedKeyBindings();
|
||||
}
|
||||
|
||||
private void createReservedKeyBindings() {
|
||||
KeyBindingAction keyBindingAction = new KeyBindingAction(this);
|
||||
keyBindingsManager.addReservedAction(keyBindingAction,
|
||||
ReservedKeyBindings.UPDATE_KEY_BINDINGS_KEY);
|
||||
|
||||
actionGuiHelper.setKeyBindingsManager(keyBindingsManager);
|
||||
keyBindingsManager.addReservedAction(new HelpAction(false, ReservedKeyBindings.HELP_KEY1));
|
||||
keyBindingsManager.addReservedAction(new HelpAction(false, ReservedKeyBindings.HELP_KEY2));
|
||||
keyBindingsManager.addReservedAction(
|
||||
new HelpAction(true, ReservedKeyBindings.HELP_INFO_KEY));
|
||||
|
||||
// these are diagnostic
|
||||
if (SystemUtilities.isInDevelopmentMode()) {
|
||||
keyBindingsManager.addReservedAction(new ShowFocusInfoAction());
|
||||
keyBindingsManager.addReservedAction(new ShowFocusCycleAction());
|
||||
}
|
||||
}
|
||||
|
||||
public void dispose() {
|
||||
actionsByNameByOwner.clear();
|
||||
sharedActionMap.clear();
|
||||
keyBindingsManager.dispose();
|
||||
}
|
||||
|
||||
private void addActionToMap(DockingActionIf action) {
|
||||
|
@ -95,12 +109,14 @@ public class ToolActions implements PropertyChangeListener {
|
|||
* @param provider provider associated with the action
|
||||
* @param action local action to the provider
|
||||
*/
|
||||
@Override
|
||||
public synchronized void addLocalAction(ComponentProvider provider, DockingActionIf action) {
|
||||
checkForAlreadyAddedAction(provider, action);
|
||||
|
||||
action.addPropertyChangeListener(this);
|
||||
addActionToMap(action);
|
||||
setKeyBindingOption(action);
|
||||
keyBindingsManager.addAction(action, provider);
|
||||
actionGuiHelper.addLocalAction(provider, action);
|
||||
}
|
||||
|
||||
|
@ -108,10 +124,14 @@ public class ToolActions implements PropertyChangeListener {
|
|||
* Adds the action to the tool.
|
||||
* @param action the action to be added.
|
||||
*/
|
||||
public synchronized void addToolAction(DockingActionIf action) {
|
||||
@Override
|
||||
public synchronized void addGlobalAction(DockingActionIf action) {
|
||||
checkForAlreadyAddedAction(null, action);
|
||||
|
||||
action.addPropertyChangeListener(this);
|
||||
addActionToMap(action);
|
||||
setKeyBindingOption(action);
|
||||
keyBindingsManager.addAction(action, null);
|
||||
actionGuiHelper.addToolAction(action);
|
||||
}
|
||||
|
||||
|
@ -158,17 +178,15 @@ public class ToolActions implements PropertyChangeListener {
|
|||
* Removes the given action from the tool
|
||||
* @param action the action to be removed.
|
||||
*/
|
||||
public synchronized void removeToolAction(DockingActionIf action) {
|
||||
@Override
|
||||
public synchronized void removeGlobalAction(DockingActionIf action) {
|
||||
action.removePropertyChangeListener(this);
|
||||
removeAction(action);
|
||||
actionGuiHelper.removeToolAction(action);
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove all actions that have the given owner.
|
||||
* @param owner owner of the actions to remove
|
||||
*/
|
||||
public synchronized void removeToolActions(String owner) {
|
||||
@Override
|
||||
public synchronized void removeActions(String owner) {
|
||||
|
||||
// remove from the outer map first, to prevent concurrent modification exceptions
|
||||
Map<String, Set<DockingActionIf>> toCleanup = actionsByNameByOwner.remove(owner);
|
||||
|
@ -180,15 +198,17 @@ public class ToolActions implements PropertyChangeListener {
|
|||
toCleanup.values()
|
||||
.stream()
|
||||
.flatMap(set -> set.stream())
|
||||
.forEach(action -> removeToolAction(action))
|
||||
.forEach(action -> removeGlobalAction(action))
|
||||
;
|
||||
//@formatter:on
|
||||
}
|
||||
|
||||
private void checkForAlreadyAddedAction(ComponentProvider provider, DockingActionIf action) {
|
||||
if (getActionStorage(action).contains(action)) {
|
||||
throw new AssertException("Cannot add the same action more than once. Provider " +
|
||||
provider.getName() + " - action: " + action.getFullName());
|
||||
String providerString =
|
||||
provider == null ? "Action: " : "Provider " + provider.getName() + " - action: ";
|
||||
throw new AssertException("Cannot add the same action more than once. " +
|
||||
providerString + action.getFullName());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -198,6 +218,7 @@ public class ToolActions implements PropertyChangeListener {
|
|||
* @return array of actions; zero length array is returned if no
|
||||
* action exists with the given name
|
||||
*/
|
||||
@Override
|
||||
public synchronized Set<DockingActionIf> getActions(String owner) {
|
||||
|
||||
Set<DockingActionIf> result = new HashSet<>();
|
||||
|
@ -215,8 +236,10 @@ public class ToolActions implements PropertyChangeListener {
|
|||
|
||||
/**
|
||||
* Get a set of all actions in the tool
|
||||
* @return the actions
|
||||
*
|
||||
* @return a new set of the existing actions
|
||||
*/
|
||||
@Override
|
||||
public synchronized Set<DockingActionIf> getAllActions() {
|
||||
|
||||
Set<DockingActionIf> result = new HashSet<>();
|
||||
|
@ -278,23 +301,24 @@ public class ToolActions implements PropertyChangeListener {
|
|||
* @param provider provider associated with the action
|
||||
* @param action local action to the provider
|
||||
*/
|
||||
public synchronized void removeProviderAction(ComponentProvider provider,
|
||||
DockingActionIf action) {
|
||||
@Override
|
||||
public synchronized void removeLocalAction(ComponentProvider provider, DockingActionIf action) {
|
||||
action.removePropertyChangeListener(this);
|
||||
removeAction(action);
|
||||
keyBindingsManager.removeAction(action);
|
||||
actionGuiHelper.removeProviderAction(provider, action);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the actions for the given provider and remove them from the action map
|
||||
* @param provider provider whose actions are to be removed
|
||||
*/
|
||||
public synchronized void removeComponentActions(ComponentProvider provider) {
|
||||
@Override
|
||||
public synchronized void removeActions(ComponentProvider provider) {
|
||||
Iterator<DockingActionIf> it = actionGuiHelper.getComponentActions(provider);
|
||||
|
||||
// copy the data to avoid concurrent modification exceptions
|
||||
Set<DockingActionIf> set = CollectionUtils.asSet(it);
|
||||
for (DockingActionIf action : set) {
|
||||
removeProviderAction(provider, action);
|
||||
removeLocalAction(provider, action);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private void removeAction(DockingActionIf action) {
|
||||
|
@ -346,12 +370,12 @@ public class ToolActions implements PropertyChangeListener {
|
|||
}
|
||||
}
|
||||
|
||||
DockingActionIf getSharedStubKeyBindingAction(String name) {
|
||||
return sharedActionMap.get(name);
|
||||
public Action getAction(KeyStroke ks) {
|
||||
return keyBindingsManager.getDockingKeyAction(ks);
|
||||
}
|
||||
|
||||
Action getAction(KeyStroke ks) {
|
||||
return keyBindingsManager.getDockingKeyAction(ks);
|
||||
DockingActionIf getSharedStubKeyBindingAction(String name) {
|
||||
return sharedActionMap.get(name);
|
||||
}
|
||||
|
||||
// triggered by a user-initiated action
|
||||
|
|
|
@ -35,9 +35,11 @@ import docking.tool.util.DockingToolConstants;
|
|||
import ghidra.framework.options.ToolOptions;
|
||||
import ghidra.util.Msg;
|
||||
import ghidra.util.SpyErrorLogger;
|
||||
import ghidra.util.exception.AssertException;
|
||||
|
||||
public class SharedKeyBindingDockingActionTest extends AbstractDockingTest {
|
||||
|
||||
private static final String NON_SHARED_NAME = "Non-Shared Action Name";
|
||||
private static final String SHARED_NAME = "Shared Action Name";
|
||||
private static final String SHARED_OWNER = SharedStubKeyBindingAction.SHARED_OWNER;
|
||||
|
||||
|
@ -167,7 +169,14 @@ public class SharedKeyBindingDockingActionTest extends AbstractDockingTest {
|
|||
TestAction action1 = new TestAction(OWNER_1, DEFAULT_KS_1);
|
||||
|
||||
tool.addAction(action1);
|
||||
tool.addAction(action1);
|
||||
|
||||
try {
|
||||
tool.addAction(action1);
|
||||
fail("Did not get expected exception");
|
||||
}
|
||||
catch (AssertException e) {
|
||||
// expected
|
||||
}
|
||||
|
||||
assertOnlyOneVersionOfActionInTool(action1);
|
||||
|
||||
|
@ -294,7 +303,7 @@ public class SharedKeyBindingDockingActionTest extends AbstractDockingTest {
|
|||
}
|
||||
|
||||
@Test
|
||||
public void testNonSharedKeyBinding_SameActionAddedTwice() {
|
||||
public void testSharedKeyBinding_SameActionAddedTwice() {
|
||||
//
|
||||
// We support adding the same action twice. (This can happen when a transient component
|
||||
// provider is repeatedly shown, such as a search results provider.) Make sure we get
|
||||
|
@ -323,7 +332,7 @@ public class SharedKeyBindingDockingActionTest extends AbstractDockingTest {
|
|||
}
|
||||
|
||||
@Test
|
||||
public void testNonSharedKeyBinding_DifferentActionsWithSameFullName() {
|
||||
public void testSharedKeyBinding_DifferentActionsWithSameFullName() {
|
||||
//
|
||||
// We support adding the same action twice. (This can happen when a transient component
|
||||
// provider is repeatedly shown, such as a search results provider.) Make sure we get
|
||||
|
@ -351,6 +360,36 @@ public class SharedKeyBindingDockingActionTest extends AbstractDockingTest {
|
|||
assertActionNotInTool(action1Copy);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNonSharedKeyBinding_DifferentActionsWithSameFullName() {
|
||||
//
|
||||
// We support adding the same action twice. (This can happen when a transient component
|
||||
// provider is repeatedly shown, such as a search results provider.) Make sure we get
|
||||
// a warning if the same action is added twice, but with different key bindings.
|
||||
//
|
||||
// Note: in this context, two actions are considered to be the same if they share the
|
||||
// same name and owner.
|
||||
//
|
||||
|
||||
TestNonSharedAction action1 = new TestNonSharedAction(OWNER_1, DEFAULT_KS_1);
|
||||
TestNonSharedAction action1Copy =
|
||||
new TestNonSharedAction(OWNER_1, DEFAULT_KS_DIFFERENT_THAN_1);
|
||||
|
||||
tool.addAction(action1);
|
||||
tool.addAction(action1Copy);
|
||||
assertActionInTool(action1);
|
||||
assertActionInTool(action1Copy);
|
||||
|
||||
assertImproperDefaultBindingMessage();
|
||||
|
||||
tool.removeAction(action1);
|
||||
assertActionNotInTool(action1);
|
||||
assertActionInTool(action1Copy);
|
||||
|
||||
tool.removeAction(action1Copy);
|
||||
assertActionNotInTool(action1Copy);
|
||||
}
|
||||
|
||||
//==================================================================================================
|
||||
// Private Methods
|
||||
//==================================================================================================
|
||||
|
@ -361,7 +400,7 @@ public class SharedKeyBindingDockingActionTest extends AbstractDockingTest {
|
|||
assertNotNull("Shared action stub is not in the tool", action);
|
||||
}
|
||||
|
||||
private void assertOnlyOneVersionOfActionInTool(TestAction action) {
|
||||
private void assertOnlyOneVersionOfActionInTool(DockingActionIf action) {
|
||||
|
||||
// this method will fail if more than one action is registered
|
||||
DockingActionIf registeredAction = getAction(tool, action.getOwner(), action.getName());
|
||||
|
@ -369,7 +408,7 @@ public class SharedKeyBindingDockingActionTest extends AbstractDockingTest {
|
|||
registeredAction);
|
||||
}
|
||||
|
||||
private void assertActionInTool(TestAction action) {
|
||||
private void assertActionInTool(DockingActionIf action) {
|
||||
|
||||
Set<DockingActionIf> actions = getActionsByName(tool, action.getName());
|
||||
for (DockingActionIf toolAction : actions) {
|
||||
|
@ -381,7 +420,7 @@ public class SharedKeyBindingDockingActionTest extends AbstractDockingTest {
|
|||
fail("Action is not in the tool: " + action);
|
||||
}
|
||||
|
||||
private void assertActionNotInTool(TestAction action) {
|
||||
private void assertActionNotInTool(DockingActionIf action) {
|
||||
Set<DockingActionIf> actions = getActionsByName(tool, action.getName());
|
||||
for (DockingActionIf toolAction : actions) {
|
||||
assertNotSame(toolAction, action);
|
||||
|
@ -436,6 +475,19 @@ public class SharedKeyBindingDockingActionTest extends AbstractDockingTest {
|
|||
}
|
||||
}
|
||||
|
||||
private class TestNonSharedAction extends DockingAction {
|
||||
|
||||
public TestNonSharedAction(String owner, KeyStroke ks) {
|
||||
super(NON_SHARED_NAME, owner, KeyBindingType.INDIVIDUAL);
|
||||
setKeyBindingData(new KeyBindingData(ks));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void actionPerformed(ActionContext context) {
|
||||
fail("Action performed should not have been called");
|
||||
}
|
||||
}
|
||||
|
||||
private class DummyComponentProvider extends ComponentProvider {
|
||||
public DummyComponentProvider() {
|
||||
super(tool, "Dummy", "Dummy Owner");
|
||||
|
|
|
@ -35,9 +35,9 @@ public class FakeDockingTool extends AbstractDockingTool {
|
|||
|
||||
DockWinListener listener = new DummyListener();
|
||||
List<Image> windowIcons = ApplicationInformationDisplayFactory.getWindowIcons();
|
||||
winMgr = new DockingWindowManager("EMPTY", windowIcons, listener, false /*isModal*/,
|
||||
winMgr = new DockingWindowManager(this, windowIcons, listener, false /*isModal*/,
|
||||
true /*isDockable*/, true /*hasStatus*/, null /*DropTargetFactory*/);
|
||||
toolActions = new ToolActions(this, winMgr);
|
||||
toolActions = new ToolActions(this, new ActionToGuiHelper(winMgr));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -71,7 +71,5 @@ public class FakeDockingTool extends AbstractDockingTool {
|
|||
public List<DockingActionIf> getPopupActions(ActionContext context) {
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -150,16 +150,16 @@ public abstract class PluginTool extends AbstractDockingTool
|
|||
this.projectManager = projectManager;
|
||||
this.toolServices = toolServices;
|
||||
propertyChangeMgr = new PropertyChangeSupport(this);
|
||||
winMgr = createDockingWindowManager(isDockable, hasStatus, isModal);
|
||||
taskMgr = new ToolTaskManager(this);
|
||||
optionsMgr = new OptionsManager(this);
|
||||
winMgr = createDockingWindowManager(isDockable, hasStatus, isModal);
|
||||
toolActions = new ToolActions(this, new ActionToGuiHelper(winMgr));
|
||||
taskMgr = new ToolTaskManager(this);
|
||||
setToolOptionsHelpLocation();
|
||||
winMgr.addStatusItem(taskMgr.getMonitorComponent(), false, true);
|
||||
winMgr.removeStatusItem(taskMgr.getMonitorComponent());
|
||||
eventMgr = new EventManager(this);
|
||||
serviceMgr = new ServiceManager();
|
||||
installServices();
|
||||
toolActions = new ToolActions(this, winMgr);
|
||||
pluginMgr = new PluginManager(this, serviceMgr);
|
||||
dialogMgr = new DialogManager(this);
|
||||
initActions();
|
||||
|
@ -190,8 +190,8 @@ public abstract class PluginTool extends AbstractDockingTool
|
|||
boolean isModal) {
|
||||
|
||||
List<Image> windowIcons = ApplicationInformationDisplayFactory.getWindowIcons();
|
||||
DockingWindowManager newManager = new DockingWindowManager("EMPTY", windowIcons, this,
|
||||
isModal, isDockable, hasStatus, null);
|
||||
DockingWindowManager newManager =
|
||||
new DockingWindowManager(this, windowIcons, this, isModal, isDockable, hasStatus, null);
|
||||
return newManager;
|
||||
}
|
||||
|
||||
|
@ -1322,8 +1322,8 @@ public abstract class PluginTool extends AbstractDockingTool
|
|||
}
|
||||
|
||||
void removeAll(String owner) {
|
||||
toolActions.removeToolActions(owner);
|
||||
winMgr.removeAll(owner);
|
||||
toolActions.removeActions(owner);
|
||||
winMgr.ownerRemoved(owner);
|
||||
}
|
||||
|
||||
void registerEventProduced(Class<? extends PluginEvent> eventClass) {
|
||||
|
@ -1468,6 +1468,7 @@ public abstract class PluginTool extends AbstractDockingTool
|
|||
return winMgr.getActiveWindow();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ComponentProvider getActiveComponentProvider() {
|
||||
return winMgr.getActiveComponentProvider();
|
||||
}
|
||||
|
|
|
@ -67,7 +67,7 @@ public class KeyBindingsPanel extends JPanel {
|
|||
private ListSelectionModel selectionModel;
|
||||
private Options options;
|
||||
|
||||
private Map<String, DockingActionIf> actionsByFullName;
|
||||
private Map<String, List<DockingActionIf>> actionsByFullName;
|
||||
private Map<String, List<String>> actionNamesByKeyStroke;
|
||||
private Map<String, KeyStroke> keyStrokesByFullName;
|
||||
private Map<String, KeyStroke> originalValues; // to know what has been changed
|
||||
|
@ -114,11 +114,11 @@ public class KeyBindingsPanel extends JPanel {
|
|||
changesMade(false);
|
||||
}
|
||||
|
||||
private boolean updateOptions(String fullActionName, KeyStroke currentKeyStroke,
|
||||
private void updateOptions(String fullActionName, KeyStroke currentKeyStroke,
|
||||
KeyStroke newKeyStroke) {
|
||||
if ((currentKeyStroke != null && currentKeyStroke.equals(newKeyStroke)) ||
|
||||
(currentKeyStroke == null && newKeyStroke == null)) {
|
||||
return false;
|
||||
|
||||
if (Objects.equals(currentKeyStroke, newKeyStroke)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (newKeyStroke != null) {
|
||||
|
@ -130,19 +130,12 @@ public class KeyBindingsPanel extends JPanel {
|
|||
originalValues.put(fullActionName, newKeyStroke);
|
||||
keyStrokesByFullName.put(fullActionName, newKeyStroke);
|
||||
|
||||
Set<DockingActionIf> actions = tool.getAllActions();
|
||||
List<DockingActionIf> actions = actionsByFullName.get(fullActionName);
|
||||
for (DockingActionIf action : actions) {
|
||||
if (action.getFullName().equals(fullActionName)) {
|
||||
action.setUnvalidatedKeyBindingData(new KeyBindingData(newKeyStroke));
|
||||
}
|
||||
action.setUnvalidatedKeyBindingData(new KeyBindingData(newKeyStroke));
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Cancel the changes to the actions.
|
||||
*/
|
||||
public void cancel() {
|
||||
Iterator<String> iter = originalValues.keySet().iterator();
|
||||
while (iter.hasNext()) {
|
||||
|
@ -173,10 +166,12 @@ public class KeyBindingsPanel extends JPanel {
|
|||
String longestName = "";
|
||||
|
||||
actionsByFullName = KeyBindingUtils.getAllActionsByFullName(tool);
|
||||
Set<Entry<String, DockingActionIf>> entries = actionsByFullName.entrySet();
|
||||
for (Entry<String, DockingActionIf> entry : entries) {
|
||||
Set<Entry<String, List<DockingActionIf>>> entries = actionsByFullName.entrySet();
|
||||
for (Entry<String, List<DockingActionIf>> entry : entries) {
|
||||
|
||||
DockingActionIf action = entry.getValue();
|
||||
// pick one action, they are all conceptually the same
|
||||
List<DockingActionIf> actions = entry.getValue();
|
||||
DockingActionIf action = actions.get(0);
|
||||
tableActions.add(action);
|
||||
|
||||
String actionName = entry.getKey();
|
||||
|
@ -413,11 +408,13 @@ public class KeyBindingsPanel extends JPanel {
|
|||
Iterator<String> iter = keyStrokesByFullName.keySet().iterator();
|
||||
while (iter.hasNext()) {
|
||||
String actionName = iter.next();
|
||||
DockingActionIf action = actionsByFullName.get(actionName);
|
||||
if (action == null) {
|
||||
List<DockingActionIf> actions = actionsByFullName.get(actionName);
|
||||
if (actions.isEmpty()) {
|
||||
throw new AssertException("No actions defined for " + actionName);
|
||||
}
|
||||
|
||||
// pick one action, they are all conceptually the same
|
||||
DockingActionIf action = actions.get(0);
|
||||
KeyStroke currentKeyStroke = keyStrokesByFullName.get(actionName);
|
||||
KeyBindingData defaultBinding = action.getDefaultKeyBindingData();
|
||||
KeyStroke newKeyStroke =
|
||||
|
@ -669,11 +666,14 @@ public class KeyBindingsPanel extends JPanel {
|
|||
}
|
||||
|
||||
ksField.setText(ksName);
|
||||
|
||||
// make sure the label gets enough space
|
||||
statusLabel.setPreferredSize(
|
||||
new Dimension(statusLabel.getPreferredSize().width, STATUS_LABEL_HEIGHT));
|
||||
|
||||
DockingActionIf action = actionsByFullName.get(fullActionName);
|
||||
// pick one action, they are all conceptually the same
|
||||
List<DockingActionIf> actions = actionsByFullName.get(fullActionName);
|
||||
DockingActionIf action = actions.get(0);
|
||||
String description = action.getDescription();
|
||||
if (description == null || description.trim().isEmpty()) {
|
||||
description = action.getName();
|
||||
|
|
|
@ -83,7 +83,7 @@ public class GhidraTool extends PluginTool {
|
|||
@Override
|
||||
protected DockingWindowManager createDockingWindowManager(boolean isDockable, boolean hasStatus,
|
||||
boolean isModal) {
|
||||
return new DockingWindowManager("EMPTY", null, this, isModal, isDockable, hasStatus,
|
||||
return new DockingWindowManager(this, null, this, isModal, isDockable, hasStatus,
|
||||
new OpenFileDropHandlerFactory(this));
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue