mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2025-10-04 18:29:37 +02:00
GP-732 - Added key binding support for showing context menu
This commit is contained in:
parent
98d0cd9034
commit
cffc1787ae
9 changed files with 179 additions and 33 deletions
|
@ -15,7 +15,6 @@
|
||||||
*/
|
*/
|
||||||
package docking;
|
package docking;
|
||||||
|
|
||||||
import java.awt.event.MouseEvent;
|
|
||||||
import java.util.LinkedHashSet;
|
import java.util.LinkedHashSet;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
|
@ -134,7 +133,7 @@ public class ActionToGuiMapper {
|
||||||
return menuGroupMap;
|
return menuGroupMap;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void showPopupMenu(ComponentPlaceholder componentInfo, MouseEvent e) {
|
public void showPopupMenu(ComponentPlaceholder componentInfo, PopupMenuContext popupContext) {
|
||||||
popupActionManager.popupMenu(componentInfo, e);
|
popupActionManager.popupMenu(componentInfo, popupContext);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -67,17 +67,17 @@ public class DockableComponent extends JPanel implements ContainerListener {
|
||||||
@Override
|
@Override
|
||||||
public void mousePressed(MouseEvent e) {
|
public void mousePressed(MouseEvent e) {
|
||||||
componentSelected((Component) e.getSource());
|
componentSelected((Component) e.getSource());
|
||||||
processPopupMouseEvent(e);
|
showContextMenu(e);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void mouseReleased(MouseEvent e) {
|
public void mouseReleased(MouseEvent e) {
|
||||||
processPopupMouseEvent(e);
|
showContextMenu(e);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void mouseClicked(MouseEvent e) {
|
public void mouseClicked(MouseEvent e) {
|
||||||
processPopupMouseEvent(e);
|
showContextMenu(e);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -146,24 +146,27 @@ public class DockableComponent extends JPanel implements ContainerListener {
|
||||||
return focusedComponent;
|
return focusedComponent;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void processPopupMouseEvent(final MouseEvent e) {
|
void showContextMenu(PopupMenuContext popupContext) {
|
||||||
|
actionMgr.showPopupMenu(placeholder, popupContext);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void showContextMenu(MouseEvent e) {
|
||||||
Component component = e.getComponent();
|
Component component = e.getComponent();
|
||||||
if (component == null) {
|
if (component == null) {
|
||||||
return;
|
return; // not sure this can happen
|
||||||
}
|
}
|
||||||
|
|
||||||
// get the bounds to see if the clicked point is over the component
|
// get the bounds to see if the clicked point is over the component
|
||||||
Rectangle bounds = component.getBounds(); // get bounds to get width and height
|
Rectangle bounds = component.getBounds();
|
||||||
|
|
||||||
if (component instanceof JComponent) {
|
if (component instanceof JComponent) {
|
||||||
((JComponent) component).computeVisibleRect(bounds);
|
((JComponent) component).computeVisibleRect(bounds);
|
||||||
}
|
}
|
||||||
|
|
||||||
Point point = e.getPoint();
|
Point point = e.getPoint();
|
||||||
boolean withinBounds = bounds.contains(point);
|
boolean withinBounds = bounds.contains(point);
|
||||||
|
|
||||||
if (e.isPopupTrigger() && withinBounds) {
|
if (e.isPopupTrigger() && withinBounds) {
|
||||||
actionMgr.showPopupMenu(placeholder, e);
|
PopupMenuContext popupContext = new PopupMenuContext(e);
|
||||||
|
actionMgr.showPopupMenu(placeholder, popupContext);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -476,17 +479,11 @@ public class DockableComponent extends JPanel implements ContainerListener {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @see java.awt.event.ContainerListener#componentAdded(java.awt.event.ContainerEvent)
|
|
||||||
*/
|
|
||||||
@Override
|
@Override
|
||||||
public void componentAdded(ContainerEvent e) {
|
public void componentAdded(ContainerEvent e) {
|
||||||
initializeComponents(e.getChild());
|
initializeComponents(e.getChild());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @see java.awt.event.ContainerListener#componentRemoved(java.awt.event.ContainerEvent)
|
|
||||||
*/
|
|
||||||
@Override
|
@Override
|
||||||
public void componentRemoved(ContainerEvent e) {
|
public void componentRemoved(ContainerEvent e) {
|
||||||
deinitializeComponents(e.getChild());
|
deinitializeComponents(e.getChild());
|
||||||
|
|
|
@ -2172,6 +2172,34 @@ public class DockingWindowManager implements PropertyChangeListener, Placeholder
|
||||||
objectUnderMouse = null;
|
objectUnderMouse = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Shows a popup menu over the given component. If this given component is not part of the
|
||||||
|
* docking windows hierarchy, then no action is taken.
|
||||||
|
*
|
||||||
|
* @param component the component
|
||||||
|
*/
|
||||||
|
public static void showContextMenu(Component component) {
|
||||||
|
|
||||||
|
DockingWindowManager dwm = getInstance(component);
|
||||||
|
if (dwm == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
DockableComponent dockableComponent = dwm.getDockableComponent(component);
|
||||||
|
if (dockableComponent == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Rectangle bounds = dockableComponent.getBounds();
|
||||||
|
|
||||||
|
bounds.x = 0;
|
||||||
|
bounds.y = 0;
|
||||||
|
int x = (int) bounds.getCenterX();
|
||||||
|
int y = (int) bounds.getCenterY();
|
||||||
|
PopupMenuContext popupContext = new PopupMenuContext(dockableComponent, new Point(x, y));
|
||||||
|
dockableComponent.showContextMenu(popupContext);
|
||||||
|
}
|
||||||
|
|
||||||
public void contextChanged(ComponentProvider provider) {
|
public void contextChanged(ComponentProvider provider) {
|
||||||
|
|
||||||
if (provider == null) {
|
if (provider == null) {
|
||||||
|
|
|
@ -16,6 +16,7 @@
|
||||||
package docking;
|
package docking;
|
||||||
|
|
||||||
import java.awt.Component;
|
import java.awt.Component;
|
||||||
|
import java.awt.Point;
|
||||||
import java.awt.event.MouseEvent;
|
import java.awt.event.MouseEvent;
|
||||||
import java.beans.PropertyChangeEvent;
|
import java.beans.PropertyChangeEvent;
|
||||||
import java.beans.PropertyChangeListener;
|
import java.beans.PropertyChangeListener;
|
||||||
|
@ -67,28 +68,27 @@ public class PopupActionManager implements PropertyChangeListener {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void popupMenu(ComponentPlaceholder info, MouseEvent e) {
|
void popupMenu(ComponentPlaceholder placeholder, PopupMenuContext popupContext) {
|
||||||
|
|
||||||
if (e.isConsumed()) {
|
MouseEvent event = popupContext.getEvent();
|
||||||
return;
|
ComponentProvider popupProvider = placeholder.getProvider();
|
||||||
}
|
ActionContext actionContext = popupProvider.getActionContext(event);
|
||||||
ComponentProvider popupProvider = info.getProvider();
|
|
||||||
ActionContext actionContext = popupProvider.getActionContext(e);
|
|
||||||
if (actionContext == null) {
|
if (actionContext == null) {
|
||||||
actionContext = new ActionContext();
|
actionContext = new ActionContext();
|
||||||
}
|
}
|
||||||
|
|
||||||
actionContext.setSourceObject(e.getSource());
|
actionContext.setSourceObject(popupContext.getSource());
|
||||||
actionContext.setMouseEvent(e);
|
actionContext.setMouseEvent(event);
|
||||||
|
|
||||||
Iterator<DockingActionIf> localActions = info.getActions();
|
Iterator<DockingActionIf> localActions = placeholder.getActions();
|
||||||
JPopupMenu popupMenu = createPopupMenu(localActions, actionContext);
|
JPopupMenu popupMenu = createPopupMenu(localActions, actionContext);
|
||||||
if (popupMenu == null) {
|
if (popupMenu == null) {
|
||||||
return; // no matching actions
|
return; // no matching actions
|
||||||
}
|
}
|
||||||
|
|
||||||
Component c = (Component) e.getSource();
|
Component c = popupContext.getComponent();
|
||||||
popupMenu.show(c, e.getX(), e.getY());
|
Point p = popupContext.getPoint();
|
||||||
|
popupMenu.show(c, p.x, p.y);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected JPopupMenu createPopupMenu(Iterator<DockingActionIf> localActions,
|
protected JPopupMenu createPopupMenu(Iterator<DockingActionIf> localActions,
|
||||||
|
|
|
@ -0,0 +1,61 @@
|
||||||
|
/* ###
|
||||||
|
* 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;
|
||||||
|
|
||||||
|
import java.awt.Component;
|
||||||
|
import java.awt.Point;
|
||||||
|
import java.awt.event.MouseEvent;
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A class that holds information used to show a popup menu
|
||||||
|
*/
|
||||||
|
public class PopupMenuContext {
|
||||||
|
|
||||||
|
private Component component;
|
||||||
|
private MouseEvent event;
|
||||||
|
private Point point;
|
||||||
|
|
||||||
|
PopupMenuContext(MouseEvent event) {
|
||||||
|
this.event = event;
|
||||||
|
this.component = Objects.requireNonNull(event.getComponent());
|
||||||
|
this.point = event.getPoint();
|
||||||
|
}
|
||||||
|
|
||||||
|
PopupMenuContext(Component component, Point point) {
|
||||||
|
this.component = Objects.requireNonNull(component);
|
||||||
|
this.point = point;
|
||||||
|
}
|
||||||
|
|
||||||
|
public MouseEvent getEvent() {
|
||||||
|
return event;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Component getComponent() {
|
||||||
|
return component;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Point getPoint() {
|
||||||
|
return new Point(point);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Object getSource() {
|
||||||
|
if (event != null) {
|
||||||
|
return event.getSource();
|
||||||
|
}
|
||||||
|
return component;
|
||||||
|
}
|
||||||
|
}
|
|
@ -17,8 +17,7 @@ package docking.action;
|
||||||
|
|
||||||
import java.beans.PropertyChangeEvent;
|
import java.beans.PropertyChangeEvent;
|
||||||
import java.beans.PropertyChangeListener;
|
import java.beans.PropertyChangeListener;
|
||||||
import java.util.HashMap;
|
import java.util.*;
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
import javax.swing.Action;
|
import javax.swing.Action;
|
||||||
import javax.swing.KeyStroke;
|
import javax.swing.KeyStroke;
|
||||||
|
@ -61,6 +60,7 @@ public class KeyBindingsManager implements PropertyChangeListener {
|
||||||
|
|
||||||
public void addReservedAction(DockingActionIf action) {
|
public void addReservedAction(DockingActionIf action) {
|
||||||
KeyStroke keyBinding = action.getKeyBinding();
|
KeyStroke keyBinding = action.getKeyBinding();
|
||||||
|
Objects.requireNonNull(keyBinding);
|
||||||
addReservedKeyBinding(action, keyBinding);
|
addReservedKeyBinding(action, keyBinding);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,52 @@
|
||||||
|
/* ###
|
||||||
|
* 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.action;
|
||||||
|
|
||||||
|
import java.awt.*;
|
||||||
|
|
||||||
|
import javax.swing.KeyStroke;
|
||||||
|
|
||||||
|
import docking.ActionContext;
|
||||||
|
import docking.DockingWindowManager;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An action to trigger a context menu over the focus owner. This allows context menus to be
|
||||||
|
* triggered from the keyboard.
|
||||||
|
*/
|
||||||
|
public class ShowContextMenuAction extends DockingAction {
|
||||||
|
|
||||||
|
public ShowContextMenuAction(KeyStroke keyStroke) {
|
||||||
|
super("Show Context Menu", DockingWindowManager.DOCKING_WINDOWS_OWNER);
|
||||||
|
setKeyBindingData(new KeyBindingData(keyStroke));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void actionPerformed(ActionContext context) {
|
||||||
|
|
||||||
|
KeyboardFocusManager kfm = KeyboardFocusManager.getCurrentKeyboardFocusManager();
|
||||||
|
Window window = kfm.getActiveWindow();
|
||||||
|
if (window == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// use the focused component to determine what should get the context menu
|
||||||
|
Component focusOwner = kfm.getFocusOwner();
|
||||||
|
if (focusOwner != null) {
|
||||||
|
DockingWindowManager.showContextMenu(focusOwner);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -91,6 +91,10 @@ public class ToolActions implements DockingToolActions, PropertyChangeListener {
|
||||||
keyBindingsManager.addReservedAction(new HelpAction(false, ReservedKeyBindings.HELP_KEY2));
|
keyBindingsManager.addReservedAction(new HelpAction(false, ReservedKeyBindings.HELP_KEY2));
|
||||||
keyBindingsManager.addReservedAction(
|
keyBindingsManager.addReservedAction(
|
||||||
new HelpAction(true, ReservedKeyBindings.HELP_INFO_KEY));
|
new HelpAction(true, ReservedKeyBindings.HELP_INFO_KEY));
|
||||||
|
keyBindingsManager.addReservedAction(
|
||||||
|
new ShowContextMenuAction(ReservedKeyBindings.CONTEXT_MENU_KEY1));
|
||||||
|
keyBindingsManager.addReservedAction(
|
||||||
|
new ShowContextMenuAction(ReservedKeyBindings.CONTEXT_MENU_KEY2));
|
||||||
|
|
||||||
// these are diagnostic
|
// these are diagnostic
|
||||||
if (SystemUtilities.isInDevelopmentMode()) {
|
if (SystemUtilities.isInDevelopmentMode()) {
|
||||||
|
|
|
@ -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.
|
||||||
|
@ -34,6 +33,11 @@ public class ReservedKeyBindings {
|
||||||
public static final KeyStroke HELP_INFO_KEY =
|
public static final KeyStroke HELP_INFO_KEY =
|
||||||
KeyStroke.getKeyStroke(KeyEvent.VK_F1, DockingUtils.CONTROL_KEY_MODIFIER_MASK);
|
KeyStroke.getKeyStroke(KeyEvent.VK_F1, DockingUtils.CONTROL_KEY_MODIFIER_MASK);
|
||||||
|
|
||||||
|
public static final KeyStroke CONTEXT_MENU_KEY1 =
|
||||||
|
KeyStroke.getKeyStroke(KeyEvent.VK_F10, InputEvent.SHIFT_DOWN_MASK);
|
||||||
|
public static final KeyStroke CONTEXT_MENU_KEY2 =
|
||||||
|
KeyStroke.getKeyStroke(KeyEvent.VK_CONTEXT_MENU, 0);
|
||||||
|
|
||||||
public static final KeyStroke FOCUS_INFO_KEY =
|
public static final KeyStroke FOCUS_INFO_KEY =
|
||||||
KeyStroke.getKeyStroke(KeyEvent.VK_F2, DockingUtils.CONTROL_KEY_MODIFIER_MASK |
|
KeyStroke.getKeyStroke(KeyEvent.VK_F2, DockingUtils.CONTROL_KEY_MODIFIER_MASK |
|
||||||
InputEvent.ALT_DOWN_MASK | InputEvent.SHIFT_DOWN_MASK);
|
InputEvent.ALT_DOWN_MASK | InputEvent.SHIFT_DOWN_MASK);
|
||||||
|
@ -50,7 +54,8 @@ public class ReservedKeyBindings {
|
||||||
code == KeyEvent.VK_CAPS_LOCK || code == KeyEvent.VK_TAB ||
|
code == KeyEvent.VK_CAPS_LOCK || code == KeyEvent.VK_TAB ||
|
||||||
HELP_KEY1.equals(keyStroke) || HELP_KEY2.equals(keyStroke) ||
|
HELP_KEY1.equals(keyStroke) || HELP_KEY2.equals(keyStroke) ||
|
||||||
HELP_INFO_KEY.equals(keyStroke) || UPDATE_KEY_BINDINGS_KEY.equals(keyStroke) ||
|
HELP_INFO_KEY.equals(keyStroke) || UPDATE_KEY_BINDINGS_KEY.equals(keyStroke) ||
|
||||||
FOCUS_INFO_KEY.equals(keyStroke) || FOCUS_CYCLE_INFO_KEY.equals(keyStroke)) {
|
FOCUS_INFO_KEY.equals(keyStroke) || FOCUS_CYCLE_INFO_KEY.equals(keyStroke) ||
|
||||||
|
CONTEXT_MENU_KEY1.equals(keyStroke) || CONTEXT_MENU_KEY2.equals(keyStroke)) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue