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.LogManager;
|
||||||
import org.apache.logging.log4j.Logger;
|
import org.apache.logging.log4j.Logger;
|
||||||
|
|
||||||
import docking.DockingWindowManager;
|
|
||||||
import docking.framework.SplashScreen;
|
import docking.framework.SplashScreen;
|
||||||
import ghidra.base.help.GhidraHelpService;
|
import ghidra.base.help.GhidraHelpService;
|
||||||
import ghidra.framework.Application;
|
import ghidra.framework.Application;
|
||||||
|
@ -86,7 +85,6 @@ public class GhidraRun implements GhidraLaunchable {
|
||||||
updateSplashScreenStatusMessage("Populating Ghidra help...");
|
updateSplashScreenStatusMessage("Populating Ghidra help...");
|
||||||
GhidraHelpService.install();
|
GhidraHelpService.install();
|
||||||
|
|
||||||
DockingWindowManager.enableDiagnosticActions(SystemUtilities.isInDevelopmentMode());
|
|
||||||
ExtensionUtils.cleanupUninstalledExtensions();
|
ExtensionUtils.cleanupUninstalledExtensions();
|
||||||
|
|
||||||
// Allows handling of old content which did not have a content type property
|
// Allows handling of old content which did not have a content type property
|
||||||
|
|
|
@ -32,7 +32,7 @@ public class TestTool extends GhidraTool {
|
||||||
@Override
|
@Override
|
||||||
protected DockingWindowManager createDockingWindowManager(boolean isDockable, boolean hasStatus,
|
protected DockingWindowManager createDockingWindowManager(boolean isDockable, boolean hasStatus,
|
||||||
boolean isModal) {
|
boolean isModal) {
|
||||||
return new DockingWindowManager("EMPTY", null, this, isModal, isDockable, hasStatus, null);
|
return new DockingWindowManager(this, null, this, isModal, isDockable, hasStatus, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -27,6 +27,7 @@ import org.junit.*;
|
||||||
import docking.action.DockingActionIf;
|
import docking.action.DockingActionIf;
|
||||||
import docking.action.KeyBindingData;
|
import docking.action.KeyBindingData;
|
||||||
import docking.actions.KeyEntryDialog;
|
import docking.actions.KeyEntryDialog;
|
||||||
|
import docking.actions.ToolActions;
|
||||||
import docking.tool.util.DockingToolConstants;
|
import docking.tool.util.DockingToolConstants;
|
||||||
import ghidra.framework.options.ToolOptions;
|
import ghidra.framework.options.ToolOptions;
|
||||||
import ghidra.framework.plugintool.PluginTool;
|
import ghidra.framework.plugintool.PluginTool;
|
||||||
|
@ -235,15 +236,6 @@ public class ComponentProviderActionsTest extends AbstractGhidraHeadedIntegratio
|
||||||
// Private Methods
|
// 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() {
|
private void switchToTransientProvider() {
|
||||||
provider.setTransient();
|
provider.setTransient();
|
||||||
}
|
}
|
||||||
|
@ -390,9 +382,8 @@ public class ComponentProviderActionsTest extends AbstractGhidraHeadedIntegratio
|
||||||
}
|
}
|
||||||
|
|
||||||
private void performLaunchKeyStrokeDialogAction() {
|
private void performLaunchKeyStrokeDialogAction() {
|
||||||
DockingWindowManager dwm = tool.getWindowManager();
|
ToolActions toolActions = ((AbstractDockingTool) tool).getToolActions();
|
||||||
ActionToGuiMapper actionMapper = dwm.getActionToGuiMapper();
|
Action action = toolActions.getAction(KeyStroke.getKeyStroke("F4"));
|
||||||
Action action = actionMapper.getDockingKeyAction(KeyStroke.getKeyStroke("F4"));
|
|
||||||
assertNotNull(action);
|
assertNotNull(action);
|
||||||
runSwing(() -> action.actionPerformed(new ActionEvent(this, 0, "")), false);
|
runSwing(() -> action.actionPerformed(new ActionEvent(this, 0, "")), false);
|
||||||
}
|
}
|
||||||
|
|
|
@ -32,12 +32,11 @@ import org.junit.Test;
|
||||||
import docking.test.AbstractDockingTest;
|
import docking.test.AbstractDockingTest;
|
||||||
import docking.widgets.label.GDLabel;
|
import docking.widgets.label.GDLabel;
|
||||||
import ghidra.framework.plugintool.ComponentProviderAdapter;
|
import ghidra.framework.plugintool.ComponentProviderAdapter;
|
||||||
|
import ghidra.test.DummyTool;
|
||||||
|
|
||||||
public class DockingWindowManagerTest extends AbstractDockingTest {
|
public class DockingWindowManagerTest extends AbstractDockingTest {
|
||||||
|
|
||||||
public DockingWindowManagerTest() {
|
private DockingTool tool = new DummyTool();
|
||||||
super();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testDefaultGroupWindowPosition() {
|
public void testDefaultGroupWindowPosition() {
|
||||||
|
@ -46,7 +45,7 @@ public class DockingWindowManagerTest extends AbstractDockingTest {
|
||||||
// default window position.
|
// 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 providerA = addProvider(dwm, "A", "a", RIGHT);
|
||||||
ComponentProvider providerB = addProvider(dwm, "B", "b", BOTTOM);
|
ComponentProvider providerB = addProvider(dwm, "B", "b", BOTTOM);
|
||||||
|
@ -66,7 +65,7 @@ public class DockingWindowManagerTest extends AbstractDockingTest {
|
||||||
// intragroup window position. Note: 'Stacked' is the default.
|
// 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 providerA1 = addProvider(dwm, "A1", "a", RIGHT, STACK);
|
||||||
ComponentProvider providerA2 = addProvider(dwm, "A2", "a", BOTTOM, STACK);
|
ComponentProvider providerA2 = addProvider(dwm, "A2", "a", BOTTOM, STACK);
|
||||||
|
@ -84,7 +83,7 @@ public class DockingWindowManagerTest extends AbstractDockingTest {
|
||||||
// intragroup window position.
|
// 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 providerA1 = addProvider(dwm, "A1", "a", RIGHT, STACK);
|
||||||
ComponentProvider providerA2 = addProvider(dwm, "A2", "a", LEFT, BOTTOM);
|
ComponentProvider providerA2 = addProvider(dwm, "A2", "a", LEFT, BOTTOM);
|
||||||
|
@ -101,7 +100,7 @@ public class DockingWindowManagerTest extends AbstractDockingTest {
|
||||||
// intragroup window position.
|
// 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 providerA1 = addProvider(dwm, "A1", "a", RIGHT, WINDOW);
|
||||||
ComponentProvider providerA2 = addProvider(dwm, "A2", "a", LEFT, 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
|
// 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 providerA = addProvider(dwm, "A", "a", RIGHT, STACK);
|
||||||
ComponentProvider providerAB = addProvider(dwm, "AB", "a.b", BOTTOM, 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
|
// 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 providerA = addProvider(dwm, "A", "a", RIGHT, BOTTOM);
|
||||||
ComponentProvider providerAB = addProvider(dwm, "AB", "a.b", BOTTOM, TOP);
|
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
|
// 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
|
// are shown after that XML is restored--even if the window positioning changes
|
||||||
//
|
//
|
||||||
final DockingWindowManager dwm1 =
|
final DockingWindowManager dwm1 = new DockingWindowManager(tool, (List<Image>) null, null);
|
||||||
new DockingWindowManager("test", (List<Image>) null, null);
|
|
||||||
|
|
||||||
ComponentProvider providerA = addProvider(dwm1, "A", "a", RIGHT);
|
ComponentProvider providerA = addProvider(dwm1, "A", "a", RIGHT);
|
||||||
ComponentProvider providerB = addProvider(dwm1, "B", "b", BOTTOM);
|
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
|
// 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
|
// 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 providerA = addProvider(dwm1, "A", "a", RIGHT);
|
||||||
ComponentProvider providerAB = addProvider(dwm1, "AB", "a.b", BOTTOM);
|
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
|
// 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.
|
// 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 providerA = addProvider(dwm, "A", "a", TOP, RIGHT);
|
||||||
ComponentProvider providerAB = addProvider(dwm, "AB", "a.b", RIGHT, BOTTOM);
|
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
|
// 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.
|
// 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 providerAB = addProvider(dwm, "AB", "a.b", RIGHT, BOTTOM);
|
||||||
ComponentProvider providerA = addProvider(dwm, "A", "a", TOP, RIGHT);
|
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
|
// Test that two providers that don't share an owner (the plugin) can share a group and
|
||||||
// open relative to each other.
|
// 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 p1 = addProvider(dwm, "Owner_1", "Name_1", "group", TOP, TOP);
|
||||||
ComponentProvider p2 = addProvider(dwm, "Owner_2", "Name_2", "group", BOTTOM, RIGHT);
|
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 pA = addProvider(dwm, "Owner_1", "A", "a", LEFT, LEFT);
|
||||||
ComponentProvider pB = addProvider(dwm, "Owner_2", "B", "b", RIGHT, RIGHT);
|
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) {
|
private DockingWindowManager createNewDockingWindowManagerFromXML(final Element element) {
|
||||||
final DockingWindowManager dwm2 =
|
final DockingWindowManager dwm2 =
|
||||||
new DockingWindowManager("text2", (List<Image>) null, null);
|
new DockingWindowManager(new DummyTool("Tool2"), (List<Image>) null, null);
|
||||||
|
|
||||||
runSwing(() -> {
|
runSwing(() -> {
|
||||||
dwm2.setVisible(true);
|
dwm2.setVisible(true);
|
||||||
|
|
|
@ -30,10 +30,12 @@ import org.junit.Test;
|
||||||
import docking.DockingWindowManager;
|
import docking.DockingWindowManager;
|
||||||
import docking.test.AbstractDockingTest;
|
import docking.test.AbstractDockingTest;
|
||||||
import docking.widgets.textfield.IntegerTextField;
|
import docking.widgets.textfield.IntegerTextField;
|
||||||
|
import ghidra.test.DummyTool;
|
||||||
|
|
||||||
public class NumberInputDialogTest extends AbstractDockingTest {
|
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 NumberInputDialog dialog;
|
||||||
private JButton okButton;
|
private JButton okButton;
|
||||||
private JTextField textField;
|
private JTextField textField;
|
||||||
|
|
|
@ -28,6 +28,7 @@ import docking.widgets.filter.*;
|
||||||
import docking.widgets.table.model.DirData;
|
import docking.widgets.table.model.DirData;
|
||||||
import docking.widgets.table.model.TestDataModel;
|
import docking.widgets.table.model.TestDataModel;
|
||||||
import ghidra.test.AbstractGhidraHeadedIntegrationTest;
|
import ghidra.test.AbstractGhidraHeadedIntegrationTest;
|
||||||
|
import ghidra.test.DummyTool;
|
||||||
import ghidra.util.table.GhidraTable;
|
import ghidra.util.table.GhidraTable;
|
||||||
|
|
||||||
public class GhidraTableFilterTest extends AbstractGhidraHeadedIntegrationTest {
|
public class GhidraTableFilterTest extends AbstractGhidraHeadedIntegrationTest {
|
||||||
|
@ -50,7 +51,7 @@ public class GhidraTableFilterTest extends AbstractGhidraHeadedIntegrationTest {
|
||||||
filteredModel = filterPanel.getTableFilterModel();
|
filteredModel = filterPanel.getTableFilterModel();
|
||||||
table.setAutoLookupColumn(4);
|
table.setAutoLookupColumn(4);
|
||||||
|
|
||||||
winMgr = new DockingWindowManager("Tests", null, null);
|
winMgr = new DockingWindowManager(new DummyTool(), null, null);
|
||||||
winMgr.addComponent(new TestTableComponentProvider());
|
winMgr.addComponent(new TestTableComponentProvider());
|
||||||
winMgr.setVisible(true);
|
winMgr.setVisible(true);
|
||||||
}
|
}
|
||||||
|
|
|
@ -28,6 +28,7 @@ import org.jdom.Element;
|
||||||
|
|
||||||
import docking.*;
|
import docking.*;
|
||||||
import docking.action.DockingActionIf;
|
import docking.action.DockingActionIf;
|
||||||
|
import docking.actions.DockingToolActions;
|
||||||
import ghidra.framework.model.*;
|
import ghidra.framework.model.*;
|
||||||
import ghidra.framework.options.ToolOptions;
|
import ghidra.framework.options.ToolOptions;
|
||||||
import ghidra.framework.plugintool.PluginEvent;
|
import ghidra.framework.plugintool.PluginEvent;
|
||||||
|
@ -42,6 +43,8 @@ public class DummyTool implements Tool {
|
||||||
private ToolIconURL iconURL;
|
private ToolIconURL iconURL;
|
||||||
private Project project;
|
private Project project;
|
||||||
|
|
||||||
|
private DockingToolActions toolActions = new DummyToolActions();
|
||||||
|
|
||||||
public DummyTool() {
|
public DummyTool() {
|
||||||
this(DEFAULT_NAME);
|
this(DEFAULT_NAME);
|
||||||
}
|
}
|
||||||
|
@ -305,6 +308,11 @@ public class DummyTool implements Tool {
|
||||||
return Collections.emptySet();
|
return Collections.emptySet();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ComponentProvider getActiveComponentProvider() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void showComponentProvider(ComponentProvider componentProvider, boolean visible) {
|
public void showComponentProvider(ComponentProvider componentProvider, boolean visible) {
|
||||||
//do nothing
|
//do nothing
|
||||||
|
@ -345,6 +353,11 @@ public class DummyTool implements Tool {
|
||||||
//do nothing
|
//do nothing
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ActionContext getGlobalContext() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setStatusInfo(String text) {
|
public void setStatusInfo(String text) {
|
||||||
//do nothing
|
//do nothing
|
||||||
|
@ -389,4 +402,9 @@ public class DummyTool implements Tool {
|
||||||
public void removeContextListener(DockingContextListener listener) {
|
public void removeContextListener(DockingContextListener listener) {
|
||||||
//do nothing
|
//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) {
|
public void addComponentProvider(ComponentProvider provider, boolean show) {
|
||||||
Runnable r = () -> {
|
Runnable r = () -> {
|
||||||
winMgr.addComponent(provider, show);
|
winMgr.addComponent(provider, show);
|
||||||
toolActions.addToolAction(provider.getShowProviderAction());
|
toolActions.addGlobalAction(provider.getShowProviderAction());
|
||||||
};
|
};
|
||||||
Swing.runNow(r);
|
Swing.runNow(r);
|
||||||
}
|
}
|
||||||
|
@ -67,7 +67,7 @@ public abstract class AbstractDockingTool implements DockingTool {
|
||||||
@Override
|
@Override
|
||||||
public void removeComponentProvider(ComponentProvider provider) {
|
public void removeComponentProvider(ComponentProvider provider) {
|
||||||
Runnable r = () -> {
|
Runnable r = () -> {
|
||||||
toolActions.removeComponentActions(provider);
|
toolActions.removeActions(provider);
|
||||||
winMgr.removeComponent(provider);
|
winMgr.removeComponent(provider);
|
||||||
};
|
};
|
||||||
Swing.runNow(r);
|
Swing.runNow(r);
|
||||||
|
@ -99,12 +99,12 @@ public abstract class AbstractDockingTool implements DockingTool {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void addAction(DockingActionIf action) {
|
public void addAction(DockingActionIf action) {
|
||||||
toolActions.addToolAction(action);
|
toolActions.addGlobalAction(action);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void removeAction(DockingActionIf action) {
|
public void removeAction(DockingActionIf action) {
|
||||||
toolActions.removeToolAction(action);
|
toolActions.removeGlobalAction(action);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -114,15 +114,12 @@ public abstract class AbstractDockingTool implements DockingTool {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void removeLocalAction(ComponentProvider provider, DockingActionIf action) {
|
public void removeLocalAction(ComponentProvider provider, DockingActionIf action) {
|
||||||
toolActions.removeProviderAction(provider, action);
|
toolActions.removeLocalAction(provider, action);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Set<DockingActionIf> getAllActions() {
|
public Set<DockingActionIf> getAllActions() {
|
||||||
Set<DockingActionIf> actions = toolActions.getAllActions();
|
return toolActions.getAllActions();
|
||||||
ActionToGuiMapper am = winMgr.getActionToGuiMapper();
|
|
||||||
actions.addAll(am.getAllActions());
|
|
||||||
return actions;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -130,6 +127,11 @@ public abstract class AbstractDockingTool implements DockingTool {
|
||||||
return toolActions.getActions(owner);
|
return toolActions.getActions(owner);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ComponentProvider getActiveComponentProvider() {
|
||||||
|
return winMgr.getActiveComponentProvider();
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void showComponentProvider(ComponentProvider provider, boolean visible) {
|
public void showComponentProvider(ComponentProvider provider, boolean visible) {
|
||||||
Runnable r = () -> winMgr.showComponent(provider, visible);
|
Runnable r = () -> winMgr.showComponent(provider, visible);
|
||||||
|
@ -176,6 +178,11 @@ public abstract class AbstractDockingTool implements DockingTool {
|
||||||
winMgr.contextChanged(provider);
|
winMgr.contextChanged(provider);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ActionContext getGlobalContext() {
|
||||||
|
return winMgr.getGlobalContext();
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void addContextListener(DockingContextListener listener) {
|
public void addContextListener(DockingContextListener listener) {
|
||||||
winMgr.addContextListener(listener);
|
winMgr.addContextListener(listener);
|
||||||
|
@ -200,4 +207,9 @@ public abstract class AbstractDockingTool implements DockingTool {
|
||||||
public boolean hasConfigChanged() {
|
public boolean hasConfigChanged() {
|
||||||
return configChangedFlag;
|
return configChangedFlag;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ToolActions getToolActions() {
|
||||||
|
return toolActions;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,7 +18,6 @@ package docking;
|
||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
|
|
||||||
import docking.action.DockingActionIf;
|
import docking.action.DockingActionIf;
|
||||||
import docking.action.KeyBindingsManager;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A class that exists primarily to provide access to action-related package-level methods of the
|
* 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);
|
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
|
* Call this method to signal that key bindings for one or more actions have changed
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -16,63 +16,38 @@
|
||||||
package docking;
|
package docking;
|
||||||
|
|
||||||
import java.awt.event.MouseEvent;
|
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.MenuGroupMap;
|
||||||
import docking.menu.MenuHandler;
|
import docking.menu.MenuHandler;
|
||||||
import ghidra.util.*;
|
import ghidra.util.HelpLocation;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Manages the global actions for the menu and toolbar.
|
* Manages the global actions for the menu and toolbar.
|
||||||
*/
|
*/
|
||||||
public class ActionToGuiMapper {
|
public class ActionToGuiMapper {
|
||||||
|
|
||||||
private static boolean enableDiagnosticActions;
|
|
||||||
|
|
||||||
private Set<DockingActionIf> globalActions = new LinkedHashSet<>();
|
private Set<DockingActionIf> globalActions = new LinkedHashSet<>();
|
||||||
|
|
||||||
private MenuHandler menuBarMenuHandler;
|
private MenuHandler menuBarMenuHandler;
|
||||||
private MenuGroupMap menuGroupMap;
|
private MenuGroupMap menuGroupMap;
|
||||||
|
|
||||||
private KeyBindingsManager keyBindingsManager;
|
|
||||||
private GlobalMenuAndToolBarManager menuAndToolBarManager;
|
private GlobalMenuAndToolBarManager menuAndToolBarManager;
|
||||||
private PopupActionManager popupActionManager;
|
private PopupActionManager popupActionManager;
|
||||||
|
|
||||||
ActionToGuiMapper(DockingWindowManager winMgr, KeyBindingsManager keyBindingsManager) {
|
ActionToGuiMapper(DockingWindowManager winMgr) {
|
||||||
this.keyBindingsManager = keyBindingsManager;
|
|
||||||
menuGroupMap = new MenuGroupMap();
|
menuGroupMap = new MenuGroupMap();
|
||||||
menuBarMenuHandler = new MenuBarMenuHandler(winMgr);
|
menuBarMenuHandler = new MenuBarMenuHandler(winMgr);
|
||||||
menuAndToolBarManager =
|
menuAndToolBarManager =
|
||||||
new GlobalMenuAndToolBarManager(winMgr, menuBarMenuHandler, menuGroupMap);
|
new GlobalMenuAndToolBarManager(winMgr, menuBarMenuHandler, menuGroupMap);
|
||||||
popupActionManager = new PopupActionManager(winMgr, menuGroupMap);
|
popupActionManager = new PopupActionManager(winMgr, menuGroupMap);
|
||||||
|
|
||||||
initializeHelpActions();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void initializeHelpActions() {
|
|
||||||
DockingWindowsContextSensitiveHelpListener.install();
|
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);
|
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.
|
* Adds the given Global action to the menu and/or toolbar.
|
||||||
* @param action the action to be added.
|
* @param action the action to be added.
|
||||||
*/
|
*/
|
||||||
void addToolAction(DockingActionIf action) {
|
void addToolAction(DockingActionIf action) {
|
||||||
if (globalActions.add(action)) {
|
if (globalActions.add(action)) {
|
||||||
keyBindingsManager.addAction(action, null);
|
|
||||||
popupActionManager.addAction(action);
|
popupActionManager.addAction(action);
|
||||||
menuAndToolBarManager.addAction(action);
|
menuAndToolBarManager.addAction(action);
|
||||||
}
|
}
|
||||||
|
@ -132,24 +78,11 @@ public class ActionToGuiMapper {
|
||||||
* @param action the action to be removed.
|
* @param action the action to be removed.
|
||||||
*/
|
*/
|
||||||
void removeToolAction(DockingActionIf action) {
|
void removeToolAction(DockingActionIf action) {
|
||||||
keyBindingsManager.removeAction(action);
|
|
||||||
popupActionManager.removeAction(action);
|
popupActionManager.removeAction(action);
|
||||||
menuAndToolBarManager.removeAction(action);
|
menuAndToolBarManager.removeAction(action);
|
||||||
globalActions.remove(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() {
|
Set<DockingActionIf> getGlobalActions() {
|
||||||
return globalActions;
|
return globalActions;
|
||||||
}
|
}
|
||||||
|
@ -162,28 +95,16 @@ public class ActionToGuiMapper {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Close all menus (includes popup menus)
|
|
||||||
*/
|
|
||||||
private void dismissMenus() {
|
private void dismissMenus() {
|
||||||
MenuSelectionManager.defaultManager().clearSelectedPath();
|
MenuSelectionManager.defaultManager().clearSelectedPath();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Updates the menu and toolbar to reflect any changes in the set of actions.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
void update() {
|
void update() {
|
||||||
menuAndToolBarManager.update();
|
menuAndToolBarManager.update();
|
||||||
contextChangedAll();
|
contextChangedAll();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Releases all resources and makes this object unavailable for future use.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
void dispose() {
|
void dispose() {
|
||||||
keyBindingsManager.dispose();
|
|
||||||
popupActionManager.dispose();
|
popupActionManager.dispose();
|
||||||
menuAndToolBarManager.dispose();
|
menuAndToolBarManager.dispose();
|
||||||
globalActions.clear();
|
globalActions.clear();
|
||||||
|
@ -216,8 +137,4 @@ public class ActionToGuiMapper {
|
||||||
public void showPopupMenu(ComponentPlaceholder componentInfo, MouseEvent e) {
|
public void showPopupMenu(ComponentPlaceholder componentInfo, MouseEvent e) {
|
||||||
popupActionManager.popupMenu(componentInfo, 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()) {
|
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);
|
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
|
* 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.
|
* 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;
|
private DockingActionIf docakbleAction;
|
||||||
|
|
||||||
protected KeyStroke keyStroke;
|
protected final KeyStroke keyStroke;
|
||||||
protected final DockingWindowManager winMgr;
|
protected final DockingTool tool;
|
||||||
|
|
||||||
public DockingKeyBindingAction(DockingWindowManager winMgr, DockingActionIf action,
|
public DockingKeyBindingAction(DockingTool tool, DockingActionIf action, KeyStroke keyStroke) {
|
||||||
KeyStroke keyStroke) {
|
|
||||||
super(KeyBindingUtils.parseKeyStroke(keyStroke));
|
super(KeyBindingUtils.parseKeyStroke(keyStroke));
|
||||||
this.winMgr = winMgr;
|
this.tool = tool;
|
||||||
this.docakbleAction = action;
|
this.docakbleAction = action;
|
||||||
this.keyStroke = keyStroke;
|
this.keyStroke = keyStroke;
|
||||||
}
|
}
|
||||||
|
@ -52,18 +51,16 @@ public class DockingKeyBindingAction extends AbstractAction {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isReservedKeybindingPrecedence() {
|
public abstract KeyBindingPrecedence getKeyBindingPrecedence();
|
||||||
return getKeyBindingPrecedence() == KeyBindingPrecedence.ReservedActionsLevel;
|
|
||||||
}
|
|
||||||
|
|
||||||
public KeyBindingPrecedence getKeyBindingPrecedence() {
|
public boolean isReservedKeybindingPrecedence() {
|
||||||
return KeyBindingPrecedence.ReservedActionsLevel;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void actionPerformed(final ActionEvent e) {
|
public void actionPerformed(final ActionEvent e) {
|
||||||
winMgr.setStatusText("");
|
tool.setStatusInfo("");
|
||||||
ComponentProvider provider = winMgr.getActiveComponentProvider();
|
ComponentProvider provider = tool.getActiveComponentProvider();
|
||||||
ActionContext context = getLocalContext(provider);
|
ActionContext context = getLocalContext(provider);
|
||||||
context.setSource(e.getSource());
|
context.setSource(e.getSource());
|
||||||
docakbleAction.actionPerformed(context);
|
docakbleAction.actionPerformed(context);
|
||||||
|
|
|
@ -21,6 +21,7 @@ import java.util.Set;
|
||||||
import javax.swing.ImageIcon;
|
import javax.swing.ImageIcon;
|
||||||
|
|
||||||
import docking.action.DockingActionIf;
|
import docking.action.DockingActionIf;
|
||||||
|
import docking.actions.DockingToolActions;
|
||||||
import ghidra.framework.options.ToolOptions;
|
import ghidra.framework.options.ToolOptions;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -151,6 +152,12 @@ public interface DockingTool {
|
||||||
*/
|
*/
|
||||||
public Set<DockingActionIf> getDockingActionsByOwnerName(String owner);
|
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
|
* Shows or hides the component provider in the tool
|
||||||
* @param componentProvider the provider to either show or hide.
|
* @param componentProvider the provider to either show or hide.
|
||||||
|
@ -209,6 +216,15 @@ public interface DockingTool {
|
||||||
*/
|
*/
|
||||||
public void contextChanged(ComponentProvider provider);
|
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
|
* Adds the given context listener to this tool
|
||||||
* @param listener the listener to add
|
* @param listener the listener to add
|
||||||
|
@ -246,4 +262,15 @@ public interface DockingTool {
|
||||||
* @return true if the tool's configuration has changed
|
* @return true if the tool's configuration has changed
|
||||||
*/
|
*/
|
||||||
public boolean hasConfigChanged();
|
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 org.jdom.Element;
|
||||||
|
|
||||||
import docking.action.DockingActionIf;
|
import docking.action.DockingActionIf;
|
||||||
import docking.action.KeyBindingsManager;
|
import docking.actions.DockingToolActions;
|
||||||
|
import docking.actions.ToolActions;
|
||||||
import docking.help.HelpService;
|
import docking.help.HelpService;
|
||||||
import generic.util.WindowUtilities;
|
import generic.util.WindowUtilities;
|
||||||
import ghidra.framework.OperatingSystem;
|
import ghidra.framework.OperatingSystem;
|
||||||
|
@ -73,6 +74,7 @@ public class DockingWindowManager implements PropertyChangeListener, Placeholder
|
||||||
|
|
||||||
private static List<DockingWindowManager> instanceList = new ArrayList<>();
|
private static List<DockingWindowManager> instanceList = new ArrayList<>();
|
||||||
|
|
||||||
|
private DockingTool tool;
|
||||||
private RootNode root;
|
private RootNode root;
|
||||||
|
|
||||||
private PlaceholderManager placeholderManager;
|
private PlaceholderManager placeholderManager;
|
||||||
|
@ -105,18 +107,18 @@ public class DockingWindowManager implements PropertyChangeListener, Placeholder
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructs a new DockingWindowManager
|
* 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 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) {
|
public DockingWindowManager(DockingTool tool, List<Image> images, DockWinListener docListener) {
|
||||||
this(toolName, images, docListener, false, true, true, null);
|
this(tool, images, docListener, false, true, true, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructs a new DockingWindowManager
|
* 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 images the list of icons to set on the window
|
||||||
* @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
|
||||||
* @param modal if true then the root window will be a modal dialog instead of a frame
|
* @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 hasStatusBar if true a status bar will be created for the main window
|
||||||
* @param factory the drop target factory
|
* @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) {
|
boolean modal, boolean isDocking, boolean hasStatusBar, DropTargetFactory factory) {
|
||||||
|
|
||||||
KeyBindingOverrideKeyEventDispatcher.install();
|
KeyBindingOverrideKeyEventDispatcher.install();
|
||||||
|
|
||||||
|
this.tool = tool;
|
||||||
this.docListener = docListener;
|
this.docListener = docListener;
|
||||||
this.isDocking = isDocking;
|
this.isDocking = isDocking;
|
||||||
this.hasStatusBar = hasStatusBar;
|
this.hasStatusBar = hasStatusBar;
|
||||||
|
@ -137,7 +140,7 @@ public class DockingWindowManager implements PropertyChangeListener, Placeholder
|
||||||
images = new ArrayList<>();
|
images = new ArrayList<>();
|
||||||
}
|
}
|
||||||
|
|
||||||
root = new RootNode(this, toolName, images, modal, factory);
|
root = new RootNode(this, tool.getName(), images, modal, factory);
|
||||||
|
|
||||||
KeyboardFocusManager km = KeyboardFocusManager.getCurrentKeyboardFocusManager();
|
KeyboardFocusManager km = KeyboardFocusManager.getCurrentKeyboardFocusManager();
|
||||||
km.addPropertyChangeListener("permanentFocusOwner", this);
|
km.addPropertyChangeListener("permanentFocusOwner", this);
|
||||||
|
@ -145,6 +148,7 @@ public class DockingWindowManager implements PropertyChangeListener, Placeholder
|
||||||
addInstance(this);
|
addInstance(this);
|
||||||
|
|
||||||
placeholderManager = new PlaceholderManager(this);
|
placeholderManager = new PlaceholderManager(this);
|
||||||
|
actionToGuiMapper = new ActionToGuiMapper(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -152,15 +156,6 @@ public class DockingWindowManager implements PropertyChangeListener, Placeholder
|
||||||
return "DockingWindowManager: " + root.getTitle();
|
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.
|
* Sets the help service for the all docking window managers.
|
||||||
* @param helpSvc the help service to use.
|
* @param helpSvc the help service to use.
|
||||||
|
@ -310,17 +305,6 @@ public class DockingWindowManager implements PropertyChangeListener, Placeholder
|
||||||
root.setIcon(icon);
|
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.
|
* Returns true if this manager contains the given provider.
|
||||||
*
|
*
|
||||||
|
@ -362,6 +346,13 @@ public class DockingWindowManager implements PropertyChangeListener, Placeholder
|
||||||
defaultProvider = provider;
|
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() {
|
public ActionContext getGlobalContext() {
|
||||||
if (defaultProvider != null) {
|
if (defaultProvider != null) {
|
||||||
ActionContext actionContext = defaultProvider.getActionContext(null);
|
ActionContext actionContext = defaultProvider.getActionContext(null);
|
||||||
|
@ -640,24 +631,10 @@ public class DockingWindowManager implements PropertyChangeListener, Placeholder
|
||||||
placeholderManager.removeComponent(provider);
|
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
|
// Package-level Action Methods
|
||||||
//==================================================================================================
|
//==================================================================================================
|
||||||
|
|
||||||
void setKeyBindingsManager(KeyBindingsManager keyBindingsManager) {
|
|
||||||
actionToGuiMapper = new ActionToGuiMapper(this, keyBindingsManager);
|
|
||||||
}
|
|
||||||
|
|
||||||
Iterator<DockingActionIf> getComponentActions(ComponentProvider provider) {
|
Iterator<DockingActionIf> getComponentActions(ComponentProvider provider) {
|
||||||
ComponentPlaceholder placeholder = getActivePlaceholder(provider);
|
ComponentPlaceholder placeholder = getActivePlaceholder(provider);
|
||||||
if (placeholder != null) {
|
if (placeholder != null) {
|
||||||
|
@ -671,7 +648,6 @@ public class DockingWindowManager implements PropertyChangeListener, Placeholder
|
||||||
void removeProviderAction(ComponentProvider provider, DockingActionIf action) {
|
void removeProviderAction(ComponentProvider provider, DockingActionIf action) {
|
||||||
ComponentPlaceholder placeholder = getActivePlaceholder(provider);
|
ComponentPlaceholder placeholder = getActivePlaceholder(provider);
|
||||||
if (placeholder != null) {
|
if (placeholder != null) {
|
||||||
actionToGuiMapper.removeLocalAction(action);
|
|
||||||
placeholder.removeAction(action);
|
placeholder.removeAction(action);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -682,7 +658,6 @@ public class DockingWindowManager implements PropertyChangeListener, Placeholder
|
||||||
throw new IllegalArgumentException("Unknown component provider: " + provider);
|
throw new IllegalArgumentException("Unknown component provider: " + provider);
|
||||||
}
|
}
|
||||||
placeholder.addAction(action);
|
placeholder.addAction(action);
|
||||||
actionToGuiMapper.addLocalAction(action, provider);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void addToolAction(DockingActionIf action) {
|
void addToolAction(DockingActionIf action) {
|
||||||
|
@ -695,10 +670,32 @@ public class DockingWindowManager implements PropertyChangeListener, Placeholder
|
||||||
scheduleUpdate();
|
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
|
// End Package-level Methods
|
||||||
//==================================================================================================
|
//==================================================================================================
|
||||||
|
|
||||||
|
public void ownerRemoved(String owner) {
|
||||||
|
placeholderManager.removeAll(owner);
|
||||||
|
scheduleUpdate();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Hides or shows the component associated with the given provider.
|
* Hides or shows the component associated with the given provider.
|
||||||
* <p><br>
|
* <p><br>
|
||||||
|
@ -1002,7 +999,7 @@ public class DockingWindowManager implements PropertyChangeListener, Placeholder
|
||||||
Iterator<DockingActionIf> iter = placeholder.getActions();
|
Iterator<DockingActionIf> iter = placeholder.getActions();
|
||||||
while (iter.hasNext()) {
|
while (iter.hasNext()) {
|
||||||
DockingActionIf action = iter.next();
|
DockingActionIf action = iter.next();
|
||||||
actionToGuiMapper.removeLocalAction(action);
|
placeholder.removeAction(action);
|
||||||
}
|
}
|
||||||
|
|
||||||
ComponentNode node = placeholder.getNode();
|
ComponentNode node = placeholder.getNode();
|
||||||
|
@ -1093,7 +1090,7 @@ public class DockingWindowManager implements PropertyChangeListener, Placeholder
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
actionToGuiMapper.removeAll(DOCKING_WINDOWS_OWNER);
|
tool.getToolActions().removeActions(DOCKING_WINDOWS_OWNER);
|
||||||
|
|
||||||
Map<String, List<ComponentPlaceholder>> permanentMap = new HashMap<>();
|
Map<String, List<ComponentPlaceholder>> permanentMap = new HashMap<>();
|
||||||
Map<String, List<ComponentPlaceholder>> transientMap = 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));
|
actionList.add(new ShowAllComponentsAction(this, placeholders, subMenuName));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
DockingToolActions toolActions = tool.getToolActions();
|
||||||
Collections.sort(actionList);
|
Collections.sort(actionList);
|
||||||
for (ShowComponentAction action : 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);
|
Collections.sort(actions);
|
||||||
for (ShowWindowAction action : 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
|
* Notifies the window manager that an update is needed
|
||||||
*/
|
*/
|
||||||
void scheduleUpdate() {
|
void scheduleUpdate() {
|
||||||
|
if (rebuildUpdater.isBusy()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
rebuildUpdater.updateLater();
|
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
|
root.update(); // do this before rebuilding the menu, as new windows may be opened
|
||||||
|
|
||||||
buildComponentMenu();
|
buildComponentMenu();
|
||||||
SystemUtilities.runSwingLater(() -> updateFocus());
|
SystemUtilities.runSwingLater(() -> updateFocus());
|
||||||
}
|
}
|
||||||
|
|
|
@ -36,7 +36,6 @@ class ShowComponentAction extends DockingAction implements Comparable<ShowCompon
|
||||||
protected DockingWindowManager winMgr;
|
protected DockingWindowManager winMgr;
|
||||||
private ComponentPlaceholder info;
|
private ComponentPlaceholder info;
|
||||||
private String title;
|
private String title;
|
||||||
private boolean isTransient;
|
|
||||||
|
|
||||||
private static String truncateTitleAsNeeded(String title) {
|
private static String truncateTitleAsNeeded(String title) {
|
||||||
if (title.length() <= MAX_LENGTH) {
|
if (title.length() <= MAX_LENGTH) {
|
||||||
|
@ -58,7 +57,6 @@ class ShowComponentAction extends DockingAction implements Comparable<ShowCompon
|
||||||
this.info = placeholder;
|
this.info = placeholder;
|
||||||
this.winMgr = winMgr;
|
this.winMgr = winMgr;
|
||||||
this.title = truncateTitleAsNeeded(placeholder.getTitle());
|
this.title = truncateTitleAsNeeded(placeholder.getTitle());
|
||||||
this.isTransient = isTransient;
|
|
||||||
String group = isTransient ? "Transient" : "Permanent";
|
String group = isTransient ? "Transient" : "Permanent";
|
||||||
|
|
||||||
Icon icon = placeholder.getIcon();
|
Icon icon = placeholder.getIcon();
|
||||||
|
@ -139,6 +137,10 @@ class ShowComponentAction extends DockingAction implements Comparable<ShowCompon
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getHelpInfo() {
|
public String getHelpInfo() {
|
||||||
|
if (info == null) {
|
||||||
|
return super.getHelpInfo();
|
||||||
|
}
|
||||||
|
|
||||||
StringBuilder buffy = new StringBuilder(super.getHelpInfo());
|
StringBuilder buffy = new StringBuilder(super.getHelpInfo());
|
||||||
|
|
||||||
ComponentProvider provider = info.getProvider();
|
ComponentProvider provider = info.getProvider();
|
||||||
|
|
|
@ -17,7 +17,8 @@ package docking.action;
|
||||||
|
|
||||||
import java.beans.PropertyChangeEvent;
|
import java.beans.PropertyChangeEvent;
|
||||||
import java.beans.PropertyChangeListener;
|
import java.beans.PropertyChangeListener;
|
||||||
import java.util.*;
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
import javax.swing.Action;
|
import javax.swing.Action;
|
||||||
import javax.swing.KeyStroke;
|
import javax.swing.KeyStroke;
|
||||||
|
@ -30,11 +31,10 @@ public class KeyBindingsManager implements PropertyChangeListener {
|
||||||
|
|
||||||
protected Map<KeyStroke, DockingKeyBindingAction> dockingKeyMap;
|
protected Map<KeyStroke, DockingKeyBindingAction> dockingKeyMap;
|
||||||
protected Map<DockingActionIf, ComponentProvider> actionToProviderMap;
|
protected Map<DockingActionIf, ComponentProvider> actionToProviderMap;
|
||||||
|
private DockingTool tool;
|
||||||
|
|
||||||
private DockingWindowManager winMgr;
|
public KeyBindingsManager(DockingTool tool) {
|
||||||
|
this.tool = tool;
|
||||||
public KeyBindingsManager(DockingWindowManager winMgr) {
|
|
||||||
this.winMgr = winMgr;
|
|
||||||
dockingKeyMap = new HashMap<>();
|
dockingKeyMap = new HashMap<>();
|
||||||
actionToProviderMap = new HashMap<>();
|
actionToProviderMap = new HashMap<>();
|
||||||
}
|
}
|
||||||
|
@ -76,8 +76,7 @@ public class KeyBindingsManager implements PropertyChangeListener {
|
||||||
|
|
||||||
DockingKeyBindingAction existingAction = dockingKeyMap.get(keyStroke);
|
DockingKeyBindingAction existingAction = dockingKeyMap.get(keyStroke);
|
||||||
if (existingAction == null) {
|
if (existingAction == null) {
|
||||||
dockingKeyMap.put(keyStroke,
|
dockingKeyMap.put(keyStroke, new MultipleKeyAction(tool, provider, action, keyStroke));
|
||||||
new MultipleKeyAction(winMgr, provider, action, keyStroke));
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -98,7 +97,7 @@ public class KeyBindingsManager implements PropertyChangeListener {
|
||||||
|
|
||||||
KeyBindingData binding = KeyBindingData.createReservedKeyBindingData(keyStroke);
|
KeyBindingData binding = KeyBindingData.createReservedKeyBindingData(keyStroke);
|
||||||
action.setKeyBindingData(binding);
|
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) {
|
public Action getDockingKeyAction(KeyStroke keyStroke) {
|
||||||
return dockingKeyMap.get(keyStroke);
|
return dockingKeyMap.get(keyStroke);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void dispose() {
|
public void dispose() {
|
||||||
winMgr = null;
|
|
||||||
dockingKeyMap.clear();
|
dockingKeyMap.clear();
|
||||||
actionToProviderMap.clear();
|
actionToProviderMap.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -32,35 +32,17 @@ public class MultipleKeyAction extends DockingKeyBindingAction {
|
||||||
|
|
||||||
private ActionDialog dialog;
|
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
|
* 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 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 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
|
* @param keyStroke the keystroke, if any, associated with the action
|
||||||
*/
|
*/
|
||||||
public MultipleKeyAction(DockingWindowManager winMgr, ComponentProvider provider,
|
public MultipleKeyAction(DockingTool tool, ComponentProvider provider, DockingActionIf action,
|
||||||
DockingActionIf action, KeyStroke keyStroke) {
|
KeyStroke keyStroke) {
|
||||||
super(winMgr, action, keyStroke);
|
super(tool, action, keyStroke);
|
||||||
addAction(provider, action);
|
addAction(provider, action);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -134,11 +116,11 @@ public class MultipleKeyAction extends DockingKeyBindingAction {
|
||||||
@Override
|
@Override
|
||||||
public void actionPerformed(final ActionEvent event) {
|
public void actionPerformed(final ActionEvent event) {
|
||||||
// Build list of actions which are valid in current context
|
// Build list of actions which are valid in current context
|
||||||
ComponentProvider localProvider = winMgr.getActiveComponentProvider();
|
ComponentProvider localProvider = tool.getActiveComponentProvider();
|
||||||
ActionContext localContext = getLocalContext(localProvider);
|
ActionContext localContext = getLocalContext(localProvider);
|
||||||
localContext.setSource(event.getSource());
|
localContext.setSource(event.getSource());
|
||||||
|
|
||||||
ActionContext globalContext = winMgr.getGlobalContext();
|
ActionContext globalContext = tool.getGlobalContext();
|
||||||
List<ExecutableKeyActionAdapter> list = getValidContextActions(localContext, globalContext);
|
List<ExecutableKeyActionAdapter> list = getValidContextActions(localContext, globalContext);
|
||||||
|
|
||||||
// If menu active, disable all key bindings
|
// If menu active, disable all key bindings
|
||||||
|
@ -163,12 +145,12 @@ public class MultipleKeyAction extends DockingKeyBindingAction {
|
||||||
}
|
}
|
||||||
else if (list.size() == 1) {
|
else if (list.size() == 1) {
|
||||||
final ExecutableKeyActionAdapter actionProxy = list.get(0);
|
final ExecutableKeyActionAdapter actionProxy = list.get(0);
|
||||||
winMgr.setStatusText("");
|
tool.setStatusInfo("");
|
||||||
actionProxy.execute();
|
actionProxy.execute();
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
String name = (String) getValue(Action.NAME);
|
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
|
@Override
|
||||||
public KeyBindingPrecedence getKeyBindingPrecedence() {
|
public KeyBindingPrecedence getKeyBindingPrecedence() {
|
||||||
ComponentProvider localProvider = winMgr.getActiveComponentProvider();
|
ComponentProvider localProvider = tool.getActiveComponentProvider();
|
||||||
ActionContext localContext = getLocalContext(localProvider);
|
ActionContext localContext = getLocalContext(localProvider);
|
||||||
ActionContext globalContext = winMgr.getGlobalContext();
|
ActionContext globalContext = tool.getGlobalContext();
|
||||||
List<ExecutableKeyActionAdapter> validActions =
|
List<ExecutableKeyActionAdapter> validActions =
|
||||||
getValidContextActions(localContext, globalContext);
|
getValidContextActions(localContext, globalContext);
|
||||||
|
|
||||||
|
@ -274,4 +256,22 @@ public class MultipleKeyAction extends DockingKeyBindingAction {
|
||||||
|
|
||||||
return buildy.toString();
|
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 javax.swing.KeyStroke;
|
||||||
|
|
||||||
import docking.DockingKeyBindingAction;
|
import docking.*;
|
||||||
import docking.DockingWindowManager;
|
|
||||||
|
|
||||||
class ReservedKeyBindingAction extends DockingKeyBindingAction {
|
class ReservedKeyBindingAction extends DockingKeyBindingAction {
|
||||||
|
|
||||||
ReservedKeyBindingAction(DockingWindowManager winMgr, DockingActionIf action,
|
ReservedKeyBindingAction(DockingTool tool, DockingActionIf action, KeyStroke keyStroke) {
|
||||||
KeyStroke keyStroke) {
|
super(tool, action, keyStroke);
|
||||||
super(winMgr, action, keyStroke);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isReservedKeybindingPrecedence() {
|
public boolean isReservedKeybindingPrecedence() {
|
||||||
return true;
|
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 javax.swing.*;
|
||||||
|
|
||||||
|
import org.apache.commons.collections4.map.LazyMap;
|
||||||
import org.apache.logging.log4j.LogManager;
|
import org.apache.logging.log4j.LogManager;
|
||||||
import org.apache.logging.log4j.Logger;
|
import org.apache.logging.log4j.Logger;
|
||||||
import org.jdom.*;
|
import org.jdom.*;
|
||||||
|
@ -344,15 +345,21 @@ public class KeyBindingUtils {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A utility method to get all key binding actions. This method will remove duplicate
|
* A utility method to get all key binding actions. This method will
|
||||||
* actions and will only return actions that support {@link KeyBindingType key bindings}.
|
* 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
|
* @param tool the tool containing the actions
|
||||||
* @return the actions mapped by their full name (e.g., 'Name (OwnerName)')
|
* @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();
|
Set<DockingActionIf> actions = tool.getAllActions();
|
||||||
for (DockingActionIf action : actions) {
|
for (DockingActionIf action : actions) {
|
||||||
if (isIgnored(action)) {
|
if (isIgnored(action)) {
|
||||||
|
@ -362,10 +369,10 @@ public class KeyBindingUtils {
|
||||||
continue;
|
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) {
|
private static boolean isIgnored(DockingActionIf action) {
|
||||||
// a shared keybinding implies that this action should not be in
|
// 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
|
// 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) {
|
private static KeyStroke getKeyStroke(KeyBindingData data) {
|
||||||
|
|
|
@ -33,13 +33,14 @@ import docking.action.*;
|
||||||
import docking.tool.util.DockingToolConstants;
|
import docking.tool.util.DockingToolConstants;
|
||||||
import ghidra.framework.options.*;
|
import ghidra.framework.options.*;
|
||||||
import ghidra.util.ReservedKeyBindings;
|
import ghidra.util.ReservedKeyBindings;
|
||||||
|
import ghidra.util.SystemUtilities;
|
||||||
import ghidra.util.exception.AssertException;
|
import ghidra.util.exception.AssertException;
|
||||||
import util.CollectionUtils;
|
import util.CollectionUtils;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An class to manage actions registered with the tool
|
* An class to manage actions registered with the tool
|
||||||
*/
|
*/
|
||||||
public class ToolActions implements PropertyChangeListener {
|
public class ToolActions implements DockingToolActions, PropertyChangeListener {
|
||||||
|
|
||||||
private ActionToGuiHelper actionGuiHelper;
|
private ActionToGuiHelper actionGuiHelper;
|
||||||
|
|
||||||
|
@ -62,25 +63,38 @@ public class ToolActions implements PropertyChangeListener {
|
||||||
* Construct an ActionManager
|
* Construct an ActionManager
|
||||||
*
|
*
|
||||||
* @param tool tool using this ActionManager
|
* @param tool tool using this ActionManager
|
||||||
* @param windowManager manager of the "Docking" arrangement of a set of components
|
* @param actionToGuiHelper the class that takes actions and maps them to GUI widgets
|
||||||
* and actions in the tool
|
|
||||||
*/
|
*/
|
||||||
public ToolActions(DockingTool tool, DockingWindowManager windowManager) {
|
public ToolActions(DockingTool tool, ActionToGuiHelper actionToGuiHelper) {
|
||||||
this.dockingTool = tool;
|
this.dockingTool = tool;
|
||||||
this.actionGuiHelper = new ActionToGuiHelper(windowManager);
|
this.actionGuiHelper = actionToGuiHelper;
|
||||||
this.keyBindingsManager = new KeyBindingsManager(windowManager);
|
this.keyBindingsManager = new KeyBindingsManager(tool);
|
||||||
this.keyBindingOptions = tool.getOptions(DockingToolConstants.KEY_BINDINGS);
|
this.keyBindingOptions = tool.getOptions(DockingToolConstants.KEY_BINDINGS);
|
||||||
|
|
||||||
|
createReservedKeyBindings();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void createReservedKeyBindings() {
|
||||||
KeyBindingAction keyBindingAction = new KeyBindingAction(this);
|
KeyBindingAction keyBindingAction = new KeyBindingAction(this);
|
||||||
keyBindingsManager.addReservedAction(keyBindingAction,
|
keyBindingsManager.addReservedAction(keyBindingAction,
|
||||||
ReservedKeyBindings.UPDATE_KEY_BINDINGS_KEY);
|
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() {
|
public void dispose() {
|
||||||
actionsByNameByOwner.clear();
|
actionsByNameByOwner.clear();
|
||||||
sharedActionMap.clear();
|
sharedActionMap.clear();
|
||||||
|
keyBindingsManager.dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void addActionToMap(DockingActionIf action) {
|
private void addActionToMap(DockingActionIf action) {
|
||||||
|
@ -95,12 +109,14 @@ public class ToolActions implements PropertyChangeListener {
|
||||||
* @param provider provider associated with the action
|
* @param provider provider associated with the action
|
||||||
* @param action local action to the provider
|
* @param action local action to the provider
|
||||||
*/
|
*/
|
||||||
|
@Override
|
||||||
public synchronized void addLocalAction(ComponentProvider provider, DockingActionIf action) {
|
public synchronized void addLocalAction(ComponentProvider provider, DockingActionIf action) {
|
||||||
checkForAlreadyAddedAction(provider, action);
|
checkForAlreadyAddedAction(provider, action);
|
||||||
|
|
||||||
action.addPropertyChangeListener(this);
|
action.addPropertyChangeListener(this);
|
||||||
addActionToMap(action);
|
addActionToMap(action);
|
||||||
setKeyBindingOption(action);
|
setKeyBindingOption(action);
|
||||||
|
keyBindingsManager.addAction(action, provider);
|
||||||
actionGuiHelper.addLocalAction(provider, action);
|
actionGuiHelper.addLocalAction(provider, action);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -108,10 +124,14 @@ public class ToolActions implements PropertyChangeListener {
|
||||||
* Adds the action to the tool.
|
* Adds the action to the tool.
|
||||||
* @param action the action to be added.
|
* @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);
|
action.addPropertyChangeListener(this);
|
||||||
addActionToMap(action);
|
addActionToMap(action);
|
||||||
setKeyBindingOption(action);
|
setKeyBindingOption(action);
|
||||||
|
keyBindingsManager.addAction(action, null);
|
||||||
actionGuiHelper.addToolAction(action);
|
actionGuiHelper.addToolAction(action);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -158,17 +178,15 @@ public class ToolActions implements PropertyChangeListener {
|
||||||
* Removes the given action from the tool
|
* Removes the given action from the tool
|
||||||
* @param action the action to be removed.
|
* @param action the action to be removed.
|
||||||
*/
|
*/
|
||||||
public synchronized void removeToolAction(DockingActionIf action) {
|
@Override
|
||||||
|
public synchronized void removeGlobalAction(DockingActionIf action) {
|
||||||
action.removePropertyChangeListener(this);
|
action.removePropertyChangeListener(this);
|
||||||
removeAction(action);
|
removeAction(action);
|
||||||
actionGuiHelper.removeToolAction(action);
|
actionGuiHelper.removeToolAction(action);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
@Override
|
||||||
* Remove all actions that have the given owner.
|
public synchronized void removeActions(String owner) {
|
||||||
* @param owner owner of the actions to remove
|
|
||||||
*/
|
|
||||||
public synchronized void removeToolActions(String owner) {
|
|
||||||
|
|
||||||
// remove from the outer map first, to prevent concurrent modification exceptions
|
// remove from the outer map first, to prevent concurrent modification exceptions
|
||||||
Map<String, Set<DockingActionIf>> toCleanup = actionsByNameByOwner.remove(owner);
|
Map<String, Set<DockingActionIf>> toCleanup = actionsByNameByOwner.remove(owner);
|
||||||
|
@ -180,15 +198,17 @@ public class ToolActions implements PropertyChangeListener {
|
||||||
toCleanup.values()
|
toCleanup.values()
|
||||||
.stream()
|
.stream()
|
||||||
.flatMap(set -> set.stream())
|
.flatMap(set -> set.stream())
|
||||||
.forEach(action -> removeToolAction(action))
|
.forEach(action -> removeGlobalAction(action))
|
||||||
;
|
;
|
||||||
//@formatter:on
|
//@formatter:on
|
||||||
}
|
}
|
||||||
|
|
||||||
private void checkForAlreadyAddedAction(ComponentProvider provider, DockingActionIf action) {
|
private void checkForAlreadyAddedAction(ComponentProvider provider, DockingActionIf action) {
|
||||||
if (getActionStorage(action).contains(action)) {
|
if (getActionStorage(action).contains(action)) {
|
||||||
throw new AssertException("Cannot add the same action more than once. Provider " +
|
String providerString =
|
||||||
provider.getName() + " - action: " + action.getFullName());
|
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
|
* @return array of actions; zero length array is returned if no
|
||||||
* action exists with the given name
|
* action exists with the given name
|
||||||
*/
|
*/
|
||||||
|
@Override
|
||||||
public synchronized Set<DockingActionIf> getActions(String owner) {
|
public synchronized Set<DockingActionIf> getActions(String owner) {
|
||||||
|
|
||||||
Set<DockingActionIf> result = new HashSet<>();
|
Set<DockingActionIf> result = new HashSet<>();
|
||||||
|
@ -215,8 +236,10 @@ public class ToolActions implements PropertyChangeListener {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get a set of all actions in the tool
|
* 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() {
|
public synchronized Set<DockingActionIf> getAllActions() {
|
||||||
|
|
||||||
Set<DockingActionIf> result = new HashSet<>();
|
Set<DockingActionIf> result = new HashSet<>();
|
||||||
|
@ -278,23 +301,24 @@ public class ToolActions implements PropertyChangeListener {
|
||||||
* @param provider provider associated with the action
|
* @param provider provider associated with the action
|
||||||
* @param action local action to the provider
|
* @param action local action to the provider
|
||||||
*/
|
*/
|
||||||
public synchronized void removeProviderAction(ComponentProvider provider,
|
@Override
|
||||||
DockingActionIf action) {
|
public synchronized void removeLocalAction(ComponentProvider provider, DockingActionIf action) {
|
||||||
action.removePropertyChangeListener(this);
|
action.removePropertyChangeListener(this);
|
||||||
removeAction(action);
|
removeAction(action);
|
||||||
|
keyBindingsManager.removeAction(action);
|
||||||
actionGuiHelper.removeProviderAction(provider, action);
|
actionGuiHelper.removeProviderAction(provider, action);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
@Override
|
||||||
* Get the actions for the given provider and remove them from the action map
|
public synchronized void removeActions(ComponentProvider provider) {
|
||||||
* @param provider provider whose actions are to be removed
|
|
||||||
*/
|
|
||||||
public synchronized void removeComponentActions(ComponentProvider provider) {
|
|
||||||
Iterator<DockingActionIf> it = actionGuiHelper.getComponentActions(provider);
|
Iterator<DockingActionIf> it = actionGuiHelper.getComponentActions(provider);
|
||||||
|
|
||||||
|
// copy the data to avoid concurrent modification exceptions
|
||||||
Set<DockingActionIf> set = CollectionUtils.asSet(it);
|
Set<DockingActionIf> set = CollectionUtils.asSet(it);
|
||||||
for (DockingActionIf action : set) {
|
for (DockingActionIf action : set) {
|
||||||
removeProviderAction(provider, action);
|
removeLocalAction(provider, action);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void removeAction(DockingActionIf action) {
|
private void removeAction(DockingActionIf action) {
|
||||||
|
@ -346,12 +370,12 @@ public class ToolActions implements PropertyChangeListener {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
DockingActionIf getSharedStubKeyBindingAction(String name) {
|
public Action getAction(KeyStroke ks) {
|
||||||
return sharedActionMap.get(name);
|
return keyBindingsManager.getDockingKeyAction(ks);
|
||||||
}
|
}
|
||||||
|
|
||||||
Action getAction(KeyStroke ks) {
|
DockingActionIf getSharedStubKeyBindingAction(String name) {
|
||||||
return keyBindingsManager.getDockingKeyAction(ks);
|
return sharedActionMap.get(name);
|
||||||
}
|
}
|
||||||
|
|
||||||
// triggered by a user-initiated action
|
// triggered by a user-initiated action
|
||||||
|
|
|
@ -35,9 +35,11 @@ import docking.tool.util.DockingToolConstants;
|
||||||
import ghidra.framework.options.ToolOptions;
|
import ghidra.framework.options.ToolOptions;
|
||||||
import ghidra.util.Msg;
|
import ghidra.util.Msg;
|
||||||
import ghidra.util.SpyErrorLogger;
|
import ghidra.util.SpyErrorLogger;
|
||||||
|
import ghidra.util.exception.AssertException;
|
||||||
|
|
||||||
public class SharedKeyBindingDockingActionTest extends AbstractDockingTest {
|
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_NAME = "Shared Action Name";
|
||||||
private static final String SHARED_OWNER = SharedStubKeyBindingAction.SHARED_OWNER;
|
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);
|
TestAction action1 = new TestAction(OWNER_1, DEFAULT_KS_1);
|
||||||
|
|
||||||
tool.addAction(action1);
|
tool.addAction(action1);
|
||||||
|
|
||||||
|
try {
|
||||||
tool.addAction(action1);
|
tool.addAction(action1);
|
||||||
|
fail("Did not get expected exception");
|
||||||
|
}
|
||||||
|
catch (AssertException e) {
|
||||||
|
// expected
|
||||||
|
}
|
||||||
|
|
||||||
assertOnlyOneVersionOfActionInTool(action1);
|
assertOnlyOneVersionOfActionInTool(action1);
|
||||||
|
|
||||||
|
@ -294,7 +303,7 @@ public class SharedKeyBindingDockingActionTest extends AbstractDockingTest {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testNonSharedKeyBinding_SameActionAddedTwice() {
|
public void testSharedKeyBinding_SameActionAddedTwice() {
|
||||||
//
|
//
|
||||||
// We support adding the same action twice. (This can happen when a transient component
|
// 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
|
// provider is repeatedly shown, such as a search results provider.) Make sure we get
|
||||||
|
@ -323,7 +332,7 @@ public class SharedKeyBindingDockingActionTest extends AbstractDockingTest {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testNonSharedKeyBinding_DifferentActionsWithSameFullName() {
|
public void testSharedKeyBinding_DifferentActionsWithSameFullName() {
|
||||||
//
|
//
|
||||||
// We support adding the same action twice. (This can happen when a transient component
|
// 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
|
// 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);
|
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
|
// Private Methods
|
||||||
//==================================================================================================
|
//==================================================================================================
|
||||||
|
@ -361,7 +400,7 @@ public class SharedKeyBindingDockingActionTest extends AbstractDockingTest {
|
||||||
assertNotNull("Shared action stub is not in the tool", action);
|
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
|
// this method will fail if more than one action is registered
|
||||||
DockingActionIf registeredAction = getAction(tool, action.getOwner(), action.getName());
|
DockingActionIf registeredAction = getAction(tool, action.getOwner(), action.getName());
|
||||||
|
@ -369,7 +408,7 @@ public class SharedKeyBindingDockingActionTest extends AbstractDockingTest {
|
||||||
registeredAction);
|
registeredAction);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void assertActionInTool(TestAction action) {
|
private void assertActionInTool(DockingActionIf action) {
|
||||||
|
|
||||||
Set<DockingActionIf> actions = getActionsByName(tool, action.getName());
|
Set<DockingActionIf> actions = getActionsByName(tool, action.getName());
|
||||||
for (DockingActionIf toolAction : actions) {
|
for (DockingActionIf toolAction : actions) {
|
||||||
|
@ -381,7 +420,7 @@ public class SharedKeyBindingDockingActionTest extends AbstractDockingTest {
|
||||||
fail("Action is not in the tool: " + action);
|
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());
|
Set<DockingActionIf> actions = getActionsByName(tool, action.getName());
|
||||||
for (DockingActionIf toolAction : actions) {
|
for (DockingActionIf toolAction : actions) {
|
||||||
assertNotSame(toolAction, action);
|
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 {
|
private class DummyComponentProvider extends ComponentProvider {
|
||||||
public DummyComponentProvider() {
|
public DummyComponentProvider() {
|
||||||
super(tool, "Dummy", "Dummy Owner");
|
super(tool, "Dummy", "Dummy Owner");
|
||||||
|
|
|
@ -35,9 +35,9 @@ public class FakeDockingTool extends AbstractDockingTool {
|
||||||
|
|
||||||
DockWinListener listener = new DummyListener();
|
DockWinListener listener = new DummyListener();
|
||||||
List<Image> windowIcons = ApplicationInformationDisplayFactory.getWindowIcons();
|
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*/);
|
true /*isDockable*/, true /*hasStatus*/, null /*DropTargetFactory*/);
|
||||||
toolActions = new ToolActions(this, winMgr);
|
toolActions = new ToolActions(this, new ActionToGuiHelper(winMgr));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -71,7 +71,5 @@ public class FakeDockingTool extends AbstractDockingTool {
|
||||||
public List<DockingActionIf> getPopupActions(ActionContext context) {
|
public List<DockingActionIf> getPopupActions(ActionContext context) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -150,16 +150,16 @@ public abstract class PluginTool extends AbstractDockingTool
|
||||||
this.projectManager = projectManager;
|
this.projectManager = projectManager;
|
||||||
this.toolServices = toolServices;
|
this.toolServices = toolServices;
|
||||||
propertyChangeMgr = new PropertyChangeSupport(this);
|
propertyChangeMgr = new PropertyChangeSupport(this);
|
||||||
winMgr = createDockingWindowManager(isDockable, hasStatus, isModal);
|
|
||||||
taskMgr = new ToolTaskManager(this);
|
|
||||||
optionsMgr = new OptionsManager(this);
|
optionsMgr = new OptionsManager(this);
|
||||||
|
winMgr = createDockingWindowManager(isDockable, hasStatus, isModal);
|
||||||
|
toolActions = new ToolActions(this, new ActionToGuiHelper(winMgr));
|
||||||
|
taskMgr = new ToolTaskManager(this);
|
||||||
setToolOptionsHelpLocation();
|
setToolOptionsHelpLocation();
|
||||||
winMgr.addStatusItem(taskMgr.getMonitorComponent(), false, true);
|
winMgr.addStatusItem(taskMgr.getMonitorComponent(), false, true);
|
||||||
winMgr.removeStatusItem(taskMgr.getMonitorComponent());
|
winMgr.removeStatusItem(taskMgr.getMonitorComponent());
|
||||||
eventMgr = new EventManager(this);
|
eventMgr = new EventManager(this);
|
||||||
serviceMgr = new ServiceManager();
|
serviceMgr = new ServiceManager();
|
||||||
installServices();
|
installServices();
|
||||||
toolActions = new ToolActions(this, winMgr);
|
|
||||||
pluginMgr = new PluginManager(this, serviceMgr);
|
pluginMgr = new PluginManager(this, serviceMgr);
|
||||||
dialogMgr = new DialogManager(this);
|
dialogMgr = new DialogManager(this);
|
||||||
initActions();
|
initActions();
|
||||||
|
@ -190,8 +190,8 @@ public abstract class PluginTool extends AbstractDockingTool
|
||||||
boolean isModal) {
|
boolean isModal) {
|
||||||
|
|
||||||
List<Image> windowIcons = ApplicationInformationDisplayFactory.getWindowIcons();
|
List<Image> windowIcons = ApplicationInformationDisplayFactory.getWindowIcons();
|
||||||
DockingWindowManager newManager = new DockingWindowManager("EMPTY", windowIcons, this,
|
DockingWindowManager newManager =
|
||||||
isModal, isDockable, hasStatus, null);
|
new DockingWindowManager(this, windowIcons, this, isModal, isDockable, hasStatus, null);
|
||||||
return newManager;
|
return newManager;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1322,8 +1322,8 @@ public abstract class PluginTool extends AbstractDockingTool
|
||||||
}
|
}
|
||||||
|
|
||||||
void removeAll(String owner) {
|
void removeAll(String owner) {
|
||||||
toolActions.removeToolActions(owner);
|
toolActions.removeActions(owner);
|
||||||
winMgr.removeAll(owner);
|
winMgr.ownerRemoved(owner);
|
||||||
}
|
}
|
||||||
|
|
||||||
void registerEventProduced(Class<? extends PluginEvent> eventClass) {
|
void registerEventProduced(Class<? extends PluginEvent> eventClass) {
|
||||||
|
@ -1468,6 +1468,7 @@ public abstract class PluginTool extends AbstractDockingTool
|
||||||
return winMgr.getActiveWindow();
|
return winMgr.getActiveWindow();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public ComponentProvider getActiveComponentProvider() {
|
public ComponentProvider getActiveComponentProvider() {
|
||||||
return winMgr.getActiveComponentProvider();
|
return winMgr.getActiveComponentProvider();
|
||||||
}
|
}
|
||||||
|
|
|
@ -67,7 +67,7 @@ public class KeyBindingsPanel extends JPanel {
|
||||||
private ListSelectionModel selectionModel;
|
private ListSelectionModel selectionModel;
|
||||||
private Options options;
|
private Options options;
|
||||||
|
|
||||||
private Map<String, DockingActionIf> actionsByFullName;
|
private Map<String, List<DockingActionIf>> actionsByFullName;
|
||||||
private Map<String, List<String>> actionNamesByKeyStroke;
|
private Map<String, List<String>> actionNamesByKeyStroke;
|
||||||
private Map<String, KeyStroke> keyStrokesByFullName;
|
private Map<String, KeyStroke> keyStrokesByFullName;
|
||||||
private Map<String, KeyStroke> originalValues; // to know what has been changed
|
private Map<String, KeyStroke> originalValues; // to know what has been changed
|
||||||
|
@ -114,11 +114,11 @@ public class KeyBindingsPanel extends JPanel {
|
||||||
changesMade(false);
|
changesMade(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean updateOptions(String fullActionName, KeyStroke currentKeyStroke,
|
private void updateOptions(String fullActionName, KeyStroke currentKeyStroke,
|
||||||
KeyStroke newKeyStroke) {
|
KeyStroke newKeyStroke) {
|
||||||
if ((currentKeyStroke != null && currentKeyStroke.equals(newKeyStroke)) ||
|
|
||||||
(currentKeyStroke == null && newKeyStroke == null)) {
|
if (Objects.equals(currentKeyStroke, newKeyStroke)) {
|
||||||
return false;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (newKeyStroke != null) {
|
if (newKeyStroke != null) {
|
||||||
|
@ -130,19 +130,12 @@ public class KeyBindingsPanel extends JPanel {
|
||||||
originalValues.put(fullActionName, newKeyStroke);
|
originalValues.put(fullActionName, newKeyStroke);
|
||||||
keyStrokesByFullName.put(fullActionName, newKeyStroke);
|
keyStrokesByFullName.put(fullActionName, newKeyStroke);
|
||||||
|
|
||||||
Set<DockingActionIf> actions = tool.getAllActions();
|
List<DockingActionIf> actions = actionsByFullName.get(fullActionName);
|
||||||
for (DockingActionIf action : actions) {
|
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() {
|
public void cancel() {
|
||||||
Iterator<String> iter = originalValues.keySet().iterator();
|
Iterator<String> iter = originalValues.keySet().iterator();
|
||||||
while (iter.hasNext()) {
|
while (iter.hasNext()) {
|
||||||
|
@ -173,10 +166,12 @@ public class KeyBindingsPanel extends JPanel {
|
||||||
String longestName = "";
|
String longestName = "";
|
||||||
|
|
||||||
actionsByFullName = KeyBindingUtils.getAllActionsByFullName(tool);
|
actionsByFullName = KeyBindingUtils.getAllActionsByFullName(tool);
|
||||||
Set<Entry<String, DockingActionIf>> entries = actionsByFullName.entrySet();
|
Set<Entry<String, List<DockingActionIf>>> entries = actionsByFullName.entrySet();
|
||||||
for (Entry<String, DockingActionIf> entry : entries) {
|
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);
|
tableActions.add(action);
|
||||||
|
|
||||||
String actionName = entry.getKey();
|
String actionName = entry.getKey();
|
||||||
|
@ -413,11 +408,13 @@ public class KeyBindingsPanel extends JPanel {
|
||||||
Iterator<String> iter = keyStrokesByFullName.keySet().iterator();
|
Iterator<String> iter = keyStrokesByFullName.keySet().iterator();
|
||||||
while (iter.hasNext()) {
|
while (iter.hasNext()) {
|
||||||
String actionName = iter.next();
|
String actionName = iter.next();
|
||||||
DockingActionIf action = actionsByFullName.get(actionName);
|
List<DockingActionIf> actions = actionsByFullName.get(actionName);
|
||||||
if (action == null) {
|
if (actions.isEmpty()) {
|
||||||
throw new AssertException("No actions defined for " + actionName);
|
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);
|
KeyStroke currentKeyStroke = keyStrokesByFullName.get(actionName);
|
||||||
KeyBindingData defaultBinding = action.getDefaultKeyBindingData();
|
KeyBindingData defaultBinding = action.getDefaultKeyBindingData();
|
||||||
KeyStroke newKeyStroke =
|
KeyStroke newKeyStroke =
|
||||||
|
@ -669,11 +666,14 @@ public class KeyBindingsPanel extends JPanel {
|
||||||
}
|
}
|
||||||
|
|
||||||
ksField.setText(ksName);
|
ksField.setText(ksName);
|
||||||
|
|
||||||
// make sure the label gets enough space
|
// make sure the label gets enough space
|
||||||
statusLabel.setPreferredSize(
|
statusLabel.setPreferredSize(
|
||||||
new Dimension(statusLabel.getPreferredSize().width, STATUS_LABEL_HEIGHT));
|
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();
|
String description = action.getDescription();
|
||||||
if (description == null || description.trim().isEmpty()) {
|
if (description == null || description.trim().isEmpty()) {
|
||||||
description = action.getName();
|
description = action.getName();
|
||||||
|
|
|
@ -83,7 +83,7 @@ public class GhidraTool extends PluginTool {
|
||||||
@Override
|
@Override
|
||||||
protected DockingWindowManager createDockingWindowManager(boolean isDockable, boolean hasStatus,
|
protected DockingWindowManager createDockingWindowManager(boolean isDockable, boolean hasStatus,
|
||||||
boolean isModal) {
|
boolean isModal) {
|
||||||
return new DockingWindowManager("EMPTY", null, this, isModal, isDockable, hasStatus,
|
return new DockingWindowManager(this, null, this, isModal, isDockable, hasStatus,
|
||||||
new OpenFileDropHandlerFactory(this));
|
new OpenFileDropHandlerFactory(this));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue