GT-2925 - Key Bindings - Support Window Menu Provider Key Bindings -

Step 5 - cleanup of old key binding support constructor parameter; start
of cleanup of DockingActionProviderIf
This commit is contained in:
dragonmacher 2019-06-27 14:06:47 -04:00
parent ff4b3736b9
commit 115243801e
73 changed files with 574 additions and 682 deletions

View File

@ -22,8 +22,7 @@ import javax.swing.KeyStroke;
import docking.ActionContext;
import docking.DockingUtils;
import docking.action.DockingAction;
import docking.action.KeyBindingData;
import docking.action.*;
import ghidra.app.plugin.core.navigation.FindAppliedDataTypesService;
import ghidra.app.plugin.core.navigation.locationreferences.ReferenceUtils;
import ghidra.framework.plugintool.PluginTool;
@ -44,7 +43,7 @@ public abstract class AbstractFindReferencesDataTypeAction extends DockingAction
protected AbstractFindReferencesDataTypeAction(PluginTool tool, String name, String owner,
KeyStroke defaultKeyStroke) {
super(name, owner);
super(name, owner, KeyBindingType.SHARED);
this.tool = tool;
setHelpLocation(new HelpLocation("LocationReferencesPlugin", "Data_Types"));
@ -69,11 +68,6 @@ public abstract class AbstractFindReferencesDataTypeAction extends DockingAction
setKeyBindingData(new KeyBindingData(keyStroke));
}
@Override
public boolean usesSharedKeyBinding() {
return true;
}
@Override
public boolean isEnabledForContext(ActionContext context) {
DataType dataType = getDataType(context);

View File

@ -1,6 +1,5 @@
/* ###
* IP: GHIDRA
* REVIEWED: YES
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -16,28 +15,28 @@
*/
package ghidra.app.context;
import java.util.Set;
import docking.ActionContext;
import docking.action.DockingAction;
import docking.action.KeyBindingType;
public abstract class ListingContextAction extends DockingAction {
public ListingContextAction(String name, String owner) {
this(name, owner, true);
}
public ListingContextAction(String name, String owner, boolean isKeyBindingManaged) {
super(name, owner, isKeyBindingManaged);
public ListingContextAction(String name, String owner) {
super(name, owner);
}
public ListingContextAction(String name, String owner, KeyBindingType kbType) {
super(name, owner, kbType);
}
@Override
public boolean isEnabledForContext(ActionContext context) {
if (!(context instanceof ListingActionContext)) {
return false;
}
return isEnabledForContext((ListingActionContext)context);
return isEnabledForContext((ListingActionContext) context);
}
@Override
@ -45,38 +44,38 @@ public abstract class ListingContextAction extends DockingAction {
if (!(context instanceof ListingActionContext)) {
return false;
}
return isValidContext((ListingActionContext)context);
return isValidContext((ListingActionContext) context);
}
@Override
public boolean isAddToPopup(ActionContext context) {
if (!(context instanceof ListingActionContext)) {
return false;
}
return isAddToPopup((ListingActionContext)context);
return isAddToPopup((ListingActionContext) context);
}
@Override
public void actionPerformed(ActionContext context) {
actionPerformed((ListingActionContext)context);
actionPerformed((ListingActionContext) context);
}
protected boolean isAddToPopup(ListingActionContext context) {
return isEnabledForContext( context );
return isEnabledForContext(context);
}
protected boolean isValidContext(ListingActionContext context) {
return true;
}
protected boolean isEnabledForContext(ListingActionContext context) {
return true;
}
protected void actionPerformed(ListingActionContext context) {
// clients need to override this method
}
@Override
public boolean shouldAddToWindow(boolean isMainWindow, Set<Class<?>> contextTypes) {
for (Class<?> class1 : contextTypes) {

View File

@ -21,8 +21,7 @@ import java.util.List;
import javax.swing.Icon;
import docking.ActionContext;
import docking.action.DockingAction;
import docking.action.MenuData;
import docking.action.*;
import ghidra.app.CorePluginPackage;
import ghidra.app.context.ListingActionContext;
import ghidra.app.plugin.PluginCategoryNames;
@ -122,28 +121,18 @@ public class CallTreePlugin extends ProgramPlugin {
// use the name of the provider so that the shared key binding data will get used
String actionName = CallTreeProvider.TITLE;
showCallTreeFromMenuAction = new DockingAction(actionName, getName()) {
showCallTreeFromMenuAction =
new DockingAction(actionName, getName(), KeyBindingType.SHARED) {
@Override
public void actionPerformed(ActionContext context) {
showOrCreateNewCallTree(currentLocation);
}
@Override
public void actionPerformed(ActionContext context) {
showOrCreateNewCallTree(currentLocation);
}
@Override
public boolean isAddToPopup(ActionContext context) {
return (context instanceof ListingActionContext);
}
@Override
public boolean isKeyBindingManaged() {
return false;
}
@Override
public boolean usesSharedKeyBinding() {
return true;
}
};
@Override
public boolean isAddToPopup(ActionContext context) {
return (context instanceof ListingActionContext);
}
};
showCallTreeFromMenuAction.setPopupMenuData(new MenuData(
new String[] { "References", "Show Call Trees" }, PROVIDER_ICON, "ShowReferencesTo"));

View File

@ -15,8 +15,6 @@
*/
package ghidra.app.plugin.core.codebrowser.actions;
import java.util.Set;
import docking.ActionContext;
@ -24,21 +22,17 @@ import docking.action.DockingAction;
import ghidra.app.plugin.core.codebrowser.CodeViewerActionContext;
public abstract class CodeViewerContextAction extends DockingAction {
public CodeViewerContextAction(String name, String owner) {
this(name, owner, true);
}
public CodeViewerContextAction(String name, String owner, boolean isKeyBindingManaged) {
super(name, owner, isKeyBindingManaged);
public CodeViewerContextAction(String name, String owner) {
super(name, owner);
}
@Override
public boolean isEnabledForContext(ActionContext context) {
if (!(context instanceof CodeViewerActionContext)) {
return false;
}
return isEnabledForContext((CodeViewerActionContext)context);
return isEnabledForContext((CodeViewerActionContext) context);
}
@Override
@ -46,26 +40,25 @@ public abstract class CodeViewerContextAction extends DockingAction {
if (!(context instanceof CodeViewerActionContext)) {
return false;
}
return isValidContext((CodeViewerActionContext)context);
return isValidContext((CodeViewerActionContext) context);
}
@Override
public boolean isAddToPopup(ActionContext context) {
if (!(context instanceof CodeViewerActionContext)) {
return false;
}
return isAddToPopup((CodeViewerActionContext)context);
return isAddToPopup((CodeViewerActionContext) context);
}
@Override
public void actionPerformed(ActionContext context) {
actionPerformed((CodeViewerActionContext)context);
actionPerformed((CodeViewerActionContext) context);
}
protected boolean isAddToPopup(CodeViewerActionContext context) {
return isEnabledForContext( context );
return isEnabledForContext(context);
}
protected boolean isValidContext(CodeViewerActionContext context) {
return true;
@ -76,9 +69,9 @@ public abstract class CodeViewerContextAction extends DockingAction {
}
protected void actionPerformed(CodeViewerActionContext context) {
}
@Override
public boolean shouldAddToWindow(boolean isMainWindow, Set<Class<?>> contextTypes) {
for (Class<?> class1 : contextTypes) {

View File

@ -15,15 +15,14 @@
*/
package ghidra.app.plugin.core.compositeeditor;
import ghidra.framework.plugintool.Plugin;
import ghidra.framework.plugintool.PluginTool;
import ghidra.util.HelpLocation;
import java.awt.event.ActionListener;
import javax.swing.*;
import docking.action.*;
import ghidra.framework.plugintool.Plugin;
import ghidra.framework.plugintool.PluginTool;
import ghidra.util.HelpLocation;
/**
* CompositeEditorAction is an abstract class that should be extended for any
@ -45,13 +44,14 @@ abstract public class CompositeEditorTableAction extends DockingAction implement
public static final String EDIT_ACTION_PREFIX = "Editor: ";
/**
* Defines an <code>Action</code> object with the specified
* description string and a the specified icon.
*/
public CompositeEditorTableAction(CompositeEditorProvider provider, String name, String group,
String[] popupPath, String[] menuPath, ImageIcon icon) {
super(name, provider.plugin.getName());
this(provider, name, group, popupPath, menuPath, icon, KeyBindingType.INDIVIDUAL);
}
public CompositeEditorTableAction(CompositeEditorProvider provider, String name, String group,
String[] popupPath, String[] menuPath, ImageIcon icon, KeyBindingType kbType) {
super(name, provider.plugin.getName(), kbType);
this.provider = provider;
model = provider.getModel();
if (menuPath != null) {
@ -70,9 +70,6 @@ abstract public class CompositeEditorTableAction extends DockingAction implement
setHelpLocation(new HelpLocation(provider.getHelpTopic(), helpAnchor));
}
/* (non-Javadoc)
* @see ghidra.framework.plugintool.PluginAction#dispose()
*/
@Override
public void dispose() {
model.removeCompositeEditorModelListener(this);
@ -93,64 +90,53 @@ abstract public class CompositeEditorTableAction extends DockingAction implement
}
}
@Override
abstract public void adjustEnablement();
public String getHelpName() {
String actionName = getName();
if (actionName.startsWith(CompositeEditorTableAction.EDIT_ACTION_PREFIX)) {
actionName = actionName.substring(CompositeEditorTableAction.EDIT_ACTION_PREFIX.length());
actionName =
actionName.substring(CompositeEditorTableAction.EDIT_ACTION_PREFIX.length());
}
return actionName;
}
/* (non-Javadoc)
* @see ghidra.app.plugin.stackeditor.EditorModelListener#selectionChanged()
*/
@Override
public void selectionChanged() {
adjustEnablement();
}
/* (non-Javadoc)
* @see ghidra.app.plugin.stackeditor.EditorModelListener#editStateChanged(int)
*/
public void editStateChanged(int i) {
adjustEnablement();
}
/* (non-Javadoc)
* @see ghidra.app.plugin.compositeeditor.CompositeEditorModelListener#compositeEditStateChanged(int)
*/
@Override
public void compositeEditStateChanged(int type) {
adjustEnablement();
}
/* (non-Javadoc)
* @see ghidra.app.plugin.compositeeditor.CompositeEditorModelListener#endFieldEditing()
*/
@Override
public void endFieldEditing() {
adjustEnablement();
}
/* (non-Javadoc)
* @see ghidra.app.plugin.compositeeditor.CompositeEditorModelListener#componentDataChanged()
*/
@Override
public void componentDataChanged() {
adjustEnablement();
}
/* (non-Javadoc)
* @see ghidra.app.plugin.compositeeditor.CompositeEditorModelListener#compositeInfoChanged()
*/
@Override
public void compositeInfoChanged() {
adjustEnablement();
}
/* (non-Javadoc)
* @see ghidra.app.plugin.compositeeditor.CompositeEditorModelListener#statusChanged(java.lang.String, boolean)
*/
@Override
public void statusChanged(String message, boolean beep) {
// we are an action; don't care about status messages
}
@Override
public void showUndefinedStateChanged(boolean showUndefinedBytes) {
adjustEnablement();
}

View File

@ -19,6 +19,7 @@ import javax.swing.KeyStroke;
import docking.ActionContext;
import docking.action.KeyBindingData;
import docking.action.KeyBindingType;
import ghidra.program.model.data.CycleGroup;
/**
@ -32,7 +33,7 @@ public class CycleGroupAction extends CompositeEditorTableAction {
public CycleGroupAction(CompositeEditorProvider provider, CycleGroup cycleGroup) {
super(provider, cycleGroup.getName(), GROUP_NAME,
new String[] { "Cycle", cycleGroup.getName() },
new String[] { "Cycle", cycleGroup.getName() }, null);
new String[] { "Cycle", cycleGroup.getName() }, null, KeyBindingType.SHARED);
this.cycleGroup = cycleGroup;
initKeyStroke(cycleGroup.getDefaultKeyStroke());
@ -46,11 +47,6 @@ public class CycleGroupAction extends CompositeEditorTableAction {
setKeyBindingData(new KeyBindingData(keyStroke));
}
@Override
public boolean usesSharedKeyBinding() {
return true;
}
public CycleGroup getCycleGroup() {
return cycleGroup;
}

View File

@ -20,8 +20,7 @@ import java.awt.event.KeyEvent;
import javax.swing.KeyStroke;
import docking.ActionContext;
import docking.action.DockingAction;
import docking.action.KeyBindingData;
import docking.action.*;
import ghidra.app.context.ListingActionContext;
import ghidra.app.util.datatype.DataTypeSelectionDialog;
import ghidra.framework.plugintool.PluginTool;
@ -43,7 +42,7 @@ public class ChooseDataTypeAction extends DockingAction {
private final static String ACTION_NAME = "Choose Data Type";
public ChooseDataTypeAction(DataPlugin plugin) {
super(ACTION_NAME, plugin.getName(), false);
super(ACTION_NAME, plugin.getName(), KeyBindingType.SHARED);
this.plugin = plugin;
initKeyStroke(KEY_BINDING);
@ -57,11 +56,6 @@ public class ChooseDataTypeAction extends DockingAction {
setKeyBindingData(new KeyBindingData(keyStroke));
}
@Override
public boolean usesSharedKeyBinding() {
return true;
}
@Override
public void actionPerformed(ActionContext context) {
ListingActionContext programActionContext =

View File

@ -44,7 +44,7 @@ class CreateArrayAction extends DockingAction {
private DataPlugin plugin;
public CreateArrayAction(DataPlugin plugin) {
super("Define Array", plugin.getName(), false);
super("Define Array", plugin.getName(), KeyBindingType.SHARED);
this.plugin = plugin;
setPopupMenuData(new MenuData(CREATE_ARRAY_POPUP_MENU, "BasicData"));
@ -61,11 +61,6 @@ class CreateArrayAction extends DockingAction {
setKeyBindingData(new KeyBindingData(keyStroke));
}
@Override
public boolean usesSharedKeyBinding() {
return true;
}
@Override
public void actionPerformed(ActionContext context) {
ListingActionContext programActionContext =

View File

@ -18,8 +18,7 @@ package ghidra.app.plugin.core.data;
import javax.swing.KeyStroke;
import docking.ActionContext;
import docking.action.DockingAction;
import docking.action.KeyBindingData;
import docking.action.*;
import ghidra.app.cmd.data.*;
import ghidra.app.context.ListingActionContext;
import ghidra.framework.cmd.BackgroundCommand;
@ -41,7 +40,7 @@ public class CycleGroupAction extends DockingAction {
private CycleGroup cycleGroup;
CycleGroupAction(CycleGroup group, DataPlugin plugin) {
super(group.getName(), plugin.getName(), false);
super(group.getName(), plugin.getName(), KeyBindingType.SHARED);
this.plugin = plugin;
this.cycleGroup = group;
@ -56,11 +55,6 @@ public class CycleGroupAction extends DockingAction {
setKeyBindingData(new KeyBindingData(keyStroke));
}
@Override
public boolean usesSharedKeyBinding() {
return true;
}
@Override
public void dispose() {
cycleGroup = null;

View File

@ -17,8 +17,7 @@ package ghidra.app.plugin.core.data;
import javax.swing.KeyStroke;
import docking.action.KeyBindingData;
import docking.action.MenuData;
import docking.action.*;
import ghidra.app.context.ListingActionContext;
import ghidra.app.context.ListingContextAction;
import ghidra.program.model.data.*;
@ -45,7 +44,7 @@ class DataAction extends ListingContextAction {
* @param plugin the plugin that owns this action
*/
public DataAction(String name, String group, DataType dataType, DataPlugin plugin) {
super(name, plugin.getName(), false);
super(name, plugin.getName(), KeyBindingType.SHARED);
this.plugin = plugin;
this.dataType = dataType;
@ -54,11 +53,6 @@ class DataAction extends ListingContextAction {
initKeyStroke(getDefaultKeyStroke());
}
@Override
public boolean usesSharedKeyBinding() {
return true;
}
protected KeyStroke getDefaultKeyStroke() {
return null; // we have no default, but our subclasses may
}

View File

@ -123,7 +123,7 @@ class NextPreviousDataTypeAction extends MultiActionDockingAction {
private class NavigationAction extends DockingAction {
private NavigationAction(DataType dt) {
super("DataTypeNavigationAction_" + ++navigationActionIdCount, owner, false);
super("DataTypeNavigationAction_" + ++navigationActionIdCount, owner);
setMenuBarData(new MenuData(new String[] { dt.getDisplayName() }));
setEnabled(true);

View File

@ -25,7 +25,7 @@ import javax.swing.event.DocumentListener;
import docking.ActionContext;
import docking.DialogComponentProvider;
import docking.action.*;
import docking.action.DockingAction;
import docking.widgets.checkbox.GCheckBox;
import docking.widgets.label.GDLabel;
import docking.widgets.label.GLabel;
@ -40,11 +40,13 @@ import ghidra.program.model.mem.MemoryBlock;
import ghidra.program.util.ProgramSelection;
import ghidra.util.HelpLocation;
import ghidra.util.table.*;
import ghidra.util.table.actions.MakeProgramSelectionAction;
import ghidra.util.task.Task;
import resources.ResourceManager;
public class AddressTableDialog extends DialogComponentProvider {
static final int DEFAULT_MINIMUM_TABLE_SIZE = 3;
private static final int DEFAULT_MINIMUM_TABLE_SIZE = 3;
private static final String DIALOG_NAME = "Search For Address Tables";
private JPanel mainPanel;
private String[] blockData;
private AutoTableDisassemblerPlugin plugin;
@ -67,7 +69,7 @@ public class AddressTableDialog extends DialogComponentProvider {
private GhidraThreadedTablePanel<AddressTable> resultsTablePanel;
public AddressTableDialog(AutoTableDisassemblerPlugin plugin) {
super("Search For Address Tables", false, true, true, true);
super(DIALOG_NAME, false, true, true, true);
setHelpLocation(
new HelpLocation(HelpTopics.SEARCH, AutoTableDisassemblerPlugin.SEARCH_ACTION_NAME));
this.plugin = plugin;
@ -125,8 +127,7 @@ public class AddressTableDialog extends DialogComponentProvider {
JPanel makeTablePanel = new JPanel(new FlowLayout());
makeTableButton = new JButton("Make Table");
makeTableButton.setToolTipText(
"Make a table of addresses at the selected location(s).");
makeTableButton.setToolTipText("Make a table of addresses at the selected location(s).");
makeTablePanel.add(makeTableButton);
makeTableButton.setEnabled(false);
makeTableButton.addActionListener(e -> plugin.makeTable(resultsTable.getSelectedRows()));
@ -175,8 +176,7 @@ public class AddressTableDialog extends DialogComponentProvider {
skipLabel = new GDLabel("Skip Length: ");
skipField = new JTextField(5);
skipField.setName("Skip");
skipLabel.setToolTipText(
"Number of bytes to skip between found addresses in a table.");
skipLabel.setToolTipText("Number of bytes to skip between found addresses in a table.");
skipField.setText("0");
JPanel alignPanel = new JPanel(new FlowLayout(FlowLayout.RIGHT));
@ -194,8 +194,7 @@ public class AddressTableDialog extends DialogComponentProvider {
selectionButton = new GCheckBox("Search Selection");
selectionButton.setSelected(false);
selectionButton.setToolTipText(
"If checked, search only the current selection.");
selectionButton.setToolTipText("If checked, search only the current selection.");
JPanel searchOptionsWestPanel = new JPanel(new GridLayout(2, 1));
searchOptionsWestPanel.add(selectionButton);
@ -233,8 +232,7 @@ public class AddressTableDialog extends DialogComponentProvider {
"Label the top of the address table and all members of the table.");
offsetLabel = new GDLabel("Offset: ");
offsetLabel.setToolTipText(
"Offset from the beginning of the selected table(s)");
offsetLabel.setToolTipText("Offset from the beginning of the selected table(s)");
offsetLabel.setEnabled(false);
JLabel viewOffsetLabel = new GDLabel(" ");
@ -242,8 +240,7 @@ public class AddressTableDialog extends DialogComponentProvider {
viewOffset = new HintTextField(20);
viewOffset.setName("viewOffset");
viewOffset.setToolTipText(
"Address of the selected table starting at the given offset");
viewOffset.setToolTipText("Address of the selected table starting at the given offset");
viewOffset.setHintText("table start address");
viewOffset.showHint();
@ -526,20 +523,13 @@ public class AddressTableDialog extends DialogComponentProvider {
}
private void createAction() {
DockingAction selectAction =
new DockingAction("Make Selection", "AsciiFinderDialog", false) {
@Override
public void actionPerformed(ActionContext context) {
makeSelection();
}
};
selectAction.setDescription("Make a selection using selected rows");
selectAction.setEnabled(true);
Icon icon = ResourceManager.loadImage("images/text_align_justify.png");
selectAction.setPopupMenuData(new MenuData(new String[] { "Make Selection" }, icon));
selectAction.setToolBarData(new ToolBarData(icon));
selectAction.setHelpLocation(
new HelpLocation(HelpTopics.SEARCH, "Search_Make_Selection_Address_Tables"));
DockingAction selectAction = new MakeProgramSelectionAction(DIALOG_NAME, resultsTable) {
@Override
protected void makeSelection(ActionContext context) {
doMakeSelection();
}
};
selectionNavigationAction = new SelectionNavigationAction(plugin, resultsTable);
selectionNavigationAction.setHelpLocation(
@ -548,7 +538,7 @@ public class AddressTableDialog extends DialogComponentProvider {
addAction(selectAction);
}
private void makeSelection() {
private void doMakeSelection() {
Program program = plugin.getProgram();
AddressSet set = new AddressSet();
AutoTableDisassemblerModel model = plugin.getModel();

View File

@ -41,7 +41,7 @@ public class ChooseDataTypeAction extends DockingAction {
private FunctionPlugin plugin;
public ChooseDataTypeAction(FunctionPlugin plugin) {
super(ACTION_NAME, plugin.getName(), false);
super(ACTION_NAME, plugin.getName(), KeyBindingType.SHARED);
this.plugin = plugin;
setHelpLocation(new HelpLocation("DataTypeEditors", "DataTypeSelectionDialog"));
@ -57,11 +57,6 @@ public class ChooseDataTypeAction extends DockingAction {
setKeyBindingData(new KeyBindingData(keyStroke));
}
@Override
public boolean usesSharedKeyBinding() {
return true;
}
@Override
public void actionPerformed(ActionContext actionContext) {
ListingActionContext context = (ListingActionContext) actionContext.getContextObject();

View File

@ -19,8 +19,7 @@ import java.awt.event.KeyEvent;
import javax.swing.KeyStroke;
import docking.action.KeyBindingData;
import docking.action.MenuData;
import docking.action.*;
import docking.widgets.dialogs.NumberInputDialog;
import ghidra.app.context.ListingActionContext;
import ghidra.app.context.ListingContextAction;
@ -37,7 +36,7 @@ class CreateArrayAction extends ListingContextAction {
private FunctionPlugin plugin;
public CreateArrayAction(FunctionPlugin plugin) {
super("Define Array", plugin.getName(), false);
super("Define Array", plugin.getName(), KeyBindingType.SHARED);
this.plugin = plugin;
setPopupMenu(plugin.getDataActionMenuName(null));
@ -54,11 +53,6 @@ class CreateArrayAction extends ListingContextAction {
setKeyBindingData(new KeyBindingData(keyStroke));
}
@Override
public boolean usesSharedKeyBinding() {
return true;
}
private void setPopupMenu(String name) {
setPopupMenuData(new MenuData(
new String[] { FunctionPlugin.SET_DATA_TYPE_PULLRIGHT, "Array..." }, null, "Array"));

View File

@ -17,8 +17,7 @@ package ghidra.app.plugin.core.function;
import javax.swing.KeyStroke;
import docking.action.KeyBindingData;
import docking.action.MenuData;
import docking.action.*;
import ghidra.app.context.ListingActionContext;
import ghidra.app.context.ListingContextAction;
import ghidra.app.util.HelpTopics;
@ -38,7 +37,7 @@ public class CycleGroupAction extends ListingContextAction {
private CycleGroup cycleGroup;
CycleGroupAction(CycleGroup group, FunctionPlugin plugin) {
super(group.getName(), plugin.getName(), false);
super(group.getName(), plugin.getName(), KeyBindingType.SHARED);
this.plugin = plugin;
this.cycleGroup = group;
@ -56,11 +55,6 @@ public class CycleGroupAction extends ListingContextAction {
setKeyBindingData(new KeyBindingData(keyStroke));
}
@Override
public boolean usesSharedKeyBinding() {
return true;
}
private void setPopupMenu(String name, boolean isSignatureAction) {
setPopupMenuData(new MenuData(
new String[] { FunctionPlugin.SET_DATA_TYPE_PULLRIGHT, "Cycle", cycleGroup.getName() },

View File

@ -17,8 +17,7 @@ package ghidra.app.plugin.core.function;
import javax.swing.KeyStroke;
import docking.action.KeyBindingData;
import docking.action.MenuData;
import docking.action.*;
import ghidra.app.context.ListingActionContext;
import ghidra.app.context.ListingContextAction;
import ghidra.program.model.data.DataType;
@ -41,7 +40,7 @@ class DataAction extends ListingContextAction {
}
public DataAction(String name, String group, DataType dataType, FunctionPlugin plugin) {
super(name, plugin.getName(), false);
super(name, plugin.getName(), KeyBindingType.SHARED);
this.group = group;
this.plugin = plugin;
this.dataType = dataType;
@ -52,11 +51,6 @@ class DataAction extends ListingContextAction {
initKeyStroke(getDefaultKeyStroke());
}
@Override
public boolean usesSharedKeyBinding() {
return true;
}
protected KeyStroke getDefaultKeyStroke() {
return null; // we have no default, but our subclasses may
}

View File

@ -15,6 +15,11 @@
*/
package ghidra.app.plugin.core.function;
import java.awt.event.KeyEvent;
import docking.ActionContext;
import docking.action.KeyBindingData;
import docking.action.KeyBindingType;
import ghidra.app.cmd.function.SetVariableCommentCmd;
import ghidra.app.context.ListingActionContext;
import ghidra.app.context.ListingContextAction;
@ -22,26 +27,19 @@ import ghidra.program.model.listing.Function;
import ghidra.program.model.listing.Variable;
import ghidra.program.util.*;
import java.awt.event.KeyEvent;
import docking.ActionContext;
import docking.action.KeyBindingData;
/**
* <CODE>VariableCommentDeleteAction</CODE> allows the user to delete a function variable comment.
*/
class VariableCommentDeleteAction extends ListingContextAction {
/** the plugin associated with this action. */
FunctionPlugin funcPlugin;
/**
* Creates a new action with the given name and associated to the given plugin.
* @param plugin
* the plugin this action is associated with.
*/
* Creates a new action with the given name and associated to the given plugin.
* @param plugin the plugin this action is associated with.
*/
VariableCommentDeleteAction(FunctionPlugin plugin) {
super("Delete Function Variable Comment", plugin.getName(), false);
super("Delete Function Variable Comment", plugin.getName(), KeyBindingType.SHARED);
this.funcPlugin = plugin;
setKeyBindingData(new KeyBindingData(KeyEvent.VK_DELETE, 0));
}
@ -65,7 +63,6 @@ class VariableCommentDeleteAction extends ListingContextAction {
}
}
// ///////////////////////////////////////////////////////////
/**
* Get a variable using the current location.
*

View File

@ -43,19 +43,19 @@ class VariableDeleteAction extends ListingContextAction {
* @param plugin the plugin this action is associated with.
*/
VariableDeleteAction(FunctionPlugin plugin) {
super("Delete Function Variable", plugin.getName(), true);
super("Delete Function Variable", plugin.getName());
this.funcPlugin = plugin;
setPopupMenuPath(false);
setKeyBindingData(new KeyBindingData(KeyEvent.VK_DELETE, 0));
}
private void setPopupMenuPath(boolean isParameter) {
setPopupMenuData(new MenuData(new String[] { FunctionPlugin.VARIABLE_MENU_PULLRIGHT,
"Delete " + (isParameter ? "Parameter" : "Local Variable") }, null,
FunctionPlugin.VARIABLE_MENU_SUBGROUP));
setPopupMenuData(new MenuData(
new String[] { FunctionPlugin.VARIABLE_MENU_PULLRIGHT,
"Delete " + (isParameter ? "Parameter" : "Local Variable") },
null, FunctionPlugin.VARIABLE_MENU_SUBGROUP));
}
@Override

View File

@ -201,7 +201,7 @@ public class FunctionWindowPlugin extends ProgramPlugin implements DomainObjectL
}
private void addCompareAction() {
compareAction = new DockingAction("Compare Selected Functions", getName(), false) {
compareAction = new DockingAction("Compare Selected Functions", getName()) {
@Override
public void actionPerformed(ActionContext context) {
compareSelectedFunctions();

View File

@ -16,13 +16,10 @@
package ghidra.app.plugin.core.instructionsearch.ui;
import java.awt.Font;
import java.util.List;
import javax.swing.JToolBar;
import javax.swing.table.TableCellRenderer;
import docking.ActionContext;
import docking.action.DockingActionIf;
import docking.widgets.table.GTable;
import ghidra.app.plugin.core.instructionsearch.model.*;
import ghidra.util.table.GhidraTable;
@ -109,17 +106,6 @@ public abstract class AbstractInstructionTable extends GhidraTable {
return (InstructionTableDataObject) getModel().getValueAt(row, col);
}
/**
* Must invoke the parent implementation of this to have the context menu
* created.
*
*/
@Override
public List<DockingActionIf> getDockingActions(ActionContext context) {
List<DockingActionIf> list = super.getDockingActions(context);
return list;
}
/**
* Must override so it doesn't return an instance of the base
* {@link TableCellRenderer}, which will override our changes in the

View File

@ -22,7 +22,6 @@ import java.util.List;
import javax.swing.*;
import docking.ActionContext;
import docking.DockingWindowManager;
import docking.action.DockingActionIf;
import docking.widgets.EmptyBorderButton;
@ -102,7 +101,7 @@ public class InstructionTable extends AbstractInstructionTable {
* (which is all of them).
*/
@Override
public List<DockingActionIf> getDockingActions(ActionContext context) {
public List<DockingActionIf> getDockingActions() {
return new ArrayList<>();
}

View File

@ -134,14 +134,12 @@ public class PreviewTable extends AbstractInstructionTable {
/**
* Adds custom context-sensitive menus to the table. This does NOT modify
* any existing menus; it simply adds to them.
*
* @param context the action context
*/
@Override
public List<DockingActionIf> getDockingActions(ActionContext context) {
public List<DockingActionIf> getDockingActions() {
// Invoke the base class method to add default menu options.
List<DockingActionIf> list = super.getDockingActions(context);
List<DockingActionIf> list = super.getDockingActions();
// And now add our own.
addCustomMenuItems(list);
@ -489,7 +487,7 @@ public class PreviewTable extends AbstractInstructionTable {
*/
private void createCopyInstructionWithCommentsAction(String owner) {
copyInstructionWithCommentsAction =
new DockingAction("Selected Instructions (with comments)", owner, false) {
new DockingAction("Selected Instructions (with comments)", owner) {
@Override
public void actionPerformed(ActionContext context) {
int[] selectedRows = PreviewTable.this.getSelectedRows();
@ -520,7 +518,7 @@ public class PreviewTable extends AbstractInstructionTable {
* as shown in the table.
*/
private void createCopyInstructionAction(String owner) {
copyInstructionAction = new DockingAction("Selected Instructions", owner, false) {
copyInstructionAction = new DockingAction("Selected Instructions", owner) {
@Override
public void actionPerformed(ActionContext context) {
int[] selectedRows = PreviewTable.this.getSelectedRows();
@ -541,7 +539,7 @@ public class PreviewTable extends AbstractInstructionTable {
* rows, as shown in the table, with no spaces.
*/
private void createCopyNoSpacesAction(String owner) {
copyNoSpacesAction = new DockingAction("Selected instructions (no spaces)", owner, false) {
copyNoSpacesAction = new DockingAction("Selected instructions (no spaces)", owner) {
@Override
public void actionPerformed(ActionContext context) {
int[] selectedRows = PreviewTable.this.getSelectedRows();

View File

@ -368,7 +368,7 @@ public class NextPrevAddressPlugin extends Plugin {
private NavigationAction(Navigatable navigatable, LocationMemento location, boolean isNext,
NavigationHistoryService service, CodeUnitFormat formatter) {
super("NavigationAction: " + ++idCount, NextPrevAddressPlugin.this.getName(), false);
super("NavigationAction: " + ++idCount, NextPrevAddressPlugin.this.getName());
this.location = location;
this.isNext = isNext;
this.service = service;

View File

@ -17,8 +17,7 @@ package ghidra.app.plugin.core.navigation.locationreferences;
import javax.swing.KeyStroke;
import docking.action.KeyBindingData;
import docking.action.MenuData;
import docking.action.*;
import ghidra.app.actions.AbstractFindReferencesDataTypeAction;
import ghidra.app.context.ListingActionContext;
import ghidra.app.context.ListingContextAction;
@ -34,7 +33,7 @@ public class FindReferencesToAction extends ListingContextAction {
private int subGroupPosition;
public FindReferencesToAction(LocationReferencesPlugin plugin, int subGroupPosition) {
super(AbstractFindReferencesDataTypeAction.NAME, plugin.getName(), false);
super(AbstractFindReferencesDataTypeAction.NAME, plugin.getName(), KeyBindingType.SHARED);
this.plugin = plugin;
this.subGroupPosition = subGroupPosition;
@ -54,11 +53,6 @@ public class FindReferencesToAction extends ListingContextAction {
setKeyBindingData(new KeyBindingData(keyStroke));
}
@Override
public boolean usesSharedKeyBinding() {
return true;
}
@Override
public void actionPerformed(ListingActionContext context) {
plugin.displayProvider(context);

View File

@ -15,6 +15,7 @@
*/
package ghidra.app.plugin.core.navigation.locationreferences;
import docking.action.KeyBindingType;
import docking.action.MenuData;
import ghidra.app.context.ListingActionContext;
import ghidra.app.context.ListingContextAction;
@ -35,7 +36,7 @@ public class FindReferencesToAddressAction extends ListingContextAction {
private LocationReferencesPlugin plugin;
public FindReferencesToAddressAction(LocationReferencesPlugin plugin, int subGroupPosition) {
super("Show References to Address", plugin.getName(), false);
super("Show References to Address", plugin.getName(), KeyBindingType.SHARED);
this.plugin = plugin;

View File

@ -41,6 +41,7 @@ import ghidra.util.HelpLocation;
import ghidra.util.table.GhidraTable;
import ghidra.util.table.SelectionNavigationAction;
import ghidra.util.table.actions.DeleteTableRowAction;
import ghidra.util.table.actions.MakeProgramSelectionAction;
import ghidra.util.task.SwingUpdateManager;
import resources.Icons;
import resources.ResourceManager;
@ -51,7 +52,6 @@ import resources.ResourceManager;
public class LocationReferencesProvider extends ComponentProviderAdapter
implements DomainObjectListener, NavigatableRemovalListener {
private static Icon SELECT_ICON = ResourceManager.loadImage("images/text_align_justify.png");
private static Icon HIGHLIGHT_ICON = ResourceManager.loadImage("images/tag_yellow.png");
private static Icon HOME_ICON = ResourceManager.loadImage("images/go-home.png");
private static Icon REFRESH_ICON = Icons.REFRESH_ICON;
@ -153,7 +153,7 @@ public class LocationReferencesProvider extends ComponentProviderAdapter
referencesPanel.reloadModel();
}
private void makeSelection() {
private void doMakeSelection() {
locationReferencesPlugin.firePluginEvent(new ProgramSelectionPluginEvent(
locationReferencesPlugin.getName(), referencesPanel.getSelection(), program));
}
@ -176,7 +176,10 @@ public class LocationReferencesProvider extends ComponentProviderAdapter
setTitle(generateTitle());
}
/** Sets the new LocationDescriptor and updates the providers table contents. */
/**
* Sets the new LocationDescriptor and updates the providers table contents.
* @param locationDescriptor the new descriptor
*/
void update(LocationDescriptor locationDescriptor) {
setLocationDescriptor(locationDescriptor, navigatable);
updateManager.updateNow();
@ -246,30 +249,12 @@ public class LocationReferencesProvider extends ComponentProviderAdapter
homeAction.setToolBarData(new ToolBarData(HOME_ICON));
updateHomeActionState();
selectionAction = new DockingAction("Make Selection", locationReferencesPlugin.getName()) {
selectionAction = new MakeProgramSelectionAction(getName(), referencesPanel.getTable()) {
@Override
public void actionPerformed(ActionContext context) {
makeSelection();
}
@Override
public boolean isEnabledForContext(ActionContext context) {
return referencesPanel.getTable().getSelectedRowCount() > 0;
}
@Override
public boolean isAddToPopup(ActionContext context) {
if (referencesPanel.getTable().getClass().isInstance(context.getContextObject())) {
return super.isEnabledForContext(context);
}
return false;
protected void makeSelection(ActionContext context) {
doMakeSelection();
}
};
selectionAction.setPopupMenuData(
new MenuData(new String[] { "Make Selection" }, SELECT_ICON));
selectionAction.setToolBarData(new ToolBarData(SELECT_ICON));
selectionAction.setDescription("Make a program selection from selected rows in table");
selectionAction.setEnabled(false); // off by default; updated when the user clicks the table
highlightAction = new ToggleDockingAction("Highlight Matches", getName()) {
@Override

View File

@ -15,24 +15,20 @@
*/
package ghidra.app.plugin.core.reloc;
import javax.swing.ImageIcon;
import docking.ActionContext;
import docking.action.*;
import docking.action.DockingAction;
import ghidra.app.CorePluginPackage;
import ghidra.app.events.*;
import ghidra.app.plugin.PluginCategoryNames;
import ghidra.app.services.GoToService;
import ghidra.app.util.HelpTopics;
import ghidra.framework.model.*;
import ghidra.framework.plugintool.*;
import ghidra.framework.plugintool.util.PluginStatus;
import ghidra.program.model.listing.Program;
import ghidra.program.util.ChangeManager;
import ghidra.program.util.ProgramSelection;
import ghidra.util.HelpLocation;
import ghidra.util.table.SelectionNavigationAction;
import resources.ResourceManager;
import ghidra.util.table.actions.MakeProgramSelectionAction;
//@formatter:off
@PluginInfo(
@ -66,27 +62,21 @@ public class RelocationTablePlugin extends Plugin implements DomainObjectListene
}
private void createActions() {
DockingAction programSelectionAction =
new DockingAction("Make Selection", getName(), false) {
DockingAction selectAction =
new MakeProgramSelectionAction(getName(), provider.getTable()) {
@Override
public void actionPerformed(ActionContext context) {
makeSelection();
protected void makeSelection(ActionContext context) {
doMakeSelection();
}
};
programSelectionAction.setDescription("Make a selection using selected rows");
ImageIcon icon = ResourceManager.loadImage("images/text_align_justify.png");
programSelectionAction.setToolBarData(new ToolBarData(icon));
programSelectionAction.setPopupMenuData(
new MenuData(new String[] { "Make Selection" }, icon));
programSelectionAction.setHelpLocation(
new HelpLocation(HelpTopics.SEARCH, "Make_Selection"));
tool.addLocalAction(provider, programSelectionAction);
tool.addLocalAction(provider, selectAction);
DockingAction navigationAction = new SelectionNavigationAction(this, provider.getTable());
tool.addLocalAction(provider, navigationAction);
}
private void makeSelection() {
private void doMakeSelection() {
ProgramSelection selection = provider.getTable().getProgramSelection();
PluginEvent event = new ProgramSelectionPluginEvent(getName(), selection, currentProgram);
firePluginEvent(event);

View File

@ -26,7 +26,8 @@ import java.util.zip.ZipFile;
import javax.swing.KeyStroke;
import docking.*;
import docking.ActionContext;
import docking.DockingUtils;
import docking.action.*;
import docking.actions.KeyBindingUtils;
import docking.widgets.table.GTable;
@ -629,13 +630,11 @@ class GhidraScriptActionManager {
private class RerunLastScriptAction extends DockingAction {
RerunLastScriptAction(String toolbarGroup) {
super(RERUN_LAST_SHARED_ACTION_NAME, plugin.getName(), false);
super(RERUN_LAST_SHARED_ACTION_NAME, plugin.getName(), KeyBindingType.SHARED);
setToolBarData(
new ToolBarData(ResourceManager.loadImage("images/play_again.png"), toolbarGroup));
setDescription("Rerun the last run script");
setEnabled(false);
setHelpLocation(new HelpLocation(plugin.getName(), "Run_Last"));
initKeyStroke(RERUN_LAST_SCRIPT_KEYSTROKE);
@ -649,11 +648,6 @@ class GhidraScriptActionManager {
setKeyBindingData(new KeyBindingData(keyStroke));
}
@Override
public boolean usesSharedKeyBinding() {
return true;
}
@Override
public void actionPerformed(ActionContext context) {
provider.runLastScript();

View File

@ -50,6 +50,7 @@ import ghidra.util.*;
import ghidra.util.exception.AssertException;
import ghidra.util.layout.VerticalLayout;
import ghidra.util.table.*;
import ghidra.util.table.actions.MakeProgramSelectionAction;
import ghidra.util.task.TaskLauncher;
import resources.ResourceManager;
@ -304,19 +305,12 @@ public class StringTableProvider extends ComponentProviderAdapter implements Dom
makeCharArrayAction.setHelpLocation(makeStringHelp);
addLocalAction(makeCharArrayAction);
DockingAction selectAction =
new DockingAction("Make Selection", "AsciiFinderDialog", false) {
@Override
public void actionPerformed(ActionContext context) {
makeSelection();
}
};
selectAction.setDescription("Make a selection using selected rows");
selectAction.setEnabled(true);
Icon icon = ResourceManager.loadImage("images/text_align_justify.png");
selectAction.setToolBarData(new ToolBarData(icon));
selectAction.setPopupMenuData(new MenuData(new String[] { "Make Selection" }, icon));
selectAction.setHelpLocation(new HelpLocation(HelpTopics.SEARCH, "Make_Selection_Strings"));
DockingAction selectAction = new MakeProgramSelectionAction(plugin.getName(), table) {
@Override
protected void makeSelection(ActionContext context) {
doMakeSelection();
}
};
selectionNavigationAction = new SelectionNavigationAction(plugin, table);
selectionNavigationAction.setHelpLocation(
@ -327,7 +321,7 @@ public class StringTableProvider extends ComponentProviderAdapter implements Dom
}
private void makeSelection() {
private void doMakeSelection() {
AddressSet set = new AddressSet();
addToAddressSet(set, table.getSelectedRows());

View File

@ -82,7 +82,7 @@ public class ViewStringsPlugin extends ProgramPlugin implements DomainObjectList
}
private void createActions() {
DockingAction refreshAction = new DockingAction("Refresh Strings", getName(), false) {
DockingAction refreshAction = new DockingAction("Refresh Strings", getName()) {
@Override
public boolean isEnabledForContext(ActionContext context) {
@ -113,7 +113,7 @@ public class ViewStringsPlugin extends ProgramPlugin implements DomainObjectList
linkNavigationAction = new SelectionNavigationAction(this, provider.getTable());
tool.addLocalAction(provider, linkNavigationAction);
showSettingsAction = new DockingAction("Settings...", getName(), false) {
showSettingsAction = new DockingAction("Settings", getName()) {
@Override
public void actionPerformed(ActionContext context) {
try {
@ -133,7 +133,7 @@ public class ViewStringsPlugin extends ProgramPlugin implements DomainObjectList
showSettingsAction.setPopupMenuData(new MenuData(new String[] { "Settings..." }, "R"));
showSettingsAction.setDescription("Shows settings for the selected strings");
showSettingsAction.setHelpLocation(new HelpLocation("DataPlugin", "Data_Settings"));
showDefaultSettingsAction = new DockingAction("Default Settings...", getName(), false) {
showDefaultSettingsAction = new DockingAction("Default Settings", getName()) {
@Override
public void actionPerformed(ActionContext context) {
Data data = provider.getSelectedData();

View File

@ -39,9 +39,6 @@ public class SelectionAction extends SymbolTreeContextAction {
@Override
protected boolean isEnabledForContext(SymbolTreeActionContext context) {
// if (context.getSymbolCount() == 0) {
// return false;
// }
for (Symbol s : context.getSymbols()) {
if (!s.isExternal()) {
return true;

View File

@ -18,8 +18,7 @@ package ghidra.app.plugin.core.symboltree.actions;
import javax.swing.KeyStroke;
import javax.swing.tree.TreePath;
import docking.action.KeyBindingData;
import docking.action.MenuData;
import docking.action.*;
import ghidra.app.actions.AbstractFindReferencesDataTypeAction;
import ghidra.app.nav.Navigatable;
import ghidra.app.plugin.core.navigation.locationreferences.LocationReferencesService;
@ -57,7 +56,7 @@ public class ShowSymbolReferencesAction extends SymbolTreeContextAction {
};
public ShowSymbolReferencesAction(PluginTool tool, String owner) {
super(AbstractFindReferencesDataTypeAction.NAME, owner);
super(AbstractFindReferencesDataTypeAction.NAME, owner, KeyBindingType.SHARED);
this.tool = tool;
setPopupMenuData(new MenuData(new String[] { "Show References to" }, "0Middle"));
@ -76,11 +75,6 @@ public class ShowSymbolReferencesAction extends SymbolTreeContextAction {
setKeyBindingData(new KeyBindingData(keyStroke));
}
@Override
public boolean usesSharedKeyBinding() {
return true;
}
private void installHelpLocation() {
LocationReferencesService locationReferencesService =
tool.getService(LocationReferencesService.class);

View File

@ -1,6 +1,5 @@
/* ###
* IP: GHIDRA
* REVIEWED: YES
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -16,12 +15,12 @@
*/
package ghidra.app.plugin.core.symboltree.actions;
import ghidra.app.plugin.core.symboltree.SymbolTreeActionContext;
import javax.swing.tree.TreePath;
import docking.ActionContext;
import docking.action.DockingAction;
import docking.action.KeyBindingType;
import ghidra.app.plugin.core.symboltree.SymbolTreeActionContext;
public abstract class SymbolTreeContextAction extends DockingAction {
@ -29,6 +28,10 @@ public abstract class SymbolTreeContextAction extends DockingAction {
super(name, owner);
}
public SymbolTreeContextAction(String name, String owner, KeyBindingType kbType) {
super(name, owner, kbType);
}
@Override
public final boolean isEnabledForContext(ActionContext actionContext) {
if (!(actionContext instanceof SymbolTreeActionContext)) {

View File

@ -171,32 +171,31 @@ public class TableComponentProvider<T> extends ComponentProviderAdapter
selectionNavigationAction.setHelpLocation(
new HelpLocation(HelpTopics.SEARCH, "Selection_Navigation"));
DockingAction externalGotoAction =
new DockingAction("Go to External Location", getName(), false) {
@Override
public void actionPerformed(ActionContext context) {
gotoExternalAddress(getSelectedExternalAddress());
}
DockingAction externalGotoAction = new DockingAction("Go to External Location", getName()) {
@Override
public void actionPerformed(ActionContext context) {
gotoExternalAddress(getSelectedExternalAddress());
}
@Override
public boolean isEnabledForContext(ActionContext context) {
return getSelectedExternalAddress() != null &&
tool.getService(GoToService.class) != null;
}
@Override
public boolean isEnabledForContext(ActionContext context) {
return getSelectedExternalAddress() != null &&
tool.getService(GoToService.class) != null;
}
private Address getSelectedExternalAddress() {
if (table.getSelectedRowCount() != 1) {
return null;
}
ProgramSelection selection = table.getProgramSelection();
Program modelProgram = model.getProgram();
if (modelProgram == null || selection.getNumAddresses() != 1) {
return null;
}
Address addr = selection.getMinAddress();
return addr.isExternalAddress() ? addr : null;
private Address getSelectedExternalAddress() {
if (table.getSelectedRowCount() != 1) {
return null;
}
};
ProgramSelection selection = table.getProgramSelection();
Program modelProgram = model.getProgram();
if (modelProgram == null || selection.getNumAddresses() != 1) {
return null;
}
Address addr = selection.getMinAddress();
return addr.isExternalAddress() ? addr : null;
}
};
externalGotoAction.setDescription("Go to an external location");
externalGotoAction.setEnabled(false);

View File

@ -55,11 +55,6 @@ import ghidra.util.task.SwingUpdateManager;
public class TableServicePlugin extends ProgramPlugin
implements TableService, DomainObjectListener {
static final String MAKE_SELECTION_ACTION_NAME = "Make Selection";
static final String REMOVE_ITEMS_ACTION_NAME = "Remove Items";
static final String SHARED_ACTION_OWNER_SUFFIX = " (Tool)";
private SwingUpdateManager updateMgr;
private Map<Program, List<TableComponentProvider<?>>> programMap = new HashMap<>();

View File

@ -25,7 +25,7 @@ import javax.swing.*;
import javax.swing.table.TableCellRenderer;
import docking.*;
import docking.action.*;
import docking.action.DockingAction;
import docking.widgets.table.*;
import docking.widgets.table.threaded.ThreadedTableModel;
import ghidra.app.nav.Navigatable;
@ -41,8 +41,8 @@ import ghidra.util.SystemUtilities;
import ghidra.util.datastruct.WeakDataStructureFactory;
import ghidra.util.datastruct.WeakSet;
import ghidra.util.table.*;
import ghidra.util.table.actions.MakeProgramSelectionAction;
import ghidra.util.task.TaskMonitor;
import resources.ResourceManager;
import utility.function.Callback;
/**
@ -157,23 +157,13 @@ public class TableChooserDialog extends DialogComponentProvider
private void createActions() {
String owner = getClass().getSimpleName();
DockingAction selectAction = new DockingAction("Make Selection", owner, false) {
@Override
public void actionPerformed(ActionContext context) {
makeSelection();
}
DockingAction selectAction = new MakeProgramSelectionAction(owner, table) {
@Override
public boolean isEnabledForContext(ActionContext context) {
return table.getSelectedRowCount() != 0;
protected void makeSelection(ActionContext context) {
doMakeSelection();
}
};
selectAction.setDescription("Make a selection using selected rows");
selectAction.setEnabled(true);
Icon icon = ResourceManager.loadImage("images/text_align_justify.png");
selectAction.setToolBarData(new ToolBarData(icon));
selectAction.setPopupMenuData(new MenuData(new String[] { "Make Selection" }, icon));
selectAction.setHelpLocation(new HelpLocation(HelpTopics.SEARCH, "Make_Selection"));
DockingAction selectionNavigationAction = new SelectionNavigationAction(owner, table);
selectionNavigationAction.setHelpLocation(
@ -183,7 +173,7 @@ public class TableChooserDialog extends DialogComponentProvider
addAction(selectionNavigationAction);
}
private void makeSelection() {
private void doMakeSelection() {
ProgramSelection selection = table.getProgramSelection();
if (program == null || program.isClosed() || selection.getNumAddresses() == 0) {
return;

View File

@ -28,10 +28,10 @@ abstract class DualListingToggleDockingAction extends ToggleDockingAction {
* Constructor that creates a toggle action for a dual listing.
* @param name the name for this action
* @param owner the owner of this action
* @param isKeybindingManaged true if this action's key binding should be managed
* @param supportsKeyBindings true if this action's key binding should be managed
*/
public DualListingToggleDockingAction(String name, String owner, boolean isKeybindingManaged) {
super(name, owner, isKeybindingManaged);
public DualListingToggleDockingAction(String name, String owner, boolean supportsKeyBindings) {
super(name, owner, supportsKeyBindings);
}
/**

View File

@ -75,7 +75,7 @@ public class DeleteTableRowAction extends DockingAction {
}
private DeleteTableRowAction(String name, String owner, KeyStroke defaultkeyStroke) {
super(name, owner);
super(name, owner, KeyBindingType.SHARED);
setDescription("Remove the selected rows from the table");
setHelpLocation(new HelpLocation(HelpTopics.SEARCH, "Remove_Items"));
@ -93,11 +93,6 @@ public class DeleteTableRowAction extends DockingAction {
setKeyBindingData(new KeyBindingData(keyStroke));
}
@Override
public boolean usesSharedKeyBinding() {
return true;
}
@Override
public boolean isEnabledForContext(ActionContext context) {
return table.getSelectedRowCount() > 0;

View File

@ -34,7 +34,7 @@ public abstract class MakeProgramSelectionAction extends DockingAction {
private JTable table;
public MakeProgramSelectionAction(String owner, JTable table) {
super("Make Selection", owner);
super("Make Selection", owner, KeyBindingType.SHARED);
this.table = table;
setPopupMenuData(
@ -57,11 +57,6 @@ public abstract class MakeProgramSelectionAction extends DockingAction {
setKeyBindingData(new KeyBindingData(keyStroke));
}
@Override
public boolean usesSharedKeyBinding() {
return true;
}
@Override
public boolean isAddToPopup(ActionContext context) {
return true;

View File

@ -408,15 +408,13 @@ public class KeyBindingUtilsTest extends AbstractGhidraHeadedIntegrationTest {
Set<DockingActionIf> list = tool.getAllActions();
DockingActionIf arbitraryAction = null;
for (DockingActionIf action : list) {
if (action.isKeyBindingManaged() && action.getKeyBinding() == null) {
if (action.getKeyBindingType().isManaged() && action.getKeyBinding() == null) {
arbitraryAction = action;
break;
}
}
if (arbitraryAction == null) {
Assert.fail("Unable to find an action for which to set a key binding.");
}
assertNotNull("Unable to find an action for which to set a key binding", arbitraryAction);
selectRowForAction(arbitraryAction);
triggerText(keyField, keyText);

View File

@ -104,7 +104,7 @@ public class KeyBindingsTest extends AbstractGhidraHeadedIntegrationTest {
public void testManagedKeyBindings() {
Set<DockingActionIf> list = tool.getAllActions();
for (DockingActionIf action : list) {
if (action.isKeyBindingManaged()) {
if (action.getKeyBindingType().isManaged()) {
assertTrue(actionInTable(action));
}
}
@ -130,7 +130,7 @@ public class KeyBindingsTest extends AbstractGhidraHeadedIntegrationTest {
Set<DockingActionIf> list = tool.getAllActions();
for (DockingActionIf action : list) {
KeyStroke ks = getKeyStroke(action);
if (isKeyBindingManaged(action) && ks != KeyStroke.getKeyStroke(KeyEvent.VK_Z, 0)) {
if (supportsKeyBindings(action) && ks != KeyStroke.getKeyStroke(KeyEvent.VK_Z, 0)) {
break;
}
}
@ -310,15 +310,15 @@ public class KeyBindingsTest extends AbstractGhidraHeadedIntegrationTest {
waitForSwing();
}
private boolean isKeyBindingManaged(DockingActionIf action) {
return action.isKeyBindingManaged();
private boolean supportsKeyBindings(DockingActionIf action) {
return action.getKeyBindingType().isManaged();
}
private DockingActionIf getKeyBindingPluginAction() {
Set<DockingActionIf> list = tool.getAllActions();
for (DockingActionIf action : list) {
KeyStroke ks = action.getKeyBinding();
if (action.isKeyBindingManaged() && ks != null &&
if (action.getKeyBindingType().isManaged() && ks != null &&
ks != KeyStroke.getKeyStroke(KeyEvent.VK_Z, 0)) {
return action;
}
@ -388,7 +388,7 @@ public class KeyBindingsTest extends AbstractGhidraHeadedIntegrationTest {
private void grabActionsWithoutKeybinding() {
Set<DockingActionIf> list = tool.getAllActions();
for (DockingActionIf action : list) {
if (!action.isKeyBindingManaged()) {
if (!action.getKeyBindingType().isManaged()) {
continue;
}
if (action.getKeyBinding() != null) {

View File

@ -379,4 +379,14 @@ public class DummyTool implements Tool {
public ToolOptions getOptions(String categoryName) {
return null;
}
@Override
public void addContextListener(DockingContextListener listener) {
//do nothing
}
@Override
public void removeContextListener(DockingContextListener listener) {
//do nothing
}
}

View File

@ -123,38 +123,36 @@ public abstract class ByteSequenceAnalyzerProvider extends DialogComponentProvid
}
private void addSendSelectedToClipboardAction() {
sendSelectedToClipboardAction =
new DockingAction("Send Selected to Clipboard", title, false) {
@Override
public void actionPerformed(ActionContext context) {
List<ByteSequenceRowObject> rows = byteSequenceTable.getLastSelectedObjects();
for (ByteSequenceRowObject row : rows) {
DittedBitSequence seq = new DittedBitSequence(row.getSequence(), true);
PatternInfoRowObject pattern =
new PatternInfoRowObject(type, seq, cRegFilter);
pattern.setNote(row.getDisassembly());
plugin.addPattern(pattern);
}
plugin.updateClipboard();
sendSelectedToClipboardAction = new DockingAction("Send Selected to Clipboard", title) {
@Override
public void actionPerformed(ActionContext context) {
List<ByteSequenceRowObject> rows = byteSequenceTable.getLastSelectedObjects();
for (ByteSequenceRowObject row : rows) {
DittedBitSequence seq = new DittedBitSequence(row.getSequence(), true);
PatternInfoRowObject pattern = new PatternInfoRowObject(type, seq, cRegFilter);
pattern.setNote(row.getDisassembly());
plugin.addPattern(pattern);
}
plugin.updateClipboard();
}
@Override
public boolean isEnabledForContext(ActionContext context) {
List<ByteSequenceRowObject> rows = byteSequenceTable.getLastSelectedObjects();
if (rows == null) {
return false;
}
if (rows.isEmpty()) {
return false;
}
return true;
@Override
public boolean isEnabledForContext(ActionContext context) {
List<ByteSequenceRowObject> rows = byteSequenceTable.getLastSelectedObjects();
if (rows == null) {
return false;
}
if (rows.isEmpty()) {
return false;
}
return true;
}
@Override
public boolean isAddToPopup(ActionContext context) {
return true;
}
};
@Override
public boolean isAddToPopup(ActionContext context) {
return true;
}
};
ImageIcon icon = ResourceManager.loadImage("images/2rightarrow.png");
sendSelectedToClipboardAction.setPopupMenuData(
@ -168,7 +166,7 @@ public abstract class ByteSequenceAnalyzerProvider extends DialogComponentProvid
}
private void addMergeAction() {
mergeAction = new DockingAction("Merge Selected Rows", title, false) {
mergeAction = new DockingAction("Merge Selected Rows", title) {
@Override
public void actionPerformed(ActionContext context) {
merged = byteSequenceTable.mergeSelectedRows();
@ -203,7 +201,7 @@ public abstract class ByteSequenceAnalyzerProvider extends DialogComponentProvid
}
private void addSendMergedToClipboardAction() {
sendMergedToClipboardAction = new DockingAction("Send Merged to Clipboard", title, false) {
sendMergedToClipboardAction = new DockingAction("Send Merged to Clipboard", title) {
@Override
public void actionPerformed(ActionContext context) {
if (merged != null) {

View File

@ -78,7 +78,7 @@ public class ClosedPatternTableDialog extends DialogComponentProvider {
private JPanel createMainPanel() {
JPanel panel = new JPanel(new BorderLayout());
GThreadedTablePanel<ClosedPatternRowObject> table =
new GThreadedTablePanel<ClosedPatternRowObject>(closedPatternTableModel);
new GThreadedTablePanel<>(closedPatternTableModel);
panel.add(table, BorderLayout.CENTER);
return panel;
}
@ -89,33 +89,31 @@ public class ClosedPatternTableDialog extends DialogComponentProvider {
}
private void addClipboardAction() {
sendToClipboardAction =
new DockingAction("Send Selected Sequences to Clipboard", TITLE, false) {
sendToClipboardAction = new DockingAction("Send Selected Sequences to Clipboard", TITLE) {
@Override
public void actionPerformed(ActionContext context) {
List<ClosedPatternRowObject> rows =
closedPatternTableModel.getLastSelectedObjects();
for (ClosedPatternRowObject row : rows) {
DittedBitSequence seq = new DittedBitSequence(row.getDittedString(), true);
PatternInfoRowObject pattern =
new PatternInfoRowObject(type, seq, cRegFilter);
plugin.addPattern(pattern);
}
plugin.updateClipboard();
@Override
public void actionPerformed(ActionContext context) {
List<ClosedPatternRowObject> rows =
closedPatternTableModel.getLastSelectedObjects();
for (ClosedPatternRowObject row : rows) {
DittedBitSequence seq = new DittedBitSequence(row.getDittedString(), true);
PatternInfoRowObject pattern = new PatternInfoRowObject(type, seq, cRegFilter);
plugin.addPattern(pattern);
}
plugin.updateClipboard();
}
@Override
public boolean isAddToPopup(ActionContext context) {
return true;
}
@Override
public boolean isAddToPopup(ActionContext context) {
return true;
}
@Override
public boolean isEnabledForContext(ActionContext context) {
return (!closedPatternTableModel.getLastSelectedObjects().isEmpty());
}
@Override
public boolean isEnabledForContext(ActionContext context) {
return (!closedPatternTableModel.getLastSelectedObjects().isEmpty());
}
};
};
ImageIcon icon = ResourceManager.loadImage("images/2rightarrow.png");
sendToClipboardAction.setPopupMenuData(
new MenuData(new String[] { "Send Selected Sequences to Clipboard" }, icon));

View File

@ -62,7 +62,7 @@ public class PatternMiningAnalyzerProvider extends ByteSequenceAnalyzerProvider
}
private void addMiningAction() {
mineClosedPatternsAction = new DockingAction(MINE_PATTERNS_BUTTON_TEXT, title, false) {
mineClosedPatternsAction = new DockingAction(MINE_PATTERNS_BUTTON_TEXT, title) {
@Override
public void actionPerformed(ActionContext context) {
List<ByteSequenceRowObject> lastSelectedObjects =

View File

@ -1,6 +1,5 @@
/* ###
* IP: GHIDRA
* REVIEWED: YES
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -16,36 +15,33 @@
*/
package ghidra.app.plugin.core.decompile.actions;
import ghidra.app.decompiler.component.DecompilerPanel;
import ghidra.app.util.HelpTopics;
import ghidra.util.HelpLocation;
import java.awt.event.InputEvent;
import java.awt.event.KeyEvent;
import docking.ActionContext;
import docking.action.DockingAction;
import docking.action.KeyBindingData;
import ghidra.app.decompiler.component.DecompilerPanel;
import ghidra.app.util.HelpTopics;
import ghidra.util.HelpLocation;
/**
* Action for adding all fields to the current format.
*/
public class SelectAllAction extends DockingAction {
DecompilerPanel panel;
public SelectAllAction(String owner, DecompilerPanel panel) {
super("Select All", owner, false);
this.panel = panel;
setKeyBindingData( new KeyBindingData(
KeyEvent.VK_A, InputEvent.CTRL_DOWN_MASK) );
public SelectAllAction(String owner, DecompilerPanel panel) {
super("Select All", owner);
this.panel = panel;
setKeyBindingData(new KeyBindingData(KeyEvent.VK_A, InputEvent.CTRL_DOWN_MASK));
setHelpLocation(new HelpLocation(HelpTopics.SELECTION, getName()));
}
}
@Override
public void actionPerformed(ActionContext context) {
panel.selectAll();
@Override
public void actionPerformed(ActionContext context) {
panel.selectAll();
}
}

View File

@ -176,6 +176,16 @@ public abstract class AbstractDockingTool implements DockingTool {
winMgr.contextChanged(provider);
}
@Override
public void addContextListener(DockingContextListener listener) {
winMgr.addContextListener(listener);
}
@Override
public void removeContextListener(DockingContextListener listener) {
winMgr.removeContextListener(listener);
}
@Override
public DockingWindowManager getWindowManager() {
return winMgr;

View File

@ -165,7 +165,7 @@ public class ActionToGuiMapper {
/**
* Close all menus (includes popup menus)
*/
static void dismissMenus() {
private void dismissMenus() {
MenuSelectionManager.defaultManager().clearSelectedPath();
}

View File

@ -159,7 +159,8 @@ public abstract class ComponentProvider implements HelpDescriptor, ActionContext
return;
}
showProviderAction = new ShowProviderAction();
boolean supportsKeyBindings = !isTransient;
showProviderAction = new ShowProviderAction(supportsKeyBindings);
}
/**
@ -550,15 +551,14 @@ public abstract class ComponentProvider implements HelpDescriptor, ActionContext
4) Wire default 'close' action to keybinding
5) Add global action for (show last provider)
--Navigation menu?
6) Revisit all uses of the key binding managed constructor
7) Update table popup actions to be managed
8) Update help locations
Questions:
C) How to wire universal close action (it is focus-dependent)
Fix:
-Update key binding methods to use an enum for: no management / full management / shared management
*/
dockingTool.getWindowManager().setIcon(this, icon);
@ -775,8 +775,9 @@ public abstract class ComponentProvider implements HelpDescriptor, ActionContext
private class ShowProviderAction extends DockingAction {
ShowProviderAction() {
super(name, owner);
ShowProviderAction(boolean supportsKeyBindings) {
super(name, owner,
supportsKeyBindings ? KeyBindingType.SHARED : KeyBindingType.UNSUPPORTED);
if (isToolbarAction) {
setToolBarData(new ToolBarData(icon, TOOLBAR_GROUP));
@ -796,17 +797,6 @@ public abstract class ComponentProvider implements HelpDescriptor, ActionContext
dockingTool.showComponentProvider(ComponentProvider.this, true);
}
@Override
public boolean isKeyBindingManaged() {
return false;
}
@Override
public boolean usesSharedKeyBinding() {
// we do not allow transient providers to have key bindings
return !isTransient;
}
@Override
protected String getInceptionFromTheFirstClassThatIsNotUs() {
// overridden to show who created the provider, as that is what this action represents

View File

@ -102,7 +102,7 @@ public class DialogComponentProviderPopupActionManager {
Object source = actionContext.getSourceObject();
if (source instanceof DockingActionProviderIf) {
DockingActionProviderIf actionProvider = (DockingActionProviderIf) source;
List<DockingActionIf> dockingActions = actionProvider.getDockingActions(actionContext);
List<DockingActionIf> dockingActions = actionProvider.getDockingActions();
for (DockingActionIf action : dockingActions) {
MenuData popupMenuData = action.getPopupMenuData();
if (popupMenuData != null && action.isValidContext(actionContext) &&

View File

@ -200,8 +200,8 @@ public class DockingActionProxy
}
@Override
public boolean isKeyBindingManaged() {
return dockingAction.isKeyBindingManaged();
public KeyBindingType getKeyBindingType() {
return dockingAction.getKeyBindingType();
}
@Override

View File

@ -1,6 +1,5 @@
/* ###
* IP: GHIDRA
* REVIEWED: YES
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -16,6 +15,18 @@
*/
package docking;
import docking.action.DockingActionIf;
/**
* A listener to be notified when the tool's context changes. Normally context is used to
* manage {@link DockingActionIf} enablement directly by the system. This class allows
* clients to listen to context change as well.
*/
public interface DockingContextListener {
void contextChanged(ActionContext context);
/**
* Called when the context changes
* @param context the context
*/
public void contextChanged(ActionContext context);
}

View File

@ -209,6 +209,18 @@ public interface DockingTool {
*/
public void contextChanged(ComponentProvider provider);
/**
* Adds the given context listener to this tool
* @param listener the listener to add
*/
public void addContextListener(DockingContextListener listener);
/**
* Removes the given context listener to this tool
* @param listener the listener to add
*/
public void removeContextListener(DockingContextListener listener);
/**
* Returns the DockingWindowManger for this tool.
* @return the DockingWindowManger for this tool.

View File

@ -2089,8 +2089,7 @@ public class DockingWindowManager implements PropertyChangeListener, Placeholder
contextListeners.remove(listener);
}
public void notifyContextListeners(ComponentPlaceholder placeHolder,
ActionContext actionContext) {
void notifyContextListeners(ComponentPlaceholder placeHolder, ActionContext actionContext) {
if (placeHolder == focusedPlaceholder) {
for (DockingContextListener listener : contextListeners) {

View File

@ -425,7 +425,9 @@ class KeyBindingOverrideKeyEventDispatcher implements KeyEventDispatcher {
}
KeyStroke keyStroke = KeyStroke.getKeyStrokeForEvent(event);
return (DockingKeyBindingAction) activeManager.getActionForKeyStroke(keyStroke);
DockingKeyBindingAction bindingAction =
(DockingKeyBindingAction) activeManager.getActionForKeyStroke(keyStroke);
return bindingAction;
}
private DockingWindowManager getActiveDockingWindowManager() {

View File

@ -101,7 +101,7 @@ public class PopupActionManager implements PropertyChangeListener {
Object source = actionContext.getSourceObject();
if (source instanceof DockingActionProviderIf) {
DockingActionProviderIf actionProvider = (DockingActionProviderIf) source;
List<DockingActionIf> dockingActions = actionProvider.getDockingActions(actionContext);
List<DockingActionIf> dockingActions = actionProvider.getDockingActions();
for (DockingActionIf action : dockingActions) {
MenuData popupMenuData = action.getPopupMenuData();
if (popupMenuData != null && action.isValidContext(actionContext) &&

View File

@ -50,24 +50,26 @@ class ShowComponentAction extends DockingAction implements Comparable<ShowCompon
super(truncateTitleAsNeeded(name), DockingWindowManager.DOCKING_WINDOWS_OWNER);
}
ShowComponentAction(DockingWindowManager winMgr, ComponentPlaceholder info, String subMenuName,
boolean isTransient) {
super(info.getProvider().getName(), DockingWindowManager.DOCKING_WINDOWS_OWNER);
ShowComponentAction(DockingWindowManager winMgr, ComponentPlaceholder placeholder,
String subMenuName, boolean isTransient) {
super(placeholder.getProvider().getName(), DockingWindowManager.DOCKING_WINDOWS_OWNER,
createKeyBindingType(isTransient, placeholder));
this.info = info;
this.info = placeholder;
this.winMgr = winMgr;
this.title = truncateTitleAsNeeded(info.getTitle());
this.title = truncateTitleAsNeeded(placeholder.getTitle());
this.isTransient = isTransient;
String group = isTransient ? "Transient" : "Permanent";
Icon icon = info.getIcon();
Icon icon = placeholder.getIcon();
if (icon == null) {
icon = EMPTY_ICON;
}
if (subMenuName != null) {
setMenuBarData(new MenuData(
new String[] { MENU_WINDOW, subMenuName, info.getFullTitle() }, icon, "Permanent"));
setMenuBarData(
new MenuData(new String[] { MENU_WINDOW, subMenuName, placeholder.getFullTitle() },
icon, "Permanent"));
winMgr.doSetMenuGroup(new String[] { MENU_WINDOW, subMenuName }, group);
}
else {
@ -75,7 +77,7 @@ class ShowComponentAction extends DockingAction implements Comparable<ShowCompon
}
// keybinding data used to show the binding in the menu
ComponentProvider provider = info.getProvider();
ComponentProvider provider = placeholder.getProvider();
DockingActionIf action = provider.getShowProviderAction();
KeyBindingData kbData = action.getKeyBindingData();
if (kbData != null) {
@ -94,19 +96,15 @@ class ShowComponentAction extends DockingAction implements Comparable<ShowCompon
}
}
@Override
public boolean isKeyBindingManaged() {
return false;
}
private static KeyBindingType createKeyBindingType(boolean isTransient,
ComponentPlaceholder placeholder) {
@Override
public boolean usesSharedKeyBinding() {
if (isTransient) {
return false; // temporary window
return KeyBindingType.UNSUPPORTED; // temporary window
}
// 'info' is null when this action is used to 'show all' instances of a given provider
return info != null;
return placeholder == null ? KeyBindingType.UNSUPPORTED : KeyBindingType.SHARED;
}
@Override

View File

@ -96,9 +96,6 @@ public class WindowActionManager {
toolBarMgr.dispose();
}
/**
* Notifies the window manager that an action context update is needed.
*/
synchronized void contextChanged(ComponentPlaceholder placeHolder) {
placeHolderForScheduledActionUpdate = placeHolder;

View File

@ -17,6 +17,7 @@ package docking.action;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.util.Objects;
import java.util.Set;
import javax.swing.*;
@ -63,8 +64,8 @@ public abstract class DockingAction implements DockingActionIf {
private String inceptionInformation;
private boolean isEnabled = true;
private boolean isKeyBindingManaged = true;
private KeyBindingType keyBindingType = KeyBindingType.INDIVIDUAL;
private KeyBindingData defaultKeyBindingData;
private KeyBindingData keyBindingData;
private MenuBarData menuBarData;
@ -72,19 +73,29 @@ public abstract class DockingAction implements DockingActionIf {
private ToolBarData toolBarData;
public DockingAction(String name, String owner) {
this(name, owner, true);
}
public DockingAction(String name, String owner, boolean isKeyBindingManaged) {
this.name = name;
this.owner = owner;
this.isKeyBindingManaged = isKeyBindingManaged;
recordInception();
HelpLocation location = new HelpLocation(owner, name, inceptionInformation);
setHelpLocation(location);
}
public DockingAction(String name, String owner, KeyBindingType kbType) {
this(name, owner);
this.keyBindingType = Objects.requireNonNull(kbType);
}
public DockingAction(String name, String owner, boolean supportsKeyBindings) {
this(name, owner);
this.keyBindingType =
supportsKeyBindings ? KeyBindingType.INDIVIDUAL : KeyBindingType.UNSUPPORTED;
}
protected KeyBindingType getPreferredKeyBindingType() {
return KeyBindingType.INDIVIDUAL;
}
@Override
public abstract void actionPerformed(ActionContext context);
@ -98,11 +109,6 @@ public abstract class DockingAction implements DockingActionIf {
propertyListeners.remove(listener);
}
@Override
public boolean isKeyBindingManaged() {
return isKeyBindingManaged;
}
@Override
public String getDescription() {
return description;
@ -258,6 +264,11 @@ public abstract class DockingAction implements DockingActionIf {
return menuItem;
}
@Override
public KeyBindingType getKeyBindingType() {
return keyBindingType;
}
@Override
public KeyStroke getKeyBinding() {
return keyBindingData == null ? null : keyBindingData.getKeyBinding();

View File

@ -23,6 +23,17 @@ import javax.swing.*;
import docking.ActionContext;
import docking.help.HelpDescriptor;
/**
* The base interface for clients that wish to create commands to be registered with a tool.
*
* <p>An action may appear in a primary menu, a popup menu or a toolbar. Further, an action
* may have a key binding assigned.
*
* <p>The particular support for key bindings is defined by {@link KeyBindingType}. Almost all
* client actions will use the default setting of {@link KeyBindingType#INDIVIDUAL}. To control
* the level of key binding support, you can pass the desired {@link KeyBindingType} to the
* base implementation of this interface.
*/
public interface DockingActionIf extends HelpDescriptor {
public static final String ENABLEMENT_PROPERTY = "enabled";
public static final String GLOBALCONTEXT_PROPERTY = "globalContext";
@ -248,10 +259,17 @@ public interface DockingActionIf extends HelpDescriptor {
public boolean shouldAddToWindow(boolean isMainWindow, Set<Class<?>> contextTypes);
/**
* Returns true if this action can have its keybinding information changed by the user.
* @return true if this action can have its keybinding information changed by the user.
* Returns this actions level of support for key binding accelerator keys
*
* <p>Actions support key bindings by default. Some reserved actions do not support
* key bindings, while others wish to share the same key bindings with multiple, equivalent
* actions (this allows the user to set one binding that works in many different contexts).
*
* @return the key binding support
*/
public boolean isKeyBindingManaged();
public default KeyBindingType getKeyBindingType() {
return KeyBindingType.INDIVIDUAL;
}
/**
* Sets the {@link KeyBindingData} on an action to either assign a keybinding or remove it
@ -272,22 +290,4 @@ public interface DockingActionIf extends HelpDescriptor {
* @param newKeyBindingData the KeyBindingData to be used to assign this action to a keybinding
*/
public void setUnvalidatedKeyBindingData(KeyBindingData newKeyBindingData);
/**
* Returns true if this action shares a keybinding with other actions. If this returns true,
* then this action, and any action that shares a name with this action, will be updated
* to the same key binding value whenever the key binding options change.
*
* <p>This will be false for the vast majority of actions. If you are unsure if your action
* should use a shared keybinding, then do not set this value to true.
*
* <p>This value is not meant to change over the life of the action. Thus, there is no
* <code>set</code> method to change this value. Rather, you should override this method
* to return <code>true</code> as desired.
*
* @return true to share a shared keybinding
*/
public default boolean usesSharedKeyBinding() {
return false;
}
}

View File

@ -1,6 +1,5 @@
/* ###
* IP: GHIDRA
* REVIEWED: YES
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -18,8 +17,6 @@ package docking.action;
import java.util.List;
import docking.ActionContext;
/**
* An interface for objects (really Components) to implement that signals they provide actions
* for the Docking environment. This interface will be called when the implementor is the source
@ -32,9 +29,9 @@ import docking.ActionContext;
*/
public interface DockingActionProviderIf {
/**
* Returns actions that are compatible with the given context.
* @param context the current context of the Docking system
*/
public List<DockingActionIf> getDockingActions( ActionContext context );
/**
* Returns actions that are compatible with the given context.
* @return the actions
*/
public List<DockingActionIf> getDockingActions();
}

View File

@ -0,0 +1,82 @@
/* ###
* 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;
/**
* Allows clients to signal their support for the assigning of key binding shortcut keys. Most
* action clients need not be concerned with this class. The default settings of
* {@link DockingAction} work correctly for almost all cases, which is to have the action
* support individual key bindings, which are managed by the system via the UI.
*
* @see DockingActionIf
*/
public enum KeyBindingType {
//@formatter:off
/**
* Indicates the setting of key bindings through the UI is not supported
*/
UNSUPPORTED,
/**
* Supports the assignment of key bindings via the UI. Setting a key binding on an action
* with this type will not affect any other action.
*/
INDIVIDUAL,
/**
* When the key binding is set via the UI, this action, and any action that shares a
* name with this action, will be updated to the same key binding value whenever the key
* binding options change.
*
* <p>Most actions will not be shared. If you are unsure if your action
* should use a shared keybinding, then do not do so.
*/
SHARED;
//@formatter:on
/**
* Returns true if this type supports key bindings. This is a convenience method for
* checking that this type is not {@link #UNSUPPORTED}.
* @return true if key bindings are supported
*/
public boolean supportsKeyBindings() {
return this != UNSUPPORTED;
}
/**
* Convenience method for checking if this type is the {@link #SHARED} type
* @return true if shared
*/
public boolean isShared() {
return this == SHARED;
}
/**
* A convenience method for clients to check whether this key binding type should be
* managed directly by the system.
*
* <p>Shared actions are not managed directly by the system, but are instead managed through
* a proxy action.
*
* @return true if managed directly by the system; false if key binding are not supported
* or are managed through a proxy
*/
public boolean isManaged() {
return this == INDIVIDUAL;
}
}

View File

@ -1,6 +1,5 @@
/* ###
* IP: GHIDRA
* REVIEWED: YES
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -29,14 +28,16 @@ public abstract class ToggleDockingAction extends DockingAction implements Toggl
super(name, owner);
}
public ToggleDockingAction(String name, String owner, boolean isKeybindingManaged) {
super(name, owner, isKeybindingManaged);
public ToggleDockingAction(String name, String owner, boolean supportsKeyBindings) {
super(name, owner, supportsKeyBindings);
}
@Override
public boolean isSelected() {
return isSelected;
}
@Override
public void setSelected(boolean newValue) {
isSelected = newValue;
firePropertyChanged(SELECTED_STATE_PROPERTY, !isSelected, isSelected);

View File

@ -49,7 +49,7 @@ public class KeyBindingAction extends DockingAction {
action = maybeGetToolLevelAction(action);
if (!action.isKeyBindingManaged()) {
if (!action.getKeyBindingType().supportsKeyBindings()) {
Component parent = windowManager.getActiveComponent();
Msg.showInfo(getClass(), parent, "Unable to Set Keybinding",
"Action \"" + getActionName(action) + "\" is not keybinding managed and thus a " +
@ -68,15 +68,15 @@ public class KeyBindingAction extends DockingAction {
* @return A tool-level action if one is found; otherwise, the original action
*/
private DockingActionIf maybeGetToolLevelAction(DockingActionIf dockingAction) {
if (dockingAction.isKeyBindingManaged()) {
return dockingAction;
}
// It is not key binding managed, which means that it may be a shared key binding
String actionName = dockingAction.getName();
DockingActionIf sharedAction = toolActions.getSharedStubKeyBindingAction(actionName);
if (sharedAction != null) {
return sharedAction;
if (dockingAction.getKeyBindingType().isShared()) {
// It is not key binding managed, which means that it may be a shared key binding
String actionName = dockingAction.getName();
DockingActionIf sharedAction = toolActions.getSharedStubKeyBindingAction(actionName);
if (sharedAction != null) {
return sharedAction;
}
}
return dockingAction;

View File

@ -345,7 +345,7 @@ public class KeyBindingUtils {
/**
* A utility method to get all key binding actions. This method will remove duplicate
* actions and will only return actions that are {@link DockingActionIf#isKeyBindingManaged()}
* actions and will only return actions that support {@link KeyBindingType key bindings}.
*
* @param tool the tool containing the actions
* @return the actions mapped by their full name (e.g., 'Name (OwnerName)')
@ -371,7 +371,7 @@ public class KeyBindingUtils {
/**
* A utility method to get all key binding actions that have the given owner.
* This method will remove duplicate actions and will only return actions
* that are {@link DockingActionIf#isKeyBindingManaged()}
* that support {@link KeyBindingType key bindings}.
*
* @param tool the tool containing the actions
* @param owner the action owner name
@ -718,9 +718,9 @@ public class KeyBindingUtils {
//==================================================================================================
private static boolean isIgnored(DockingActionIf action) {
// not keybinding managed; 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
return !action.isKeyBindingManaged() || action.usesSharedKeyBinding();
return action.getKeyBindingType().isShared();
}
private static KeyStroke getKeyStroke(KeyBindingData data) {

View File

@ -22,7 +22,8 @@ import java.util.List;
import javax.swing.*;
import javax.swing.text.*;
import docking.*;
import docking.DialogComponentProvider;
import docking.KeyEntryTextField;
import docking.action.*;
import docking.widgets.label.GIconLabel;
import ghidra.util.HelpLocation;
@ -157,21 +158,7 @@ public class KeyEntryDialog extends DialogComponentProvider {
return;
}
KeyBindingData kbData = new KeyBindingData(newKeyStroke);
if (action instanceof SharedStubKeyBindingAction) {
action.setUnvalidatedKeyBindingData(kbData);
}
else {
Set<DockingActionIf> allActions = toolActions.getAllActions();
Set<DockingActionIf> actions =
KeyBindingUtils.getActions(allActions, action.getOwner(), action.getName());
for (DockingActionIf element : actions) {
if (element.isKeyBindingManaged()) {
element.setUnvalidatedKeyBindingData(kbData);
}
}
}
action.setUnvalidatedKeyBindingData(new KeyBindingData(newKeyStroke));
toolActions.keyBindingsChanged();
@ -248,11 +235,6 @@ public class KeyEntryDialog extends DialogComponentProvider {
}
private boolean shouldAddAction(DockingActionIf dockableAction) {
if (dockableAction.isKeyBindingManaged()) {
return true;
}
// shared key bindings are handled specially
return !dockableAction.usesSharedKeyBinding();
return dockableAction.getKeyBindingType().isManaged();
}
}

View File

@ -22,8 +22,12 @@ import java.util.*;
import javax.swing.Action;
import javax.swing.KeyStroke;
import org.apache.commons.collections4.IteratorUtils;
import org.apache.commons.collections4.Predicate;
import org.apache.commons.collections4.map.LazyMap;
import com.google.common.collect.Iterators;
import docking.*;
import docking.action.*;
import docking.tool.util.DockingToolConstants;
@ -113,12 +117,13 @@ public class ToolActions implements PropertyChangeListener {
private void setKeyBindingOption(DockingActionIf action) {
if (action.usesSharedKeyBinding()) {
installSharedKeyBinding(action);
KeyBindingType type = action.getKeyBindingType();
if (!type.supportsKeyBindings()) {
return;
}
if (!action.isKeyBindingManaged()) {
if (type.isShared()) {
installSharedKeyBinding(action);
return;
}
@ -227,25 +232,47 @@ public class ToolActions implements PropertyChangeListener {
return result;
}
private Iterator<DockingActionIf> getAllActionsIterator() {
// chain all items together, rather than copy the data
Iterator<DockingActionIf> iterator = IteratorUtils.emptyIterator();
Collection<Map<String, Set<DockingActionIf>>> maps = actionsByNameByOwner.values();
for (Map<String, Set<DockingActionIf>> actionsByName : maps) {
for (Set<DockingActionIf> actions : actionsByName.values()) {
Iterator<DockingActionIf> next = actions.iterator();
// Note: do not use apache commons here--the code below degrades exponentially
//iterator = IteratorUtils.chainedIterator(iterator, next);
iterator = Iterators.concat(iterator, next);
}
}
return Iterators.concat(iterator, sharedActionMap.values().iterator());
}
/**
* 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);
Set<DockingActionIf> actions = getAllActions();
for (DockingActionIf action : actions) {
if (!action.isKeyBindingManaged()) {
continue;
}
Iterator<DockingActionIf> it = getKeyBindingActionsIterator();
for (DockingActionIf action : CollectionUtils.asIterable(it)) {
KeyStroke ks = action.getKeyBinding();
KeyStroke newKs = keyBindingOptions.getKeyStroke(action.getFullName(), ks);
if (ks != newKs) {
if (!Objects.equals(ks, newKs)) {
action.setUnvalidatedKeyBindingData(new KeyBindingData(newKs));
}
}
}
// return only actions that allow key bindings
private Iterator<DockingActionIf> getKeyBindingActionsIterator() {
Predicate<DockingActionIf> filter = a -> a.getKeyBindingType() == KeyBindingType.INDIVIDUAL;
return IteratorUtils.filteredIterator(getAllActionsIterator(), filter);
}
/**
* Remove an action that works specifically with a component provider.
* @param provider provider associated with the action
@ -272,11 +299,13 @@ public class ToolActions implements PropertyChangeListener {
private void removeAction(DockingActionIf action) {
getActionStorage(action).remove(action);
if (action.usesSharedKeyBinding()) {
SharedStubKeyBindingAction stub = sharedActionMap.get(action.getName());
if (stub != null) {
stub.removeClientAction(action);
}
if (!action.getKeyBindingType().isShared()) {
return;
}
SharedStubKeyBindingAction stub = sharedActionMap.get(action.getName());
if (stub != null) {
stub.removeClientAction(action);
}
}
@ -293,7 +322,7 @@ public class ToolActions implements PropertyChangeListener {
}
DockingAction action = (DockingAction) evt.getSource();
if (!action.isKeyBindingManaged()) {
if (!action.getKeyBindingType().isManaged()) {
// this reads unusually, but we need to notify the tool to rebuild its 'Window' menu
// in the case that this action is one of the tool's special actions
keyBindingsChanged();

View File

@ -15,9 +15,9 @@
*/
package docking.widgets.table;
import static docking.DockingUtils.*;
import static docking.action.MenuData.*;
import static java.awt.event.InputEvent.*;
import static docking.DockingUtils.CONTROL_KEY_MODIFIER_MASK;
import static docking.action.MenuData.NO_MNEMONIC;
import static java.awt.event.InputEvent.SHIFT_DOWN_MASK;
import java.awt.*;
import java.awt.event.*;
@ -509,23 +509,14 @@ public class GTable extends JTable implements KeyStrokeConsumer, DockingActionPr
return autoLookupKeyStrokeConsumer.isKeyConsumed(keyStroke);
}
/**
* {@inheritDoc}
*/
@Override
public List<DockingActionIf> getDockingActions(ActionContext context) {
Object sourceObject = context.getSourceObject();
if (sourceObject != this) {
// we are only interested in providing actions when we are the source of the event
return Collections.emptyList();
}
public List<DockingActionIf> getDockingActions() {
return getDefaultDockingActions();
}
/**
* Returns the default actions of this table. Normally, the Docking Windows systems uses
* {@link #getDockingActions(ActionContext)} to get the correct actions to show. However,
* {@link #getDockingActions()} to get the correct actions to show. However,
* there are some cases where clients override what appears when you click on a table (such
* as in {@link DialogComponentProvider}s. For those clients that are creating their own
* action building, they need a way to get the default actions, hence this method.
@ -1178,7 +1169,8 @@ public class GTable extends JTable implements KeyStrokeConsumer, DockingActionPr
int subGroupIndex = 1; // order by insertion
String owner = getClass().getSimpleName();
copyAction = new DockingAction("Table Data Copy", owner, false) {
owner = "GTable";
copyAction = new DockingAction("Table Data Copy", owner, KeyBindingType.SHARED) {
@Override
public void actionPerformed(ActionContext context) {
copying = true;
@ -1209,7 +1201,7 @@ public class GTable extends JTable implements KeyStrokeConsumer, DockingActionPr
//@formatter:on
copyCurrentColumnAction =
new DockingAction("Table Data Copy Current Column", owner, false) {
new DockingAction("Table Data Copy Current Column", owner, KeyBindingType.SHARED) {
@Override
public void actionPerformed(ActionContext context) {
@ -1246,17 +1238,18 @@ public class GTable extends JTable implements KeyStrokeConsumer, DockingActionPr
copyCurrentColumnAction.setHelpLocation(new HelpLocation("Tables", "Copy_Current_Column"));
//@formatter:on
copyColumnsAction = new DockingAction("Table Data Copy by Columns", owner, false) {
@Override
public void actionPerformed(ActionContext context) {
int[] userColumns = promptUserForColumns();
if (userColumns == null) {
return; // cancelled
}
copyColumnsAction =
new DockingAction("Table Data Copy by Columns", owner, KeyBindingType.SHARED) {
@Override
public void actionPerformed(ActionContext context) {
int[] userColumns = promptUserForColumns();
if (userColumns == null) {
return; // cancelled
}
copyColumns(userColumns);
}
};
copyColumns(userColumns);
}
};
//@formatter:off
copyColumnsAction.setPopupMenuData(new MenuData(
new String[] { "Copy", "Copy Columns..." },
@ -1269,7 +1262,7 @@ public class GTable extends JTable implements KeyStrokeConsumer, DockingActionPr
copyColumnsAction.setHelpLocation(new HelpLocation("Tables", "Copy_Columns"));
//@formatter:on
exportAction = new DockingAction("Table Data CSV Export", owner, false) {
exportAction = new DockingAction("Table Data CSV Export", owner, KeyBindingType.SHARED) {
@Override
public void actionPerformed(ActionContext context) {
File file = chooseExportFile();
@ -1291,7 +1284,7 @@ public class GTable extends JTable implements KeyStrokeConsumer, DockingActionPr
//@formatter:on
exportColumnsAction =
new DockingAction("Table Data CSV Export (by Columns)", owner, false) {
new DockingAction("Table Data CSV Export (by Columns)", owner, KeyBindingType.SHARED) {
@Override
public void actionPerformed(ActionContext context) {
int[] userColumns = promptUserForColumns();
@ -1323,7 +1316,7 @@ public class GTable extends JTable implements KeyStrokeConsumer, DockingActionPr
exportColumnsAction.setHelpLocation(new HelpLocation("Tables", "ExportCSV_Columns"));
//@formatter:on
selectAllAction = new DockingAction("Table Select All", owner, false) {
selectAllAction = new DockingAction("Table Select All", owner, KeyBindingType.SHARED) {
@Override
public void actionPerformed(ActionContext context) {
selectAll();

View File

@ -356,7 +356,7 @@ public class SharedKeyBindingDockingActionTest extends AbstractDockingTest {
//==================================================================================================
private void assertSharedStubInTool() {
ToolActions actionManager = (ToolActions) getInstanceField("actionMgr", tool);
ToolActions actionManager = (ToolActions) getInstanceField("toolActions", tool);
DockingActionIf action = actionManager.getSharedStubKeyBindingAction(SHARED_NAME);
assertNotNull("Shared action stub is not in the tool", action);
}
@ -426,16 +426,8 @@ public class SharedKeyBindingDockingActionTest extends AbstractDockingTest {
private class TestAction extends DockingAction {
public TestAction(String owner, KeyStroke ks) {
super(SHARED_NAME, owner);
if (ks != null) {
setKeyBindingData(new KeyBindingData(ks));
}
}
@Override
public boolean usesSharedKeyBinding() {
return true;
super(SHARED_NAME, owner, KeyBindingType.SHARED);
setKeyBindingData(new KeyBindingData(ks));
}
@Override

View File

@ -490,7 +490,10 @@ public class ProjectDataTablePanel extends JPanel {
}
@Override
public List<DockingActionIf> getDockingActions(ActionContext context) {
public List<DockingActionIf> getDockingActions() {
// TODO we should at least add the 'copy' action
// the table's default actions aren't that useful in the Front End
return Collections.emptyList();
}

View File

@ -133,7 +133,7 @@ public class VersionHistoryDialog extends DialogComponentProvider
}
@Override
public List<DockingActionIf> getDockingActions(ActionContext context) {
return versionPanel.getDockingActions(context);
public List<DockingActionIf> getDockingActions() {
return versionPanel.getDockingActions();
}
}

View File

@ -402,7 +402,7 @@ public class VersionHistoryPanel extends JPanel implements Draggable {
provider.addAction(new DeleteAction());
}
public List<DockingActionIf> getDockingActions(ActionContext currentContext) {
public List<DockingActionIf> getDockingActions() {
List<DockingActionIf> list = new ArrayList<>(table.getDefaultDockingActions());
Project project = tool.getProject();
ToolChest toolChest = project.getLocalToolChest();

View File

@ -1464,17 +1464,6 @@ public abstract class PluginTool extends AbstractDockingTool
DockingWindowManager.showDialog(getToolFrame(), dialogComponent, centeredOnComponent);
}
/**
* Returns the ComponentProvider with the given name. If more than one provider exists with the name,
* one will be returned, but it could be any one of them.
* @param name the name of the provider to return.
* @return a provider with the given name, or null if no providers with that name exist.
*/
@Override
public ComponentProvider getComponentProvider(String name) {
return winMgr.getComponentProvider(name);
}
public Window getActiveWindow() {
return winMgr.getActiveWindow();
}
@ -1483,19 +1472,6 @@ public abstract class PluginTool extends AbstractDockingTool
return winMgr.getActiveComponentProvider();
}
@Override
public void contextChanged(ComponentProvider provider) {
winMgr.contextChanged(provider);
}
public void addContextListener(DockingContextListener listener) {
winMgr.addContextListener(listener);
}
public void removeContextListener(DockingContextListener listener) {
winMgr.removeContextListener(listener);
}
public void refreshKeybindings() {
toolActions.restoreKeyBindings();
}