mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2025-10-03 17:59:46 +02:00
GT-2925-2 - Key Bindings - Support Window Menu Provider Key Bindings -
test and review fixes
This commit is contained in:
parent
21db705ecc
commit
dabdc38ea9
11 changed files with 90 additions and 21 deletions
|
@ -43,7 +43,7 @@ public class ComponentProviderActionsTest extends AbstractGhidraHeadedIntegratio
|
||||||
private final Icon ICON = ResourceManager.loadImage("images/refresh.png");
|
private final Icon ICON = ResourceManager.loadImage("images/refresh.png");
|
||||||
private static final String PROVIDER_NAME = "Test Action Provider";
|
private static final String PROVIDER_NAME = "Test Action Provider";
|
||||||
private static final KeyStroke CONTROL_T =
|
private static final KeyStroke CONTROL_T =
|
||||||
KeyStroke.getKeyStroke(Character.valueOf('t'), DockingUtils.CONTROL_KEY_MODIFIER_MASK);
|
KeyStroke.getKeyStroke(Character.valueOf('T'), DockingUtils.CONTROL_KEY_MODIFIER_MASK);
|
||||||
|
|
||||||
private TestEnv env;
|
private TestEnv env;
|
||||||
private PluginTool tool;
|
private PluginTool tool;
|
||||||
|
@ -160,6 +160,19 @@ public class ComponentProviderActionsTest extends AbstractGhidraHeadedIntegratio
|
||||||
assertMenuItemHasKeyStroke(newKs);
|
assertMenuItemHasKeyStroke(newKs);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testSetKeyBinding_ViaDialog_FromWindowMenu_ThenFireKeyEventToShowProvider() {
|
||||||
|
|
||||||
|
showProvider();
|
||||||
|
|
||||||
|
KeyStroke newKs = CONTROL_T;
|
||||||
|
setKeyBindingViaF4Dialog_FromWindowsMenu(newKs);
|
||||||
|
|
||||||
|
hideProvider();
|
||||||
|
pressKey(CONTROL_T);
|
||||||
|
assertProviderIsActive();
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testSetKeyBinding_ViaDialog_FromWindowMenu_ToAlreadyBoundAction() {
|
public void testSetKeyBinding_ViaDialog_FromWindowMenu_ToAlreadyBoundAction() {
|
||||||
|
|
||||||
|
@ -326,6 +339,11 @@ public class ComponentProviderActionsTest extends AbstractGhidraHeadedIntegratio
|
||||||
waitForSwing();
|
waitForSwing();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void hideProvider() {
|
||||||
|
tool.showComponentProvider(provider, false);
|
||||||
|
waitForSwing();
|
||||||
|
}
|
||||||
|
|
||||||
private void setDefaultKeyBinding(KeyStroke defaultKs) {
|
private void setDefaultKeyBinding(KeyStroke defaultKs) {
|
||||||
runSwing(() -> provider.setKeyBinding(new KeyBindingData(defaultKs)));
|
runSwing(() -> provider.setKeyBinding(new KeyBindingData(defaultKs)));
|
||||||
}
|
}
|
||||||
|
@ -341,6 +359,14 @@ public class ComponentProviderActionsTest extends AbstractGhidraHeadedIntegratio
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void pressKey(KeyStroke ks) {
|
||||||
|
int modifiers = ks.getModifiers();
|
||||||
|
char keyChar = ks.getKeyChar();
|
||||||
|
int keyCode = ks.getKeyCode();
|
||||||
|
JFrame toolFrame = tool.getToolFrame();
|
||||||
|
triggerKey(toolFrame, modifiers, keyCode, keyChar);
|
||||||
|
}
|
||||||
|
|
||||||
private DockingActionIf getShowProviderAction() {
|
private DockingActionIf getShowProviderAction() {
|
||||||
|
|
||||||
DockingActionIf showProviderAction =
|
DockingActionIf showProviderAction =
|
||||||
|
@ -389,6 +415,11 @@ public class ComponentProviderActionsTest extends AbstractGhidraHeadedIntegratio
|
||||||
waitForSwing();
|
waitForSwing();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void assertProviderIsActive() {
|
||||||
|
assertTrue("The test provider is not showing and focused",
|
||||||
|
runSwing(() -> tool.isActive(provider)));
|
||||||
|
}
|
||||||
|
|
||||||
private void assertNoToolbarAction() {
|
private void assertNoToolbarAction() {
|
||||||
assertNull("No toolbar action found for provider", getToolbarShowProviderAction());
|
assertNull("No toolbar action found for provider", getToolbarShowProviderAction());
|
||||||
}
|
}
|
||||||
|
|
|
@ -29,7 +29,6 @@ import docking.action.DockingActionIf;
|
||||||
import ghidra.program.database.ProgramBuilder;
|
import ghidra.program.database.ProgramBuilder;
|
||||||
import ghidra.program.model.listing.Program;
|
import ghidra.program.model.listing.Program;
|
||||||
import ghidra.test.AbstractProgramBasedTest;
|
import ghidra.test.AbstractProgramBasedTest;
|
||||||
import ghidra.util.Msg;
|
|
||||||
import ghidra.util.datastruct.WeakSet;
|
import ghidra.util.datastruct.WeakSet;
|
||||||
|
|
||||||
public class ProviderNavigationPluginTest extends AbstractProgramBasedTest {
|
public class ProviderNavigationPluginTest extends AbstractProgramBasedTest {
|
||||||
|
@ -165,9 +164,6 @@ public class ProviderNavigationPluginTest extends AbstractProgramBasedTest {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void accept(ComponentProvider c) {
|
public void accept(ComponentProvider c) {
|
||||||
|
|
||||||
Msg.out("Spy - activated: " + c);
|
|
||||||
|
|
||||||
lastActivated = c;
|
lastActivated = c;
|
||||||
forceActivate(c);
|
forceActivate(c);
|
||||||
}
|
}
|
||||||
|
|
|
@ -80,7 +80,7 @@ public class ActionDialog extends DialogComponentProvider {
|
||||||
for (int i = 0; i < list.size(); i++) {
|
for (int i = 0; i < list.size(); i++) {
|
||||||
ExecutableKeyActionAdapter actionProxy = list.get(i);
|
ExecutableKeyActionAdapter actionProxy = list.get(i);
|
||||||
DockingActionIf action = actionProxy.getAction();
|
DockingActionIf action = actionProxy.getAction();
|
||||||
listModel.addElement(action.getName());
|
listModel.addElement(action.getName() + " (" + action.getOwnerDescription() + ")");
|
||||||
}
|
}
|
||||||
actionList.setSelectedIndex(0);
|
actionList.setSelectedIndex(0);
|
||||||
}
|
}
|
||||||
|
@ -144,7 +144,7 @@ public class ActionDialog extends DialogComponentProvider {
|
||||||
@Override
|
@Override
|
||||||
public void mouseClicked(MouseEvent e) {
|
public void mouseClicked(MouseEvent e) {
|
||||||
|
|
||||||
if (e.getModifiers() != InputEvent.BUTTON1_MASK) {
|
if (e.getModifiersEx() != InputEvent.BUTTON1_DOWN_MASK) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
int clickCount = e.getClickCount();
|
int clickCount = e.getClickCount();
|
||||||
|
|
|
@ -36,8 +36,6 @@ public class ShowAllComponentsAction extends ShowComponentAction {
|
||||||
winMgr.doSetMenuGroup(new String[] { MENU_WINDOW, subMenuName }, "Permanent");
|
winMgr.doSetMenuGroup(new String[] { MENU_WINDOW, subMenuName }, "Permanent");
|
||||||
|
|
||||||
setHelpLocation(new HelpLocation("DockingWindows", "Windows_Menu"));
|
setHelpLocation(new HelpLocation("DockingWindows", "Windows_Menu"));
|
||||||
|
|
||||||
this.winMgr = winMgr;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -19,6 +19,7 @@ import javax.swing.Icon;
|
||||||
import javax.swing.ImageIcon;
|
import javax.swing.ImageIcon;
|
||||||
|
|
||||||
import docking.action.*;
|
import docking.action.*;
|
||||||
|
import docking.actions.AutoGeneratedDockingAction;
|
||||||
import ghidra.util.HelpLocation;
|
import ghidra.util.HelpLocation;
|
||||||
import resources.ResourceManager;
|
import resources.ResourceManager;
|
||||||
|
|
||||||
|
@ -26,7 +27,8 @@ import resources.ResourceManager;
|
||||||
* Action for showing components. If the component is hidden it will be made visible.
|
* Action for showing components. If the component is hidden it will be made visible.
|
||||||
* If it is tabbed, it will become the top tab. In all cases it will receive focus.
|
* If it is tabbed, it will become the top tab. In all cases it will receive focus.
|
||||||
*/
|
*/
|
||||||
class ShowComponentAction extends DockingAction implements Comparable<ShowComponentAction> {
|
class ShowComponentAction extends DockingAction
|
||||||
|
implements AutoGeneratedDockingAction, Comparable<ShowComponentAction> {
|
||||||
private static final int MAX_LENGTH = 40;
|
private static final int MAX_LENGTH = 40;
|
||||||
|
|
||||||
protected static final ImageIcon EMPTY_ICON =
|
protected static final ImageIcon EMPTY_ICON =
|
||||||
|
@ -47,6 +49,7 @@ class ShowComponentAction extends DockingAction implements Comparable<ShowCompon
|
||||||
|
|
||||||
protected ShowComponentAction(DockingWindowManager winMgr, String name, String subMenuName) {
|
protected ShowComponentAction(DockingWindowManager winMgr, String name, String subMenuName) {
|
||||||
super(truncateTitleAsNeeded(name), DockingWindowManager.DOCKING_WINDOWS_OWNER);
|
super(truncateTitleAsNeeded(name), DockingWindowManager.DOCKING_WINDOWS_OWNER);
|
||||||
|
this.winMgr = winMgr;
|
||||||
}
|
}
|
||||||
|
|
||||||
ShowComponentAction(DockingWindowManager winMgr, ComponentPlaceholder placeholder,
|
ShowComponentAction(DockingWindowManager winMgr, ComponentPlaceholder placeholder,
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
/* ###
|
/* ###
|
||||||
* IP: GHIDRA
|
* IP: GHIDRA
|
||||||
* REVIEWED: YES
|
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
@ -16,15 +15,16 @@
|
||||||
*/
|
*/
|
||||||
package docking;
|
package docking;
|
||||||
|
|
||||||
import ghidra.util.HelpLocation;
|
|
||||||
|
|
||||||
import javax.swing.Icon;
|
import javax.swing.Icon;
|
||||||
|
|
||||||
import resources.ResourceManager;
|
|
||||||
import docking.action.DockingAction;
|
import docking.action.DockingAction;
|
||||||
import docking.action.MenuData;
|
import docking.action.MenuData;
|
||||||
|
import docking.actions.AutoGeneratedDockingAction;
|
||||||
|
import ghidra.util.HelpLocation;
|
||||||
|
import resources.ResourceManager;
|
||||||
|
|
||||||
class ShowWindowAction extends DockingAction implements Comparable<ShowWindowAction> {
|
class ShowWindowAction extends DockingAction
|
||||||
|
implements AutoGeneratedDockingAction, Comparable<ShowWindowAction> {
|
||||||
|
|
||||||
private static final Icon ICON = ResourceManager.loadImage("images/application_xp.png");
|
private static final Icon ICON = ResourceManager.loadImage("images/application_xp.png");
|
||||||
private static final String MENU_WINDOW = "&" + DockingWindowManager.COMPONENT_MENU_NAME;
|
private static final String MENU_WINDOW = "&" + DockingWindowManager.COMPONENT_MENU_NAME;
|
||||||
|
|
|
@ -27,10 +27,17 @@ import docking.*;
|
||||||
import ghidra.util.ReservedKeyBindings;
|
import ghidra.util.ReservedKeyBindings;
|
||||||
import ghidra.util.exception.AssertException;
|
import ghidra.util.exception.AssertException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A class that organizes system key bindings by mapping them to assigned {@link DockingActionIf}s.
|
||||||
|
*
|
||||||
|
* <p>This class understands reserved system key bindings. For non-reserved key bindings, this
|
||||||
|
* class knows how to map a single key binding to multiple actions.
|
||||||
|
*/
|
||||||
public class KeyBindingsManager implements PropertyChangeListener {
|
public class KeyBindingsManager implements PropertyChangeListener {
|
||||||
|
|
||||||
protected Map<KeyStroke, DockingKeyBindingAction> dockingKeyMap;
|
// this map exists to update the MultiKeyBindingAction when the key binding changes
|
||||||
protected Map<DockingActionIf, ComponentProvider> actionToProviderMap;
|
private Map<DockingActionIf, ComponentProvider> actionToProviderMap;
|
||||||
|
private Map<KeyStroke, DockingKeyBindingAction> dockingKeyMap;
|
||||||
private DockingTool tool;
|
private DockingTool tool;
|
||||||
|
|
||||||
public KeyBindingsManager(DockingTool tool) {
|
public KeyBindingsManager(DockingTool tool) {
|
||||||
|
|
|
@ -277,7 +277,8 @@ public class MultipleKeyAction extends DockingKeyBindingAction {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return provider.toString() + " - " + action;
|
String providerString = provider == null ? "" : provider.toString() + " - ";
|
||||||
|
return providerString + action;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,24 @@
|
||||||
|
/* ###
|
||||||
|
* 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;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A marker interface to signal that the implementing action is temporary and gets built
|
||||||
|
* automatically by the tool
|
||||||
|
*/
|
||||||
|
public interface AutoGeneratedDockingAction {
|
||||||
|
// marker interface
|
||||||
|
}
|
|
@ -164,13 +164,18 @@ public class ToolActions implements DockingToolActions, PropertyChangeListener {
|
||||||
newStub.addPropertyChangeListener(this);
|
newStub.addPropertyChangeListener(this);
|
||||||
keyBindingOptions.registerOption(newStub.getFullName(), OptionType.KEYSTROKE_TYPE,
|
keyBindingOptions.registerOption(newStub.getFullName(), OptionType.KEYSTROKE_TYPE,
|
||||||
defaultKeyStroke, null, null);
|
defaultKeyStroke, null, null);
|
||||||
|
|
||||||
|
keyBindingsManager.addAction(provider, newStub);
|
||||||
|
|
||||||
return newStub;
|
return newStub;
|
||||||
});
|
});
|
||||||
|
|
||||||
stub.addClientAction(action);
|
stub.addClientAction(action);
|
||||||
|
|
||||||
// note: only put the stub in the manager, not the actual action
|
if (!(action instanceof AutoGeneratedDockingAction)) {
|
||||||
keyBindingsManager.addAction(provider, stub);
|
// Auto-generated actions are temporary and should not receive key events
|
||||||
|
keyBindingsManager.addAction(provider, action);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -55,7 +55,8 @@ public class TestKeyEventDispatcher {
|
||||||
//
|
//
|
||||||
focusProvider.focusOwner = event.getComponent();
|
focusProvider.focusOwner = event.getComponent();
|
||||||
try {
|
try {
|
||||||
return systemDispatcher.dispatchKeyEvent(event);
|
boolean success = systemDispatcher.dispatchKeyEvent(event);
|
||||||
|
return success;
|
||||||
}
|
}
|
||||||
finally {
|
finally {
|
||||||
focusProvider.focusOwner = null;
|
focusProvider.focusOwner = null;
|
||||||
|
@ -105,6 +106,9 @@ public class TestKeyEventDispatcher {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (focusOwner instanceof Window) {
|
||||||
|
return (Window) focusOwner;
|
||||||
|
}
|
||||||
return SwingUtilities.windowForComponent(focusOwner);
|
return SwingUtilities.windowForComponent(focusOwner);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue