mirror of
https://github.com/NationalSecurityAgency/ghidra
synced 2024-08-27 21:10:26 +00:00
GT-2869 - Key Bindings - review fixes
This commit is contained in:
parent
43fa7e3f92
commit
2de5c40cd6
|
@ -102,7 +102,7 @@ public class CreateHelpTemplateScript extends GhidraScript {
|
|||
}
|
||||
|
||||
private List<DockingActionIf> getActions(PluginTool tool, Plugin plugin) {
|
||||
Set<DockingActionIf> actions = KeyBindingUtils.getKeyBindingActions(tool, plugin.getName());
|
||||
Set<DockingActionIf> actions = KeyBindingUtils.getKeyBindingActionsForOwner(tool, plugin.getName());
|
||||
List<DockingActionIf> list = new ArrayList<>(actions);
|
||||
Comparator<DockingActionIf> comparator = (action1, action2) -> {
|
||||
try {
|
||||
|
|
|
@ -186,8 +186,8 @@ public class KeyEntryDialogTest extends AbstractGhidraHeadedIntegrationTest {
|
|||
|
||||
public DockingAction getKeyBindingAction() {
|
||||
DockingWindowManager dwm = DockingWindowManager.getInstance(tool.getToolFrame());
|
||||
DockingActionManager dockingActionManager =
|
||||
(DockingActionManager) getInstanceField("actionManager", dwm);
|
||||
ActionToGuiMapper dockingActionManager =
|
||||
(ActionToGuiMapper) getInstanceField("actionManager", dwm);
|
||||
return (DockingAction) getInstanceField("keyBindingsAction", dockingActionManager);
|
||||
}
|
||||
|
||||
|
|
|
@ -21,7 +21,7 @@ import java.util.*;
|
|||
import javax.swing.JFrame;
|
||||
|
||||
import docking.action.DockingActionIf;
|
||||
import docking.actions.DockingToolActionManager;
|
||||
import docking.actions.ToolActions;
|
||||
import ghidra.framework.options.ToolOptions;
|
||||
import ghidra.util.SystemUtilities;
|
||||
|
||||
|
@ -32,7 +32,7 @@ import ghidra.util.SystemUtilities;
|
|||
public abstract class AbstractDockingTool implements DockingTool {
|
||||
|
||||
protected DockingWindowManager winMgr;
|
||||
protected DockingToolActionManager actionMgr;
|
||||
protected ToolActions actionMgr;
|
||||
protected Map<String, ToolOptions> optionsMap = new HashMap<>();
|
||||
protected boolean configChangedFlag;
|
||||
|
||||
|
@ -117,7 +117,7 @@ public abstract class AbstractDockingTool implements DockingTool {
|
|||
@Override
|
||||
public Set<DockingActionIf> getAllActions() {
|
||||
Set<DockingActionIf> actions = actionMgr.getAllActions();
|
||||
DockingActionManager am = winMgr.getActionManager();
|
||||
ActionToGuiMapper am = winMgr.getActionManager();
|
||||
actions.addAll(am.getAllActions());
|
||||
return actions;
|
||||
}
|
||||
|
|
|
@ -28,7 +28,7 @@ import ghidra.util.*;
|
|||
/**
|
||||
* Manages the global actions for the menu and toolbar.
|
||||
*/
|
||||
public class DockingActionManager {
|
||||
public class ActionToGuiMapper {
|
||||
|
||||
private HashSet<DockingActionIf> globalActions = new LinkedHashSet<>();
|
||||
|
||||
|
@ -44,7 +44,7 @@ public class DockingActionManager {
|
|||
private PopupActionManager popupActionManager;
|
||||
private DockingAction keyBindingsAction;
|
||||
|
||||
DockingActionManager(DockingWindowManager winMgr) {
|
||||
ActionToGuiMapper(DockingWindowManager winMgr) {
|
||||
menuGroupMap = new MenuGroupMap();
|
||||
|
||||
menuBarMenuHandler = new MenuBarMenuHandler(winMgr);
|
|
@ -69,7 +69,7 @@ public class DialogComponentProviderPopupActionManager {
|
|||
return;
|
||||
}
|
||||
|
||||
DockingActionManager actionManager = dwm.getActionManager();
|
||||
ActionToGuiMapper actionManager = dwm.getActionManager();
|
||||
MenuGroupMap menuGroupMap = actionManager.getMenuGroupMap();
|
||||
MenuManager menuMgr =
|
||||
new MenuManager("Popup", '\0', null, true, popupMenuHandler, menuGroupMap);
|
||||
|
|
|
@ -52,7 +52,7 @@ public class DockableComponent extends JPanel implements ContainerListener {
|
|||
private JComponent providerComp;
|
||||
private Component focusedComponent;
|
||||
private DockingWindowManager winMgr;
|
||||
private DockingActionManager actionMgr;
|
||||
private ActionToGuiMapper actionMgr;
|
||||
private DropTarget dockableDropTarget;
|
||||
|
||||
/**
|
||||
|
|
|
@ -60,7 +60,7 @@ class DockableToolBarManager {
|
|||
ComponentPlaceholder placeholder = dockableComp.getComponentWindowingPlaceholder();
|
||||
DockingWindowManager winMgr =
|
||||
dockableComp.getComponentWindowingPlaceholder().getNode().winMgr;
|
||||
DockingActionManager actionManager = winMgr.getActionManager();
|
||||
ActionToGuiMapper actionManager = winMgr.getActionManager();
|
||||
menuGroupMap = actionManager.getMenuGroupMap();
|
||||
|
||||
MenuHandler menuHandler = actionManager.getMenuHandler();
|
||||
|
|
|
@ -24,11 +24,11 @@ import docking.action.DockingActionIf;
|
|||
* {@link DockingWindowManager}. This allows the manager's interface to hide methods that
|
||||
* don't make sense for public consumption.
|
||||
*/
|
||||
public class DockingWindowManagerActionUpdater {
|
||||
public class DockingActionPackageHelper {
|
||||
|
||||
private DockingWindowManager windowManager;
|
||||
|
||||
public DockingWindowManagerActionUpdater(DockingWindowManager windowManager) {
|
||||
public DockingActionPackageHelper(DockingWindowManager windowManager) {
|
||||
this.windowManager = windowManager;
|
||||
}
|
||||
|
|
@ -89,7 +89,7 @@ public class DockingWindowManager implements PropertyChangeListener, Placeholder
|
|||
private Map<String, ComponentProvider> providerNameCache = new HashMap<>();
|
||||
private Map<String, PreferenceState> preferenceStateMap = new HashMap<>();
|
||||
private DockWinListener docListener;
|
||||
private DockingActionManager actionManager;
|
||||
private ActionToGuiMapper actionManager;
|
||||
|
||||
private WeakSet<DockingContextListener> contextListeners =
|
||||
WeakDataStructureFactory.createSingleThreadAccessWeakSet();
|
||||
|
@ -140,7 +140,7 @@ public class DockingWindowManager implements PropertyChangeListener, Placeholder
|
|||
}
|
||||
|
||||
root = new RootNode(this, toolName, images, modal, factory);
|
||||
actionManager = new DockingActionManager(this);
|
||||
actionManager = new ActionToGuiMapper(this);
|
||||
|
||||
KeyboardFocusManager km = KeyboardFocusManager.getCurrentKeyboardFocusManager();
|
||||
km.addPropertyChangeListener("permanentFocusOwner", this);
|
||||
|
@ -161,7 +161,7 @@ public class DockingWindowManager implements PropertyChangeListener, Placeholder
|
|||
* @param enable
|
||||
*/
|
||||
public static void enableDiagnosticActions(boolean enable) {
|
||||
DockingActionManager.enableDiagnosticActions(enable);
|
||||
ActionToGuiMapper.enableDiagnosticActions(enable);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -293,7 +293,7 @@ public class DockingWindowManager implements PropertyChangeListener, Placeholder
|
|||
* @param helpLocation help content location
|
||||
*/
|
||||
public static void setHelpLocation(JComponent c, HelpLocation helpLocation) {
|
||||
DockingActionManager.setHelpLocation(c, helpLocation);
|
||||
ActionToGuiMapper.setHelpLocation(c, helpLocation);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -338,7 +338,7 @@ public class DockingWindowManager implements PropertyChangeListener, Placeholder
|
|||
return placeholderManager;
|
||||
}
|
||||
|
||||
DockingActionManager getActionManager() {
|
||||
ActionToGuiMapper getActionManager() {
|
||||
return actionManager;
|
||||
}
|
||||
|
||||
|
|
|
@ -130,7 +130,7 @@ public class GlobalMenuAndToolBarManager implements DockingWindowListener {
|
|||
}
|
||||
|
||||
private List<DockingActionIf> getActionsForWindow(WindowNode windowNode) {
|
||||
DockingActionManager actionManager = windowManager.getActionManager();
|
||||
ActionToGuiMapper actionManager = windowManager.getActionManager();
|
||||
Collection<DockingActionIf> globalActions = actionManager.getGlobalActions();
|
||||
List<DockingActionIf> actionsForWindow = new ArrayList<>(globalActions.size());
|
||||
Set<Class<?>> contextTypes = windowNode.getContextTypes();
|
||||
|
|
|
@ -24,9 +24,9 @@ import ghidra.util.Msg;
|
|||
import ghidra.util.ReservedKeyBindings;
|
||||
|
||||
public class KeyBindingAction extends DockingAction {
|
||||
private final DockingActionManager dockingActionManager;
|
||||
private final ActionToGuiMapper dockingActionManager;
|
||||
|
||||
public KeyBindingAction(DockingActionManager dockingActionManager) {
|
||||
public KeyBindingAction(ActionToGuiMapper dockingActionManager) {
|
||||
super("Set KeyBinding", DockingWindowManager.DOCKING_WINDOWS_OWNER);
|
||||
this.dockingActionManager = dockingActionManager;
|
||||
createReservedKeyBinding(ReservedKeyBindings.UPDATE_KEY_BINDINGS_KEY);
|
||||
|
|
|
@ -35,7 +35,7 @@ import resources.ResourceManager;
|
|||
*/
|
||||
public class KeyEntryDialog extends DialogComponentProvider {
|
||||
|
||||
private DockingActionManager actionManager;
|
||||
private ActionToGuiMapper actionManager;
|
||||
private DockingActionIf action;
|
||||
private JPanel defaultPanel;
|
||||
private KeyEntryTextField keyEntryField;
|
||||
|
@ -45,7 +45,7 @@ public class KeyEntryDialog extends DialogComponentProvider {
|
|||
private SimpleAttributeSet textAttrSet;
|
||||
private Color bgColor;
|
||||
|
||||
public KeyEntryDialog(DockingActionIf action, DockingActionManager actionManager) {
|
||||
public KeyEntryDialog(DockingActionIf action, ActionToGuiMapper actionManager) {
|
||||
super("Set Key Binding for " + action.getName(), true);
|
||||
this.actionManager = actionManager;
|
||||
this.action = action;
|
||||
|
|
|
@ -336,7 +336,7 @@ public class KeyBindingUtils {
|
|||
* @param tool the tool containing the actions
|
||||
* @return the actions mapped by their full name (e.g., 'Name (OwnerName)')
|
||||
*/
|
||||
public static Map<String, DockingActionIf> getAllKeyBindingActions(DockingTool tool) {
|
||||
public static Map<String, DockingActionIf> getAllKeyBindingActionsByFullName(DockingTool tool) {
|
||||
|
||||
Map<String, DockingActionIf> deduper = new HashMap<>();
|
||||
Set<DockingActionIf> actions = tool.getAllActions();
|
||||
|
@ -363,7 +363,8 @@ public class KeyBindingUtils {
|
|||
* @param owner the action owner name
|
||||
* @return the actions
|
||||
*/
|
||||
public static Set<DockingActionIf> getKeyBindingActions(DockingTool tool, String owner) {
|
||||
public static Set<DockingActionIf> getKeyBindingActionsForOwner(DockingTool tool,
|
||||
String owner) {
|
||||
|
||||
Map<String, DockingActionIf> deduper = new HashMap<>();
|
||||
Set<DockingActionIf> actions = tool.getDockingActionsByOwnerName(owner);
|
||||
|
@ -381,19 +382,6 @@ public class KeyBindingUtils {
|
|||
return CollectionUtils.asSet(deduper.values());
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns all actions that match the given owner and name
|
||||
*
|
||||
* @param tool the tool containing the actions
|
||||
* @param owner the owner
|
||||
* @param name the name
|
||||
* @return the actions
|
||||
*/
|
||||
public static Set<DockingActionIf> getActions(DockingTool tool, String owner, String name) {
|
||||
Set<DockingActionIf> actions = tool.getDockingActionsByOwnerName(owner);
|
||||
return getActions(actions, owner, name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns all actions that match the given owner and name
|
||||
*
|
||||
|
@ -421,16 +409,17 @@ public class KeyBindingUtils {
|
|||
public static DockingActionIf getSharedKeyBindingAction(Set<DockingActionIf> allActions,
|
||||
String sharedName) {
|
||||
|
||||
Set<DockingActionIf> toolActions = getActions(allActions, "Tool", sharedName);
|
||||
String owner = "Tool";
|
||||
for (DockingActionIf action : allActions) {
|
||||
if (!(action instanceof SharedStubKeyBindingAction)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
//@formatter:off
|
||||
return toolActions
|
||||
.stream()
|
||||
.filter(action -> action instanceof SharedStubKeyBindingAction)
|
||||
.findAny()
|
||||
.orElse(null)
|
||||
;
|
||||
//@formatter:on
|
||||
if (action.getOwner().equals(owner) && action.getName().equals(sharedName)) {
|
||||
return action;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private static boolean isIgnored(DockingActionIf action) {
|
||||
|
@ -456,8 +445,15 @@ public class KeyBindingUtils {
|
|||
return new ActionAdapter(action);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks each action in the given collection against the given new action to make sure that
|
||||
* they share the same default key binding.
|
||||
*
|
||||
* @param newAction the action to check
|
||||
* @param existingActions the actions that have already been checked
|
||||
*/
|
||||
public static void assertSameDefaultKeyBindings(DockingActionIf newAction,
|
||||
List<DockingActionIf> existingActions) {
|
||||
Collection<DockingActionIf> existingActions) {
|
||||
|
||||
KeyBindingData newDefaultBinding = newAction.getDefaultKeyBindingData();
|
||||
KeyStroke defaultKs = getKeyStroke(newDefaultBinding);
|
||||
|
@ -471,6 +467,14 @@ public class KeyBindingUtils {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Logs a warning message for the two given actions to signal that they do not share the
|
||||
* same default key binding
|
||||
*
|
||||
* @param newAction the new action
|
||||
* @param existingAction the action that has already been validated
|
||||
* @param existingDefaultKs the current validated key stroke
|
||||
*/
|
||||
public static void logDifferentKeyBindingsWarnigMessage(DockingActionIf newAction,
|
||||
DockingActionIf existingAction, KeyStroke existingDefaultKs) {
|
||||
|
||||
|
|
|
@ -18,7 +18,7 @@ package docking.actions;
|
|||
import java.beans.PropertyChangeEvent;
|
||||
import java.beans.PropertyChangeListener;
|
||||
import java.util.*;
|
||||
import java.util.function.Predicate;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import javax.swing.KeyStroke;
|
||||
|
||||
|
@ -33,14 +33,22 @@ import ghidra.util.exception.AssertException;
|
|||
/**
|
||||
* An class to manage actions registered with the tool
|
||||
*/
|
||||
public class DockingToolActionManager implements PropertyChangeListener {
|
||||
public class ToolActions implements PropertyChangeListener {
|
||||
|
||||
private DockingWindowManager winMgr;
|
||||
private DockingWindowManagerActionUpdater winMgrActionUpdater;
|
||||
private DockingActionPackageHelper actionGuiHelper;
|
||||
|
||||
/*
|
||||
Map of Maps of Sets
|
||||
|
||||
Owner Name ->
|
||||
Action Name -> Set of Actions
|
||||
*/
|
||||
private Map<String, Map<String, Set<DockingActionIf>>> actionsByNameByOwner = LazyMap.lazyMap(
|
||||
new HashMap<>(), () -> LazyMap.lazyMap(new HashMap<>(), () -> new HashSet<>()));
|
||||
|
||||
private Map<String, List<DockingActionIf>> actionMap =
|
||||
LazyMap.lazyMap(new HashMap<>(), () -> new ArrayList<>());
|
||||
private Map<String, SharedStubKeyBindingAction> sharedActionMap = new HashMap<>();
|
||||
|
||||
private ToolOptions keyBindingOptions;
|
||||
private DockingTool dockingTool;
|
||||
|
||||
|
@ -51,32 +59,27 @@ public class DockingToolActionManager implements PropertyChangeListener {
|
|||
* @param windowManager manager of the "Docking" arrangement of a set of components
|
||||
* and actions in the tool
|
||||
*/
|
||||
public DockingToolActionManager(DockingTool tool, DockingWindowManager windowManager) {
|
||||
public ToolActions(DockingTool tool, DockingWindowManager windowManager) {
|
||||
this.dockingTool = tool;
|
||||
this.winMgr = windowManager;
|
||||
this.winMgrActionUpdater = new DockingWindowManagerActionUpdater(winMgr);
|
||||
this.actionGuiHelper = new DockingActionPackageHelper(winMgr);
|
||||
keyBindingOptions = tool.getOptions(DockingToolConstants.KEY_BINDINGS);
|
||||
}
|
||||
|
||||
public void dispose() {
|
||||
actionMap.clear();
|
||||
actionsByNameByOwner.clear();
|
||||
sharedActionMap.clear();
|
||||
}
|
||||
|
||||
private void addActionToMap(DockingActionIf action) {
|
||||
String name = action.getFullName();
|
||||
List<DockingActionIf> actionList = actionMap.get(name);
|
||||
|
||||
List<DockingActionIf> list = actionMap.get(name);
|
||||
if (!list.isEmpty()) {
|
||||
KeyBindingUtils.assertSameDefaultKeyBindings(action, actionList);
|
||||
}
|
||||
|
||||
actionList.add(action);
|
||||
Set<DockingActionIf> actions = getActionStorage(action);
|
||||
KeyBindingUtils.assertSameDefaultKeyBindings(action, actions);
|
||||
actions.add(action);
|
||||
}
|
||||
|
||||
private void removeActionFromMap(DockingActionIf action) {
|
||||
String name = action.getFullName();
|
||||
actionMap.get(name).remove(action);
|
||||
getActionStorage(action).remove(action);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -90,7 +93,7 @@ public class DockingToolActionManager implements PropertyChangeListener {
|
|||
action.addPropertyChangeListener(this);
|
||||
addActionToMap(action);
|
||||
setKeyBindingOption(action);
|
||||
winMgrActionUpdater.addLocalAction(provider, action);
|
||||
actionGuiHelper.addLocalAction(provider, action);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -101,7 +104,7 @@ public class DockingToolActionManager implements PropertyChangeListener {
|
|||
action.addPropertyChangeListener(this);
|
||||
addActionToMap(action);
|
||||
setKeyBindingOption(action);
|
||||
winMgrActionUpdater.addToolAction(action);
|
||||
actionGuiHelper.addToolAction(action);
|
||||
}
|
||||
|
||||
private void setKeyBindingOption(DockingActionIf action) {
|
||||
|
@ -148,7 +151,7 @@ public class DockingToolActionManager implements PropertyChangeListener {
|
|||
public synchronized void removeToolAction(DockingActionIf action) {
|
||||
action.removePropertyChangeListener(this);
|
||||
removeActionFromMap(action);
|
||||
winMgrActionUpdater.removeToolAction(action);
|
||||
actionGuiHelper.removeToolAction(action);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -156,19 +159,23 @@ public class DockingToolActionManager implements PropertyChangeListener {
|
|||
* @param owner owner of the actions to remove
|
||||
*/
|
||||
public synchronized void removeToolActions(String owner) {
|
||||
Predicate<String> ownerMatches = actionOwner -> actionOwner.equals(owner);
|
||||
Set<DockingActionIf> actions = getActions(ownerMatches);
|
||||
for (DockingActionIf action : actions) {
|
||||
removeToolAction(action);
|
||||
}
|
||||
|
||||
//@formatter:off
|
||||
Set<DockingActionIf> toRemove = actionsByNameByOwner.get(owner).values()
|
||||
.stream()
|
||||
.flatMap(set -> set.stream())
|
||||
.collect(Collectors.toSet())
|
||||
;
|
||||
//@formatter:on
|
||||
|
||||
// must do this later to avoid concurrent modification exceptions
|
||||
toRemove.forEach(action -> removeToolAction(action));
|
||||
}
|
||||
|
||||
private void checkForAlreadyAddedAction(ComponentProvider provider, DockingActionIf action) {
|
||||
String name = action.getFullName();
|
||||
List<DockingActionIf> actionList = actionMap.get(name);
|
||||
if (actionList.contains(action)) {
|
||||
if (getActionStorage(action).contains(action)) {
|
||||
throw new AssertException("Cannot add the same action more than once. Provider " +
|
||||
provider.getName() + " - action: " + name);
|
||||
provider.getName() + " - action: " + action.getFullName());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -184,46 +191,6 @@ public class DockingToolActionManager implements PropertyChangeListener {
|
|||
winMgr.removeProviderAction(provider, action);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all actions that have the action name which includes the action owner's name.
|
||||
*
|
||||
* @param fullName full name for the action, e.g., "My Action (My Plugin)"
|
||||
* @return list of actions; empty if no action exists with the given name
|
||||
*/
|
||||
public Set<DockingActionIf> getDockingActionsByFullActionName(String fullName) {
|
||||
List<DockingActionIf> list = actionMap.get(fullName);
|
||||
return new HashSet<>(list);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a list of actions whose owner matches the given predicate.
|
||||
*
|
||||
* Note: Actions with the same name are assumed to be different instances of the same action.
|
||||
*
|
||||
* @param ownerFilter the predicate that is used to test if the owners are the same; to get
|
||||
* all actions, return an 'always true' predicate
|
||||
* @return a list of deduped actions.
|
||||
*/
|
||||
private Set<DockingActionIf> getActions(Predicate<String> ownerFilter) {
|
||||
|
||||
Set<DockingActionIf> result = new HashSet<>();
|
||||
for (List<DockingActionIf> list : actionMap.values()) {
|
||||
for (DockingActionIf action : list) {
|
||||
if (ownerFilter.test(action.getOwner())) {
|
||||
result.addAll(list);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (DockingActionIf action : sharedActionMap.values()) {
|
||||
if (ownerFilter.test(action.getOwner())) {
|
||||
result.add(action);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all actions for the given owner.
|
||||
* @param owner owner of the actions
|
||||
|
@ -231,24 +198,42 @@ public class DockingToolActionManager implements PropertyChangeListener {
|
|||
* action exists with the given name
|
||||
*/
|
||||
public synchronized Set<DockingActionIf> getActions(String owner) {
|
||||
Predicate<String> ownerMatches = actionOwner -> actionOwner.equals(owner);
|
||||
return getActions(ownerMatches);
|
||||
|
||||
Set<DockingActionIf> result = new HashSet<>();
|
||||
Map<String, Set<DockingActionIf>> actionsByName = actionsByNameByOwner.get(owner);
|
||||
for (Set<DockingActionIf> actions : actionsByName.values()) {
|
||||
result.addAll(actions);
|
||||
}
|
||||
|
||||
if (SharedStubKeyBindingAction.SHARED_OWNER.equals(owner)) {
|
||||
result.addAll(sharedActionMap.values());
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a list of all actions in the tool
|
||||
* @return list of PluginAction objects
|
||||
* Get a set of all actions in the tool
|
||||
* @return the actions
|
||||
*/
|
||||
public synchronized Set<DockingActionIf> getAllActions() {
|
||||
Predicate<String> allOwnersMatch = name -> true;
|
||||
return getActions(allOwnersMatch);
|
||||
|
||||
Set<DockingActionIf> result = new HashSet<>();
|
||||
Collection<Map<String, Set<DockingActionIf>>> maps = actionsByNameByOwner.values();
|
||||
for (Map<String, Set<DockingActionIf>> actionsByName : maps) {
|
||||
for (Set<DockingActionIf> actions : actionsByName.values()) {
|
||||
result.addAll(actions);
|
||||
}
|
||||
}
|
||||
|
||||
result.addAll(sharedActionMap.values());
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the keybindings for each action so that they are still registered
|
||||
* as being used; otherwise the options will be removed because they
|
||||
* are noted as not being used.
|
||||
*
|
||||
* Get the keybindings for each action so that they are still registered as being used;
|
||||
* otherwise the options will be removed because they are noted as not being used.
|
||||
*/
|
||||
public synchronized void restoreKeyBindings() {
|
||||
keyBindingOptions = dockingTool.getOptions(DockingToolConstants.KEY_BINDINGS);
|
||||
|
@ -272,12 +257,16 @@ public class DockingToolActionManager implements PropertyChangeListener {
|
|||
public void removeComponentActions(ComponentProvider provider) {
|
||||
Iterator<DockingActionIf> iterator = winMgr.getComponentActions(provider);
|
||||
while (iterator.hasNext()) {
|
||||
DockingActionIf action = iterator.next();
|
||||
String name = action.getFullName();
|
||||
actionMap.get(name).remove(action);
|
||||
removeActionFromMap(iterator.next());
|
||||
}
|
||||
}
|
||||
|
||||
private Set<DockingActionIf> getActionStorage(DockingActionIf action) {
|
||||
String owner = action.getOwner();
|
||||
String name = action.getName();
|
||||
return actionsByNameByOwner.get(owner).get(name);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void propertyChange(PropertyChangeEvent evt) {
|
||||
if (evt.getPropertyName().equals(DockingActionIf.KEYBINDING_DATA_PROPERTY)) {
|
|
@ -442,9 +442,10 @@ public abstract class AbstractSortedTableModel<T> extends AbstractGTableModel<T>
|
|||
public int compare(T t1, T t2) {
|
||||
|
||||
// at this point we compare the rows, since all of the sorting column values are equal
|
||||
// (Warning: there is a chance that the two objects are comparable, but not on each
|
||||
// other. In this case, a ClassCastException will be thrown)
|
||||
if (t1 instanceof Comparable && t2 instanceof Comparable) {
|
||||
// (Warning: due to comparable being specific to the class upon which it is defined,
|
||||
// we have to make sure the class is the same to prevent class cast
|
||||
// exceptions when the table has mixed implementations of 'T')
|
||||
if (t1 instanceof Comparable && t1.getClass().equals(t2.getClass())) {
|
||||
return ((Comparable) t1).compareTo(t2);
|
||||
}
|
||||
|
||||
|
|
|
@ -357,8 +357,8 @@ public class SharedKeyBindingDockingActionTest extends AbstractDockingTest {
|
|||
//==================================================================================================
|
||||
|
||||
private void assertSharedStubInTool() {
|
||||
DockingToolActionManager actionManager =
|
||||
(DockingToolActionManager) getInstanceField("actionMgr", tool);
|
||||
ToolActions actionManager =
|
||||
(ToolActions) getInstanceField("actionMgr", tool);
|
||||
DockingActionIf action = actionManager.getSharedStubKeyBindingAction(SHARED_NAME);
|
||||
assertNotNull("Shared action stub is not in the tool", action);
|
||||
}
|
||||
|
|
|
@ -21,7 +21,7 @@ import java.util.List;
|
|||
import javax.swing.ImageIcon;
|
||||
|
||||
import docking.action.DockingActionIf;
|
||||
import docking.actions.DockingToolActionManager;
|
||||
import docking.actions.ToolActions;
|
||||
import docking.framework.ApplicationInformationDisplayFactory;
|
||||
import ghidra.framework.options.ToolOptions;
|
||||
|
||||
|
@ -37,7 +37,7 @@ public class FakeDockingTool extends AbstractDockingTool {
|
|||
List<Image> windowIcons = ApplicationInformationDisplayFactory.getWindowIcons();
|
||||
winMgr = new DockingWindowManager("EMPTY", windowIcons, listener, false /*isModal*/,
|
||||
true /*isDockable*/, true /*hasStatus*/, null /*DropTargetFactory*/);
|
||||
actionMgr = new DockingToolActionManager(this, winMgr);
|
||||
actionMgr = new ToolActions(this, winMgr);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -18,6 +18,7 @@ package ghidra.util;
|
|||
import java.util.*;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.apache.commons.lang3.ArrayUtils;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
@ -857,18 +858,9 @@ public class StringUtilities {
|
|||
return null;
|
||||
}
|
||||
|
||||
int i = 0;
|
||||
StringBuffer buffer = new StringBuffer("[ ");
|
||||
for (Object o : collection) {
|
||||
buffer.append(o.toString());
|
||||
if (i + 1 < collection.size()) {
|
||||
buffer.append(separator);
|
||||
}
|
||||
i++;
|
||||
}
|
||||
|
||||
buffer.append(" ]");
|
||||
return buffer.toString();
|
||||
String asString =
|
||||
collection.stream().map(o -> o.toString()).collect(Collectors.joining(separator));
|
||||
return "[ " + asString + " ]";
|
||||
}
|
||||
|
||||
public static String toStringWithIndent(Object o) {
|
||||
|
|
|
@ -218,7 +218,7 @@ public class PluginConfigurationModel {
|
|||
return Collections.emptySet();
|
||||
}
|
||||
|
||||
return KeyBindingUtils.getKeyBindingActions(tool, pluginDescription.getName());
|
||||
return KeyBindingUtils.getKeyBindingActionsForOwner(tool, pluginDescription.getName());
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -33,7 +33,7 @@ import org.jdom.Element;
|
|||
|
||||
import docking.*;
|
||||
import docking.action.*;
|
||||
import docking.actions.DockingToolActionManager;
|
||||
import docking.actions.ToolActions;
|
||||
import docking.framework.AboutDialog;
|
||||
import docking.framework.ApplicationInformationDisplayFactory;
|
||||
import docking.framework.SplashScreen;
|
||||
|
@ -158,7 +158,7 @@ public abstract class PluginTool extends AbstractDockingTool
|
|||
eventMgr = new EventManager(this);
|
||||
serviceMgr = new ServiceManager();
|
||||
installServices();
|
||||
actionMgr = new DockingToolActionManager(this, winMgr);
|
||||
actionMgr = new ToolActions(this, winMgr);
|
||||
pluginMgr = new PluginManager(this, serviceMgr);
|
||||
dialogMgr = new DialogManager(this);
|
||||
initActions();
|
||||
|
|
|
@ -171,7 +171,7 @@ public class KeyBindingsPanel extends JPanel {
|
|||
originalValues = new HashMap<>();
|
||||
String longestName = "";
|
||||
|
||||
actionsByFullName = KeyBindingUtils.getAllKeyBindingActions(tool);
|
||||
actionsByFullName = KeyBindingUtils.getAllKeyBindingActionsByFullName(tool);
|
||||
Set<Entry<String, DockingActionIf>> entries = actionsByFullName.entrySet();
|
||||
for (Entry<String, DockingActionIf> entry : entries) {
|
||||
|
||||
|
|
|
@ -1,299 +0,0 @@
|
|||
/* ###
|
||||
* IP: GHIDRA
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package ghidra.framework.plugintool.mgr;
|
||||
|
||||
import java.beans.PropertyChangeEvent;
|
||||
import java.beans.PropertyChangeListener;
|
||||
import java.util.*;
|
||||
|
||||
import javax.swing.KeyStroke;
|
||||
|
||||
import docking.*;
|
||||
import docking.action.*;
|
||||
import docking.tool.util.DockingToolConstants;
|
||||
import ghidra.framework.options.OptionType;
|
||||
import ghidra.framework.options.Options;
|
||||
import ghidra.framework.plugintool.PluginTool;
|
||||
import ghidra.util.exception.AssertException;
|
||||
|
||||
/**
|
||||
* Helper class to manage plugin actions for the tool.
|
||||
*/
|
||||
public class ProjectActionManager implements PropertyChangeListener {
|
||||
|
||||
private DockingWindowManager winMgr;
|
||||
private DockingWindowManagerActionUpdater winMgrActionUpdater;
|
||||
|
||||
// TODO
|
||||
// TODO
|
||||
// TODO does this class need the shared action concept (probably not)
|
||||
// TODO
|
||||
// TODO
|
||||
private Map<String, List<DockingActionIf>> actionMap;
|
||||
private Options keyBindingOptions;
|
||||
private PluginTool tool;
|
||||
|
||||
/**
|
||||
* Construct an ActionManager
|
||||
* @param tool plugin tool using this ActionManager
|
||||
* @param winMgr manager of the "Docking" arrangement
|
||||
* of a set of components and actions in the tool
|
||||
*/
|
||||
public ProjectActionManager(PluginTool tool, DockingWindowManager winMgr) {
|
||||
this.tool = tool;
|
||||
this.winMgr = winMgr;
|
||||
this.winMgrActionUpdater = new DockingWindowManagerActionUpdater(winMgr);
|
||||
actionMap = new HashMap<>();
|
||||
keyBindingOptions = tool.getOptions(DockingToolConstants.KEY_BINDINGS);
|
||||
}
|
||||
|
||||
public void dispose() {
|
||||
actionMap.clear();
|
||||
}
|
||||
|
||||
private void addActionToMap(DockingActionIf action) {
|
||||
String name = action.getFullName();
|
||||
List<DockingActionIf> actionList = actionMap.get(name);
|
||||
if (actionList == null) {
|
||||
List<DockingActionIf> newList = new ArrayList<>();
|
||||
newList.add(action);
|
||||
actionMap.put(name, newList);
|
||||
}
|
||||
else {
|
||||
actionList.add(action);
|
||||
}
|
||||
}
|
||||
|
||||
private void removeActionFromMap(DockingActionIf action) {
|
||||
String name = action.getFullName();
|
||||
List<DockingActionIf> actionList = actionMap.get(name);
|
||||
if (actionList == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (actionList.remove(action) && actionList.isEmpty()) {
|
||||
actionMap.remove(name);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds the action to the tool.
|
||||
* @param action the action to be added.
|
||||
*/
|
||||
public synchronized void addToolAction(DockingActionIf action) {
|
||||
action.addPropertyChangeListener(this);
|
||||
addActionToMap(action);
|
||||
if (action.isKeyBindingManaged()) {
|
||||
KeyStroke ks = action.getKeyBinding();
|
||||
keyBindingOptions.registerOption(action.getFullName(), OptionType.KEYSTROKE_TYPE, ks,
|
||||
null, null);
|
||||
KeyStroke newKs = keyBindingOptions.getKeyStroke(action.getFullName(), ks);
|
||||
if (ks != newKs) {
|
||||
action.setUnvalidatedKeyBindingData(new KeyBindingData(newKs));
|
||||
}
|
||||
}
|
||||
|
||||
winMgrActionUpdater.addToolAction(action);
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes the given action from the tool
|
||||
* @param action the action to be removed.
|
||||
*/
|
||||
public synchronized void removeToolAction(DockingActionIf action) {
|
||||
action.removePropertyChangeListener(this);
|
||||
removeActionFromMap(action);
|
||||
winMgrActionUpdater.removeToolAction(action);
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove all actions that have the given owner.
|
||||
* @param owner owner of the actions to remove
|
||||
*/
|
||||
public synchronized void removeToolActions(String owner) {
|
||||
List<DockingActionIf> actions = getActions(owner);
|
||||
for (DockingActionIf action : actions) {
|
||||
removeToolAction(action);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Add an action that works specifically with a component provider.
|
||||
* @param provider provider associated with the action
|
||||
* @param action local action to the provider
|
||||
*/
|
||||
public synchronized void addLocalAction(ComponentProvider provider, DockingActionIf action) {
|
||||
checkForAlreadyAddedAction(provider, action);
|
||||
|
||||
action.addPropertyChangeListener(this);
|
||||
addActionToMap(action);
|
||||
if (action.isKeyBindingManaged()) {
|
||||
KeyStroke ks = action.getKeyBinding();
|
||||
keyBindingOptions.registerOption(action.getFullName(), OptionType.KEYSTROKE_TYPE, ks,
|
||||
null, null);
|
||||
KeyStroke newKs = keyBindingOptions.getKeyStroke(action.getFullName(), ks);
|
||||
if (ks != newKs) {
|
||||
action.setUnvalidatedKeyBindingData(new KeyBindingData(newKs));
|
||||
}
|
||||
}
|
||||
winMgrActionUpdater.addLocalAction(provider, action);
|
||||
}
|
||||
|
||||
private void checkForAlreadyAddedAction(ComponentProvider provider, DockingActionIf action) {
|
||||
String name = action.getFullName();
|
||||
List<DockingActionIf> actionList = actionMap.get(name);
|
||||
if (actionList == null) {
|
||||
return;
|
||||
}
|
||||
if (actionList.contains(action)) {
|
||||
throw new AssertException("Cannot add the same action more than once. Provider " +
|
||||
provider.getName() + " - action: " + name);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove an action that works specifically with a component provider.
|
||||
* @param provider provider associated with the action
|
||||
* @param action local action to the provider
|
||||
*/
|
||||
public synchronized void removeProviderAction(ComponentProvider provider,
|
||||
DockingActionIf action) {
|
||||
action.removePropertyChangeListener(this);
|
||||
removeActionFromMap(action);
|
||||
winMgr.removeProviderAction(provider, action);
|
||||
}
|
||||
|
||||
// TODO delete me
|
||||
/**
|
||||
* Get all actions that have the action name which includes the action owner's name.
|
||||
*
|
||||
* @param fullName full name for the action, e.g., "My Action (My Plugin)"
|
||||
* @return list of actions; empty if no action exists with the given name
|
||||
*/
|
||||
public List<DockingActionIf> getDockingActionsByFullActionName(String fullName) {
|
||||
List<DockingActionIf> list = actionMap.get(fullName);
|
||||
if (list == null) {
|
||||
return new ArrayList<>();
|
||||
}
|
||||
return new ArrayList<>(list);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a list of actions whose owner matches the given owner or all actions if the given
|
||||
* owner is null.
|
||||
* <p>
|
||||
* This method will only return a single instance of any named action, even if multiple
|
||||
* actions have been registered with the same name.
|
||||
* <p>
|
||||
* Note: Actions with the same name are assumed to be different instances of the same action.
|
||||
*
|
||||
* @param owner The of the action, or null to get all actions
|
||||
* @return a list of deduped actions.
|
||||
*/
|
||||
private List<DockingActionIf> getUniqueActionList(String owner) {
|
||||
List<DockingActionIf> matchingActionList = new ArrayList<>();
|
||||
|
||||
for (List<DockingActionIf> actionList : actionMap.values()) {
|
||||
// we only want *one* instance of duplicate actions
|
||||
DockingActionIf action = actionList.get(0);
|
||||
if (owner == null || action.getOwner().equals(owner)) {
|
||||
matchingActionList.add(action);
|
||||
}
|
||||
}
|
||||
|
||||
return matchingActionList;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all actions for the given owner.
|
||||
* @param owner owner of the actions
|
||||
* @return array of actions; zero length array is returned if no
|
||||
* action exists with the given name
|
||||
*/
|
||||
public synchronized List<DockingActionIf> getActions(String owner) {
|
||||
List<DockingActionIf> list = getUniqueActionList(owner);
|
||||
return list;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a list of all actions in the tool.
|
||||
* @return list of PluginAction objects
|
||||
*/
|
||||
public List<DockingActionIf> getAllActions() {
|
||||
return getUniqueActionList(null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the keybindings for each action so that they are still registered
|
||||
* as being used; otherwise the options will be removed because they
|
||||
* are noted as not being used.
|
||||
*
|
||||
*/
|
||||
public synchronized void restoreKeyBindings() {
|
||||
keyBindingOptions = tool.getOptions(DockingToolConstants.KEY_BINDINGS);
|
||||
List<DockingActionIf> actions = getAllActions();
|
||||
for (DockingActionIf action : actions) {
|
||||
if (!action.isKeyBindingManaged()) {
|
||||
continue;
|
||||
}
|
||||
KeyStroke ks = action.getKeyBinding();
|
||||
KeyStroke newKs = keyBindingOptions.getKeyStroke(action.getFullName(), ks);
|
||||
if (ks != newKs) {
|
||||
action.setUnvalidatedKeyBindingData(new KeyBindingData(newKs));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the actions for the given provider and remove them from the
|
||||
* actionMap; call the window manager to remove the provider.
|
||||
* @param provider provider to be removed
|
||||
*/
|
||||
public void removeComponent(ComponentProvider provider) {
|
||||
Iterator<DockingActionIf> iterator = winMgr.getComponentActions(provider);
|
||||
while (iterator.hasNext()) {
|
||||
DockingActionIf action = iterator.next();
|
||||
String name = action.getFullName();
|
||||
List<DockingActionIf> actionList = actionMap.get(name);
|
||||
if (actionList != null && actionList.remove(action) && actionList.isEmpty()) {
|
||||
actionMap.remove(name);
|
||||
}
|
||||
}
|
||||
winMgr.removeComponent(provider);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void propertyChange(PropertyChangeEvent evt) {
|
||||
if (evt.getPropertyName().equals(DockingActionIf.KEYBINDING_DATA_PROPERTY)) {
|
||||
DockingAction action = (DockingAction) evt.getSource();
|
||||
if (!action.isKeyBindingManaged()) {
|
||||
tool.setConfigChanged(true);
|
||||
return;
|
||||
}
|
||||
KeyBindingData keyBindingData = (KeyBindingData) evt.getNewValue();
|
||||
KeyStroke newKeyStroke = keyBindingData.getKeyBinding();
|
||||
Options opt = tool.getOptions(DockingToolConstants.KEY_BINDINGS);
|
||||
KeyStroke optKeyStroke = opt.getKeyStroke(action.getFullName(), null);
|
||||
if (newKeyStroke == null) {
|
||||
opt.removeOption(action.getFullName());
|
||||
}
|
||||
else if (!newKeyStroke.equals(optKeyStroke)) {
|
||||
opt.setKeyStroke(action.getFullName(), newKeyStroke);
|
||||
tool.setConfigChanged(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -281,8 +281,8 @@ public class ToolScreenShots extends GhidraScreenShotGenerator {
|
|||
|
||||
tool = env.launchDefaultTool();
|
||||
DockingWindowManager windowManager = tool.getWindowManager();
|
||||
DockingActionManager actionMgr =
|
||||
(DockingActionManager) getInstanceField("actionManager", windowManager);
|
||||
ActionToGuiMapper actionMgr =
|
||||
(ActionToGuiMapper) getInstanceField("actionManager", windowManager);
|
||||
|
||||
DockingActionIf action = getAction(tool, "FunctionPlugin", "Delete Function");
|
||||
final KeyEntryDialog keyEntryDialog = new KeyEntryDialog(action, actionMgr);
|
||||
|
|
Loading…
Reference in a new issue