Merge branch 'GT-3485_action_context'

Conflicts:
	Ghidra/Framework/Docking/src/main/java/docking/action/MultipleKeyAction.java
This commit is contained in:
ghidravore
2020-03-16 13:22:53 -04:00
42 changed files with 628 additions and 631 deletions
@@ -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,25 +15,26 @@
*/
package ghidra.app.context;
import docking.ComponentProvider;
import ghidra.app.nav.Navigatable;
import ghidra.program.model.listing.Program;
import ghidra.program.util.ProgramLocation;
import ghidra.program.util.ProgramSelection;
import docking.ComponentProvider;
public class ListingActionContext extends NavigatableActionContext {
public ListingActionContext(ComponentProvider provider, Navigatable navigatable) {
super(provider, navigatable);
}
public ListingActionContext(ComponentProvider provider, Navigatable navigatable, ProgramLocation location) {
public ListingActionContext(ComponentProvider provider, Navigatable navigatable,
ProgramLocation location) {
super(provider, navigatable, location);
}
public ListingActionContext(ComponentProvider provider, Navigatable navigatable,
Program program, ProgramLocation location, ProgramSelection selection,
ProgramSelection highlight ) {
super( provider, navigatable, program, location, selection, highlight );
public ListingActionContext(ComponentProvider provider, Navigatable navigatable,
Program program, ProgramLocation location, ProgramSelection selection,
ProgramSelection highlight) {
super(provider, navigatable, program, location, selection, highlight);
}
}
@@ -25,45 +25,32 @@ public abstract class NavigatableContextAction extends DockingAction {
public NavigatableContextAction(String name, String owner) {
super(name, owner);
setSupportsDefaultToolContext(true);
}
public NavigatableContextAction(String name, String owner, KeyBindingType type) {
super(name, owner, type);
setSupportsDefaultToolContext(true);
}
@Override
public boolean isEnabledForContext(ActionContext context) {
NavigatableActionContext appropriateContext = getAppropriateContext(context);
if (appropriateContext == null) {
return false;
if (context instanceof NavigatableActionContext) {
return isEnabledForContext((NavigatableActionContext) context);
}
return isEnabledForContext(appropriateContext);
return false;
}
@Override
public void actionPerformed(ActionContext context) {
actionPerformed(getAppropriateContext(context));
}
private NavigatableActionContext getAppropriateContext(ActionContext context) {
if (context instanceof NavigatableActionContext &&
isValidNavigationContext((NavigatableActionContext) context)) {
return (NavigatableActionContext) context;
if (context instanceof NavigatableActionContext) {
actionPerformed((NavigatableActionContext) context);
}
ActionContext globalContext = context.getGlobalContext();
if (globalContext instanceof NavigatableActionContext) {
return (NavigatableActionContext) globalContext;
}
return null;
}
@Override
public final boolean isValidContext(ActionContext context) {
return true;
}
protected boolean isValidNavigationContext(NavigatableActionContext context) {
return true;
return context instanceof NavigatableActionContext;
}
@Override
@@ -30,23 +30,14 @@ public abstract class NextRangeAction extends NavigatableContextAction {
private PluginTool tool;
private NavigationOptions navOptions;
public NextRangeAction(PluginTool tool, String name, String owner, NavigationOptions navOptions) {
public NextRangeAction(PluginTool tool, String name, String owner,
NavigationOptions navOptions) {
super(name, owner);
this.tool = tool;
this.navOptions = navOptions;
setEnabled(false);
}
@Override
protected boolean isValidNavigationContext(NavigatableActionContext context) {
//
// We want the nav actions to work in the current view that supports this, which right
// now is the ListingActionContext. If the current context does not support that, then
// we will be called later with the global context, which does support navigation.
//
return context instanceof ListingActionContext;
}
@Override
public boolean isEnabledForContext(NavigatableActionContext context) {
Address currentAddress = context.getAddress();
@@ -37,16 +37,6 @@ public abstract class PreviousRangeAction extends NavigatableContextAction {
setEnabled(false);
}
@Override
protected boolean isValidNavigationContext(NavigatableActionContext context) {
//
// We want the nav actions to work in the current view that supports this, which right
// now is the ListingActionContext. If the current context does not support that, then
// we will be called later with the global context, which does support navigation.
//
return context instanceof ListingActionContext;
}
@Override
public void actionPerformed(NavigatableActionContext context) {
Address goToAddress = getGoToAddress(context);
@@ -22,6 +22,7 @@ import docking.ActionContext;
import docking.ComponentProvider;
import docking.action.DockingAction;
import docking.action.MenuData;
import docking.action.builder.ActionBuilder;
import docking.tool.ToolConstants;
import ghidra.app.CorePluginPackage;
import ghidra.app.context.*;
@@ -96,33 +97,28 @@ public class FindPossibleReferencesPlugin extends Plugin {
}
private void createActions() {
action = new ListingContextAction(SEARCH_DIRECT_REFS_ACTION_NAME, getName()) {
@Override
protected void actionPerformed(ListingActionContext context) {
findReferences(context);
}
action = new ActionBuilder(SEARCH_DIRECT_REFS_ACTION_NAME, getName())
.menuPath(ToolConstants.MENU_SEARCH, "For Direct References")
.menuGroup("search for")
.supportsDefaultToolContext(true)
.helpLocation(new HelpLocation(HelpTopics.SEARCH, SEARCH_DIRECT_REFS_ACTION_NAME))
.description(getPluginDescription().getDescription())
.withContext(ListingActionContext.class)
.onAction(this::findReferences)
.enabledWhen(this::hasCorrectAddressSize)
.buildAndInstall(tool);
@Override
protected boolean isEnabledForContext(ListingActionContext context) {
int size =
context.getProgram().getAddressFactory().getDefaultAddressSpace().getSize();
if ((size == 64) || (size == 32) || (size == 24) || (size == 16) || (size == 20) ||
(size == 21)) {
return true;
}
return false;
}
};
action.setHelpLocation(new HelpLocation(HelpTopics.SEARCH, SEARCH_DIRECT_REFS_ACTION_NAME));
action.setMenuBarData(
new MenuData(new String[] { ToolConstants.MENU_SEARCH, "For Direct References" }, null,
"search for"));
}
action.setDescription(getPluginDescription().getDescription());
//enableOnLocation(action);
tool.addAction(action);
} // end of createActions()
private boolean hasCorrectAddressSize(ListingActionContext context) {
int size =
context.getProgram().getAddressFactory().getDefaultAddressSpace().getSize();
if ((size == 64) || (size == 32) || (size == 24) || (size == 16) || (size == 20) ||
(size == 21)) {
return true;
}
return false;
}
private void createLocalActions(ProgramLocationActionContext context, ComponentProvider p,
FindReferencesTableModel model) {
@@ -196,8 +192,10 @@ public class FindPossibleReferencesPlugin extends Plugin {
"Could not find memory associated with " + fromAddr);
return;
}
if (currentProgram.getMemory().getBlock(
fromAddr).getType() == MemoryBlockType.BIT_MAPPED) {
if (currentProgram.getMemory()
.getBlock(
fromAddr)
.getType() == MemoryBlockType.BIT_MAPPED) {
Msg.showWarn(getClass(), null, "Search For Direct References",
"Cannot search for direct references on bit memory!");
return;
@@ -30,6 +30,7 @@ public class ClearSelectionAction extends CodeViewerContextAction {
public ClearSelectionAction(String owner) {
super("Clear Selection", owner);
setSupportsDefaultToolContext(true);
setMenuBarData(new MenuData(
new String[] { ToolConstants.MENU_SELECTION, "&Clear Selection" }, null, "Select"));
@@ -23,8 +23,9 @@ import javax.swing.KeyStroke;
import docking.action.KeyBindingData;
import docking.action.MenuData;
import docking.tool.ToolConstants;
import ghidra.app.context.NavigatableActionContext;
import ghidra.app.context.NavigatableContextAction;
import ghidra.app.nav.Navigatable;
import ghidra.app.plugin.core.codebrowser.CodeViewerActionContext;
import ghidra.app.services.GoToService;
import ghidra.app.util.HelpTopics;
import ghidra.framework.plugintool.PluginTool;
@@ -33,7 +34,7 @@ import ghidra.program.model.listing.*;
import ghidra.program.util.FunctionSignatureFieldLocation;
import ghidra.util.HelpLocation;
public class GotoNextFunctionAction extends CodeViewerContextAction {
public class GotoNextFunctionAction extends NavigatableContextAction {
private PluginTool tool;
@@ -67,7 +68,7 @@ public class GotoNextFunctionAction extends CodeViewerContextAction {
}
@Override
protected void actionPerformed(CodeViewerActionContext context) {
protected void actionPerformed(NavigatableActionContext context) {
Address address = context.getAddress();
Program program = context.getProgram();
Function function = getNextFunction(program, address);
@@ -79,7 +80,7 @@ public class GotoNextFunctionAction extends CodeViewerContextAction {
if (service != null) {
FunctionSignatureFieldLocation location =
new FunctionSignatureFieldLocation(program, function.getEntryPoint(), null, 0,
function.getPrototypeString(false, false));
function.getPrototypeString(false, false));
Navigatable navigatable = context.getNavigatable();
service.goTo(navigatable, location, navigatable.getProgram());
@@ -23,8 +23,9 @@ import javax.swing.KeyStroke;
import docking.action.KeyBindingData;
import docking.action.MenuData;
import docking.tool.ToolConstants;
import ghidra.app.context.NavigatableActionContext;
import ghidra.app.context.NavigatableContextAction;
import ghidra.app.nav.Navigatable;
import ghidra.app.plugin.core.codebrowser.CodeViewerActionContext;
import ghidra.app.services.GoToService;
import ghidra.app.util.HelpTopics;
import ghidra.framework.plugintool.PluginTool;
@@ -33,7 +34,7 @@ import ghidra.program.model.listing.*;
import ghidra.program.util.FunctionSignatureFieldLocation;
import ghidra.util.HelpLocation;
public class GotoPreviousFunctionAction extends CodeViewerContextAction {
public class GotoPreviousFunctionAction extends NavigatableContextAction {
private PluginTool tool;
@@ -67,7 +68,7 @@ public class GotoPreviousFunctionAction extends CodeViewerContextAction {
}
@Override
protected void actionPerformed(CodeViewerActionContext context) {
protected void actionPerformed(NavigatableActionContext context) {
Address address = context.getAddress();
Program program = context.getProgram();
Function function = getPreviousFunction(program, address);
@@ -15,10 +15,6 @@
*/
package ghidra.app.plugin.core.codebrowser.actions;
import ghidra.app.plugin.core.codebrowser.CodeViewerProvider;
import ghidra.app.util.HelpTopics;
import ghidra.util.HelpLocation;
import java.awt.event.InputEvent;
import java.awt.event.KeyEvent;
@@ -26,27 +22,32 @@ import docking.ActionContext;
import docking.action.KeyBindingData;
import docking.action.MenuData;
import docking.tool.ToolConstants;
import ghidra.app.plugin.core.codebrowser.CodeViewerProvider;
import ghidra.app.util.HelpTopics;
import ghidra.util.HelpLocation;
/**
* Action for adding all fields to the current format.
*/
public class SelectAllAction extends CodeViewerContextAction {
public SelectAllAction(String owner) {
super("Select All", owner);
setMenuBarData(
new MenuData(
new String[] {ToolConstants.MENU_SELECTION, "&All in View" },null,"Select" ) );
setKeyBindingData( new KeyBindingData(
KeyEvent.VK_A, InputEvent.CTRL_DOWN_MASK ) );
public SelectAllAction(String owner) {
super("Select All", owner);
// this is in the main tool menu, so make it a tool action
setSupportsDefaultToolContext(true);
setMenuBarData(
new MenuData(
new String[] { ToolConstants.MENU_SELECTION, "&All in View" }, null, "Select"));
setKeyBindingData(new KeyBindingData(
KeyEvent.VK_A, InputEvent.CTRL_DOWN_MASK));
setHelpLocation(new HelpLocation(HelpTopics.SELECTION, getName()));
}
@Override
public void actionPerformed(ActionContext context) {
CodeViewerProvider provider = (CodeViewerProvider) context.getComponentProvider();
provider.selectAll();
}
}
}
@Override
public void actionPerformed(ActionContext context) {
CodeViewerProvider provider = (CodeViewerProvider) context.getComponentProvider();
provider.selectAll();
}
}
@@ -14,14 +14,15 @@
* limitations under the License.
*/
package ghidra.app.plugin.core.codebrowser.actions;
import docking.ActionContext;
import docking.action.MenuData;
import docking.tool.ToolConstants;
import ghidra.app.plugin.core.codebrowser.CodeViewerActionContext;
import ghidra.app.plugin.core.codebrowser.CodeViewerProvider;
import ghidra.app.util.HelpTopics;
import ghidra.program.util.ProgramSelection;
import ghidra.util.HelpLocation;
import docking.ActionContext;
import docking.action.MenuData;
import docking.tool.ToolConstants;
/**
* Action for changing the selection to the complement of all the currently
@@ -29,29 +30,33 @@ import docking.tool.ToolConstants;
*/
public class SelectComplementAction extends CodeViewerContextAction {
public SelectComplementAction(String owner) {
super("Select Complement", owner);
setMenuBarData( new MenuData(
new String[]{ToolConstants.MENU_SELECTION, "&Complement" },
null,
"Select" ) );
public SelectComplementAction(String owner) {
super("Select Complement", owner);
setEnabled(false);
// this is in the main tool menu, so make it a tool action
setSupportsDefaultToolContext(true);
setMenuBarData(new MenuData(
new String[] { ToolConstants.MENU_SELECTION, "&Complement" },
null,
"Select"));
setEnabled(false);
setHelpLocation(new HelpLocation(HelpTopics.SELECTION, getName()));
}
}
@Override
public void actionPerformed(ActionContext context) {
CodeViewerProvider provider = (CodeViewerProvider) context.getComponentProvider();
provider.selectComplement();
}
@Override
public boolean isEnabledForContext(CodeViewerActionContext context) {
ProgramSelection selection = context.getSelection();
if (selection != null && selection.getInteriorSelection() != null) {
return false;
}
return true;
}
@Override
public void actionPerformed(ActionContext context) {
CodeViewerProvider provider = (CodeViewerProvider) context.getComponentProvider();
provider.selectComplement();
}
@Override
public boolean isEnabledForContext(CodeViewerActionContext context) {
ProgramSelection selection = context.getSelection();
if (selection != null && selection.getInteriorSelection() != null) {
return false;
}
return true;
}
}
@@ -245,9 +245,10 @@ public class InstructionSearchPlugin extends ProgramPlugin {
}
@Override
protected boolean isValidNavigationContext(NavigatableActionContext context) {
protected boolean isEnabledForContext(NavigatableActionContext context) {
return !(context instanceof RestrictedAddressSetContext);
}
};
searchAction.setHelpLocation(new HelpLocation("Search", "Instruction_Pattern_Search"));
searchAction.setMenuBarData(
@@ -17,9 +17,10 @@ package ghidra.app.plugin.core.navigation;
import javax.swing.*;
import docking.action.*;
import docking.action.KeyBindingData;
import docking.action.ToolBarData;
import docking.tool.ToolConstants;
import ghidra.app.context.ListingActionContext;
import ghidra.app.context.NavigatableActionContext;
import ghidra.app.nav.Navigatable;
import ghidra.app.plugin.core.codebrowser.CodeViewerActionContext;
import ghidra.app.plugin.core.codebrowser.actions.CodeViewerContextAction;
@@ -41,16 +42,12 @@ public abstract class AbstractNextPreviousAction extends CodeViewerContextAction
public AbstractNextPreviousAction(PluginTool tool, String name, String owner, String subGroup) {
super(name, owner);
this.tool = tool;
setSupportsDefaultToolContext(true);
ToolBarData toolBarData =
new ToolBarData(getIcon(), ToolConstants.TOOLBAR_GROUP_FOUR);
toolBarData.setToolBarSubGroup(subGroup);
setToolBarData(toolBarData);
MenuData menuData =
new MenuData(new String[] { ToolConstants.MENU_NAVIGATION, getMenuName() }, getIcon(),
ToolConstants.MENU_GROUP_NEXT_CODE_UNIT_NAV);
menuData.setMenuSubGroup(subGroup);
setMenuBarData(menuData);
setKeyBindingData(new KeyBindingData(getKeyStroke()));
setHelpLocation(new HelpLocation(HelpTopics.NAVIGATION, name));
setDescription(getDescriptionString());
@@ -90,7 +87,7 @@ public abstract class AbstractNextPreviousAction extends CodeViewerContextAction
}
}
private void gotoAddress(ListingActionContext actionContext, Address address) {
private void gotoAddress(NavigatableActionContext actionContext, Address address) {
if (address == null) {
tool.setStatusInfo("Unable to locate another \"" + getNavigationTypeName() +
"\" past the current range, in the current direction.");
@@ -23,9 +23,9 @@ import javax.swing.Icon;
import docking.action.*;
import docking.tool.ToolConstants;
import ghidra.app.CorePluginPackage;
import ghidra.app.context.NavigatableActionContext;
import ghidra.app.context.NavigatableContextAction;
import ghidra.app.plugin.PluginCategoryNames;
import ghidra.app.plugin.core.codebrowser.CodeViewerActionContext;
import ghidra.app.plugin.core.codebrowser.actions.CodeViewerContextAction;
import ghidra.app.services.GoToService;
import ghidra.app.util.HelpTopics;
import ghidra.framework.plugintool.*;
@@ -119,18 +119,13 @@ public class NextPrevCodeUnitPlugin extends Plugin {
bookmarkAction.setDirection(searchForward);
}
private class ToggleDirectionAction extends CodeViewerContextAction {
private class ToggleDirectionAction extends NavigatableContextAction {
Icon forwardIcon = ResourceManager.loadImage("images/down.png");
Icon backwardIcon = ResourceManager.loadImage("images/up.png");
private boolean isForward = true;
ToggleDirectionAction(String subGroup) {
super("Toggle Search Direction", NextPrevCodeUnitPlugin.this.getName());
MenuData menuData =
new MenuData(new String[] { ToolConstants.MENU_NAVIGATION, getName() },
forwardIcon, ToolConstants.MENU_GROUP_NEXT_CODE_UNIT_NAV);
menuData.setMenuSubGroup(subGroup);
setMenuBarData(menuData);
setToolBarData(new ToolBarData(forwardIcon,
ToolConstants.TOOLBAR_GROUP_FOUR, subGroup));
setKeyBindingData(new KeyBindingData(KeyEvent.VK_T, InputEvent.CTRL_DOWN_MASK |
@@ -144,7 +139,7 @@ public class NextPrevCodeUnitPlugin extends Plugin {
}
@Override
public void actionPerformed(CodeViewerActionContext context) {
public void actionPerformed(NavigatableActionContext context) {
isForward = !isForward;
getMenuBarData().setIcon(isForward ? forwardIcon : backwardIcon);
getToolBarData().setIcon(isForward ? forwardIcon : backwardIcon);
@@ -29,6 +29,7 @@ import docking.menu.MultiStateDockingAction;
import docking.tool.ToolConstants;
import docking.widgets.EventTrigger;
import ghidra.app.context.ListingActionContext;
import ghidra.app.context.NavigatableActionContext;
import ghidra.app.nav.Navigatable;
import ghidra.app.plugin.core.codebrowser.CodeViewerActionContext;
import ghidra.app.services.GoToService;
@@ -56,18 +57,13 @@ public class NextPreviousBookmarkAction extends MultiStateDockingAction<String>
public NextPreviousBookmarkAction(PluginTool tool, String owner, String subGroup) {
super("Next Bookmark", owner);
this.tool = tool;
setSupportsDefaultToolContext(true);
ToolBarData toolBarData =
new ToolBarData(bookmarkIcon, ToolConstants.TOOLBAR_GROUP_FOUR);
toolBarData.setToolBarSubGroup(subGroup);
setToolBarData(toolBarData);
MenuData menuData =
new MenuData(new String[] { ToolConstants.MENU_NAVIGATION, getMenuName() },
bookmarkIcon, ToolConstants.MENU_GROUP_NEXT_CODE_UNIT_NAV);
menuData.setMenuSubGroup(subGroup);
setMenuBarData(menuData);
setKeyBindingData(new KeyBindingData(getKeyStroke()));
setHelpLocation(new HelpLocation(HelpTopics.NAVIGATION, getName()));
@@ -93,19 +89,6 @@ public class NextPreviousBookmarkAction extends MultiStateDockingAction<String>
addActionState(warning);
addActionState(custom);
/*BookmarkPlugin bookmarkPlugin = new BookmarkPlugin(tool);
Program program = bookmarkPlugin.getCurrentProgram();
BookmarkManager bookmarkManager = program.getBookmarkManager();
BookmarkType[] bookmarkTypes = bookmarkManager.getBookmarkTypes();
for (BookmarkType bookmarkType : bookmarkTypes) {
ActionState<String> tempBookmarkType =
new ActionState<String>(bookmarkType.getTypeString(), bookmarkUnknownIcon,
bookmarkType.getTypeString());
addActionState(tempBookmarkType);
}*/
setCurrentActionState(allBookmarks); // default
}
@@ -119,8 +102,8 @@ public class NextPreviousBookmarkAction extends MultiStateDockingAction<String>
@Override
protected void doActionPerformed(ActionContext context) {
if (context instanceof ListingActionContext) {
gotoNextPrevious((ListingActionContext) context, this.getCurrentUserData());
if (context instanceof NavigatableActionContext) {
gotoNextPrevious((NavigatableActionContext) context, this.getCurrentUserData());
}
}
@@ -212,7 +195,8 @@ public class NextPreviousBookmarkAction extends MultiStateDockingAction<String>
//==================================================================================================
// AbstractNextPreviousAction Methods
//==================================================================================================
private void gotoNextPrevious(final ListingActionContext context, final String bookmarkType) {
private void gotoNextPrevious(final NavigatableActionContext context,
final String bookmarkType) {
final Address address =
isForward ? getNextAddress(context.getProgram(), context.getAddress(), bookmarkType)
: getPreviousAddress(context.getProgram(), context.getAddress(), bookmarkType);
@@ -225,7 +209,7 @@ public class NextPreviousBookmarkAction extends MultiStateDockingAction<String>
});
}
private void gotoAddress(ListingActionContext listingActionContext, Address address) {
private void gotoAddress(NavigatableActionContext listingActionContext, Address address) {
if (address == null) {
tool.setStatusInfo("Unable to locate another " + getNavigationTypeName() +
" past the current range, in the current direction.");
@@ -264,40 +248,14 @@ public class NextPreviousBookmarkAction extends MultiStateDockingAction<String>
//==================================================================================================
// CodeViewerContextAction Methods
//==================================================================================================
@Override
public boolean isEnabledForContext(ActionContext context) {
if (!(context instanceof CodeViewerActionContext)) {
return false;
}
return isEnabledForContext((CodeViewerActionContext) context);
}
@Override
public boolean isValidContext(ActionContext context) {
if (!(context instanceof CodeViewerActionContext)) {
return false;
}
return isValidContext((CodeViewerActionContext) context);
return context instanceof ListingActionContext;
}
@Override
public boolean isAddToPopup(ActionContext context) {
if (!(context instanceof CodeViewerActionContext)) {
return false;
}
return isAddToPopup((CodeViewerActionContext) context);
}
protected boolean isValidContext(CodeViewerActionContext context) {
return true;
}
protected boolean isEnabledForContext(CodeViewerActionContext context) {
return true;
}
protected boolean isAddToPopup(CodeViewerActionContext context) {
return isEnabledForContext(context);
public boolean isEnabledForContext(ActionContext context) {
return context instanceof ListingActionContext;
}
@Override
@@ -17,7 +17,6 @@ package ghidra.app.plugin.core.progmgr;
import java.awt.Component;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.beans.PropertyEditor;
import java.io.IOException;
import java.net.MalformedURLException;
@@ -26,16 +25,12 @@ import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.atomic.AtomicReference;
import javax.swing.Icon;
import docking.ActionContext;
import docking.DockingUtils;
import docking.action.*;
import docking.action.DockingAction;
import docking.action.builder.ActionBuilder;
import docking.options.editor.*;
import docking.tool.ToolConstants;
import ghidra.app.CorePluginPackage;
import ghidra.app.context.ProgramActionContext;
import ghidra.app.context.ProgramContextAction;
import ghidra.app.events.*;
import ghidra.app.plugin.PluginCategoryNames;
import ghidra.app.services.ProgramManager;
@@ -59,7 +54,6 @@ import ghidra.program.util.*;
import ghidra.util.*;
import ghidra.util.exception.NotFoundException;
import ghidra.util.task.TaskLauncher;
import resources.ResourceManager;
//@formatter:off
@PluginInfo(
@@ -86,13 +80,15 @@ import resources.ResourceManager;
//@formatter:on
public class ProgramManagerPlugin extends Plugin implements ProgramManager {
private static final String SAVE_GROUP = "DomainObjectSave";
private static final String OPEN_GROUP = "DomainObjectOpen";
private MultiProgramManager programMgr;
private ProgramSaveManager programSaveMgr;
private DockingAction openAction;
private DockingAction saveAllAction;
private ProgramContextAction closeAction;
private ProgramContextAction saveAction;
private ProgramContextAction saveAsAction;
private DockingAction closeAction;
private DockingAction saveAction;
private DockingAction saveAsAction;
private DockingAction optionsAction;
private DockingAction closeOthersAction;
private DockingAction closeAllAction;
@@ -101,7 +97,6 @@ public class ProgramManagerPlugin extends Plugin implements ProgramManager {
private boolean locked = false;
private UndoAction undoAction;
private RedoAction redoAction;
private ProgramActionContext lastProgramContext;
private ProgramLocation currentLocation;
public ProgramManagerPlugin(PluginTool tool) {
@@ -527,206 +522,72 @@ public class ProgramManagerPlugin extends Plugin implements ProgramManager {
int subMenuGroupOrder = 1;
openAction = new DockingAction("Open File", getName()) {
@Override
public void actionPerformed(ActionContext context) {
open();
}
};
MenuData menuData =
new MenuData(new String[] { ToolConstants.MENU_FILE, "&Open..." }, "DomainObjectOpen");
menuData.setMenuSubGroup(Integer.toString(subMenuGroupOrder++));
openAction.setMenuBarData(menuData);
openAction.setKeyBindingData(
new KeyBindingData(KeyEvent.VK_O, DockingUtils.CONTROL_KEY_MODIFIER_MASK));
openAction = new ActionBuilder("Open File", getName())
.onAction(c -> open())
.menuPath(ToolConstants.MENU_FILE, "&Open...")
.menuGroup(OPEN_GROUP, Integer.toString(subMenuGroupOrder++))
.keyBinding("ctrl O")
.buildAndInstall(tool);
closeAction = new ProgramContextAction("Close File", getName()) {
@Override
public void actionPerformed(ProgramActionContext programContext) {
closeProgram(programContext.getProgram(), false);
}
closeAction = new ActionBuilder("Close File", getName())
.menuPath(ToolConstants.MENU_FILE, "&Close")
.menuGroup(OPEN_GROUP, Integer.toString(subMenuGroupOrder++))
.withContext(ProgramActionContext.class)
.onAction(c -> closeProgram(c.getProgram(), false))
.buildAndInstall(tool);
@Override
public boolean isValidContext(ActionContext context) {
if (!super.isValidContext(context)) {
getMenuBarData().setMenuItemName("&Close");
setDescription("Close Program");
return false;
}
return true;
}
closeOthersAction = new ActionBuilder("Close Others", getName())
.menuPath(ToolConstants.MENU_FILE, "Close &Others")
.menuGroup(OPEN_GROUP, Integer.toString(subMenuGroupOrder++))
.enabled(false)
.onAction(c -> closeOtherPrograms(false))
.buildAndInstall(tool);
@Override
public boolean isEnabledForContext(ProgramActionContext context) {
Program program = context.getProgram();
String programName = "'" + program.getDomainFile().getName() + "'";
getMenuBarData().setMenuItemName("&Close " + programName);
setDescription("<html>Close " + HTMLUtilities.escapeHTML(programName));
return true;
}
};
String[] closeActionMenuPath = { ToolConstants.MENU_FILE, "&Close" };
menuData = new MenuData(closeActionMenuPath, null, "DomainObjectOpen");
menuData.setMenuSubGroup(Integer.toString(subMenuGroupOrder++));
closeAction.setMenuBarData(menuData);
closeAllAction = new ActionBuilder("Close All", getName())
.menuPath(ToolConstants.MENU_FILE, "Close &All")
.menuGroup(OPEN_GROUP, Integer.toString(subMenuGroupOrder++))
.onAction(c -> closeAllPrograms(false))
.enabled(false)
.buildAndInstall(tool);
closeOthersAction = new DockingAction("Close Others", getName()) {
@Override
public void actionPerformed(ActionContext context) {
closeOtherPrograms(false);
}
};
closeOthersAction.setEnabled(false);
String[] menuPath = { ToolConstants.MENU_FILE, "Close &Others" };
menuData = new MenuData(menuPath, null, "DomainObjectOpen");
menuData.setMenuSubGroup(Integer.toString(subMenuGroupOrder++));
closeOthersAction.setMenuBarData(menuData);
saveAction = new ActionBuilder("Save File", "&Save")
.menuPath(ToolConstants.MENU_FILE, "Close &All")
.description("Save Program")
.menuGroup(SAVE_GROUP, Integer.toString(subMenuGroupOrder++))
.menuIcon(null)
.toolBarIcon("images/disk.png")
.toolBarGroup(ToolConstants.TOOLBAR_GROUP_ONE)
.keyBinding("ctrl S")
.withContext(ProgramActionContext.class)
.enabledWhen(c -> c.getProgram().isChanged())
.onAction(c -> programSaveMgr.saveProgram(c.getProgram()))
.buildAndInstall(tool);
closeAllAction = new DockingAction("Close All", getName()) {
@Override
public void actionPerformed(ActionContext context) {
closeAllPrograms(false);
}
};
closeAllAction.setEnabled(false);
String[] nenuPath = { ToolConstants.MENU_FILE, "Close &All" };
menuData = new MenuData(nenuPath, null, "DomainObjectOpen");
menuData.setMenuSubGroup(Integer.toString(subMenuGroupOrder++));
closeAllAction.setMenuBarData(menuData);
saveAsAction = new ActionBuilder("Save As File", getName())
.menuPath(ToolConstants.MENU_FILE, "Save &As...")
.menuGroup(SAVE_GROUP, Integer.toString(subMenuGroupOrder++))
.withContext(ProgramActionContext.class)
.onAction(c -> programSaveMgr.saveAs(c.getProgram()))
.buildAndInstall(tool);
saveAction = new ProgramContextAction("Save File", getName()) {
@Override
public void actionPerformed(ProgramActionContext programContext) {
programSaveMgr.saveProgram(programContext.getProgram());
// setEnabled(false);
}
saveAllAction = new ActionBuilder("Save All Files", getName())
.menuPath(ToolConstants.MENU_FILE, "Save All")
.description("Save All Programs")
.menuGroup(SAVE_GROUP, Integer.toString(subMenuGroupOrder++))
.onAction(c -> programSaveMgr.saveChangedPrograms())
.buildAndInstall(tool);
@Override
public boolean isValidContext(ActionContext context) {
lastProgramContext = null;
if (!super.isValidContext(context)) {
getMenuBarData().setMenuItemName("&Save");
setDescription("Save Program");
return false;
}
return true;
}
@Override
public boolean isEnabledForContext(ProgramActionContext context) {
lastProgramContext = context;
Program program = context.getProgram();
String programName = "'" + program.getDomainFile().getName() + "'";
getMenuBarData().setMenuItemName("&Save " + programName);
setDescription("Save " + programName);
return program.isChanged();
}
@Override
protected boolean isValidContext(ProgramActionContext context) {
return super.isValidContext(context);
}
};
String[] saveMenuPath = { ToolConstants.MENU_FILE, "&Save" };
Icon saveIcon = ResourceManager.loadImage("images/disk.png");
String saveGroup = ToolConstants.TOOLBAR_GROUP_ONE;
subMenuGroupOrder = 0;
menuData = new MenuData(saveMenuPath, saveIcon, saveGroup);
menuData.setMenuSubGroup(Integer.toString(subMenuGroupOrder++));
saveAction.setMenuBarData(menuData);
saveAction.setToolBarData(new ToolBarData(saveIcon, saveGroup));
saveAction
.setKeyBindingData(new KeyBindingData('S', DockingUtils.CONTROL_KEY_MODIFIER_MASK));
saveAction.setDescription("Save Program");
saveAsAction = new ProgramContextAction("Save As File", getName()) {
@Override
public void actionPerformed(ProgramActionContext programContext) {
programSaveMgr.saveAs(programContext.getProgram());
}
@Override
public boolean isValidContext(ActionContext context) {
if (!super.isValidContext(context)) {
getMenuBarData().setMenuItemName("Save &As...");
setDescription("Save &As...");
return false;
}
return true;
}
@Override
public boolean isEnabledForContext(ProgramActionContext context) {
Program program = context.getProgram();
String programName = "'" + program.getDomainFile().getName() + "'";
String menuName = "Save " + programName + " &As...";
getMenuBarData().setMenuItemName(menuName);
setDescription(menuName);
return true;
}
};
String[] saveAsPath = { ToolConstants.MENU_FILE, "Save &As..." };
menuData = new MenuData(saveAsPath, null, "DomainObjectSave");
menuData.setMenuSubGroup(Integer.toString(subMenuGroupOrder++));
saveAsAction.setMenuBarData(menuData);
saveAllAction = new DockingAction("Save All Files", getName()) {
@Override
public void actionPerformed(ActionContext context) {
programSaveMgr.saveChangedPrograms();
}
};
menuData =
new MenuData(new String[] { ToolConstants.MENU_FILE, "Save All" }, "DomainObjectSave");
menuData.setMenuSubGroup(Integer.toString(subMenuGroupOrder++));
saveAllAction.setMenuBarData(menuData);
saveAllAction.setDescription("Save All Programs");
optionsAction = new ProgramContextAction("Program Options", getName()) {
@Override
public void actionPerformed(ProgramActionContext programContext) {
showProgramOptions(programContext.getProgram());
}
@Override
public boolean isValidContext(ActionContext context) {
if (!super.isValidContext(context)) {
getMenuBarData().setMenuItemName("Program Options");
return false;
}
return true;
}
@Override
public boolean isEnabledForContext(ProgramActionContext context) {
lastProgramContext = context;
Program program = context.getProgram();
String programName = program.getDomainFile().getName();
getMenuBarData().setMenuItemName("Options for " + programName + "...");
return true;
}
};
String[] optionsPath = { ToolConstants.MENU_EDIT, "P&rogram Options..." };
menuData = new MenuData(optionsPath, null, ToolConstants.TOOL_OPTIONS_MENU_GROUP);
// update these options to appear below those for the tool, which we know is defined
// inside of ToolConstants
menuData.setMenuSubGroup(ToolConstants.TOOL_OPTIONS_MENU_GROUP + "b");
optionsAction.setMenuBarData(menuData);
optionsAction.setDescription("Edit Options for current program");
optionsAction = new ActionBuilder("Program Options", getName())
.menuPath(ToolConstants.MENU_EDIT, "P&rogram Options...")
.description("Edit Options for current program")
.menuGroup(ToolConstants.TOOL_OPTIONS_MENU_GROUP,
ToolConstants.TOOL_OPTIONS_MENU_GROUP + "b")
.withContext(ProgramActionContext.class)
.onAction(c -> showProgramOptions(c.getProgram()))
.buildAndInstall(tool);
undoAction = new UndoAction(tool, getName());
redoAction = new RedoAction(tool, getName());
tool.addAction(openAction);
tool.addAction(closeAction);
tool.addAction(closeOthersAction);
tool.addAction(closeAllAction);
tool.addAction(saveAction);
tool.addAction(saveAsAction);
tool.addAction(saveAllAction);
tool.addAction(optionsAction);
tool.addAction(undoAction);
tool.addAction(redoAction);
}
@@ -791,6 +652,10 @@ public class ProgramManagerPlugin extends Plugin implements ProgramManager {
private void updateActions() {
Program p = programMgr.getCurrentProgram();
updateCloseAction(p);
updateProgramOptionsAction(p);
updateSaveAction(p);
updateSaveAsAction(p);
closeAllAction.setEnabled(p != null);
optionsAction.setEnabled(p != null);
Program[] programList = programMgr.getAllPrograms();
@@ -805,6 +670,54 @@ public class ProgramManagerPlugin extends Plugin implements ProgramManager {
tool.contextChanged(null);
}
private void updateSaveAction(Program p) {
if (p == null) {
saveAction.getMenuBarData().setMenuItemName("&Save");
saveAction.setDescription("Save Program");
saveAction.setEnabled(false);
}
else {
String programName = "'" + p.getDomainFile().getName() + "'";
saveAction.getMenuBarData().setMenuItemName("&Save " + programName);
saveAction.setDescription("Save " + programName);
saveAction.setEnabled(p.isChanged());
}
}
private void updateSaveAsAction(Program p) {
if (p == null) {
saveAsAction.getMenuBarData().setMenuItemName("Save &As...");
}
else {
String programName = "'" + p.getDomainFile().getName() + "'";
saveAsAction.getMenuBarData().setMenuItemName("Save " + programName + " &As...");
}
}
private void updateProgramOptionsAction(Program p) {
if (p == null) {
optionsAction.getMenuBarData().setMenuItemName("Program Options");
}
else {
String programName = "'" + p.getDomainFile().getName() + "'";
optionsAction.getMenuBarData().setMenuItemName("Options for " + programName + "...");
}
optionsAction.setEnabled(p != null);
}
private void updateCloseAction(Program p) {
if (p == null) {
closeAction.getMenuBarData().setMenuItemName("&Close");
closeAction.setDescription("Close Program");
}
else {
String programName = "'" + p.getDomainFile().getName() + "'";
closeAction.getMenuBarData().setMenuItemName("&Close " + programName);
closeAction.setDescription("<html>Close " + HTMLUtilities.escapeHTML(programName));
}
closeAction.setEnabled(p != null);
}
private void open() {
if (openDialog == null) {
ActionListener listener = e -> {
@@ -875,17 +788,11 @@ public class ProgramManagerPlugin extends Plugin implements ProgramManager {
void updateProgramActions() {
updateSaveAllAction();
if (lastProgramContext != null) {
updateProgramAction(undoAction);
updateProgramAction(redoAction);
updateProgramAction(saveAction);
updateProgramAction(saveAsAction);
}
}
private void updateProgramAction(ProgramContextAction action) {
boolean isEnabled = action.isEnabledForContext(lastProgramContext);
action.setEnabled(isEnabled);
Program p = getCurrentProgram();
updateSaveAction(getCurrentProgram());
updateSaveAsAction(getCurrentProgram());
undoAction.update(p);
redoAction.update(p);
}
private void updateSaveAllAction() {
@@ -15,12 +15,10 @@
*/
package ghidra.app.plugin.core.progmgr;
import java.awt.event.InputEvent;
import java.io.IOException;
import javax.swing.Icon;
import docking.ActionContext;
import docking.action.*;
import docking.tool.ToolConstants;
import ghidra.app.context.ProgramActionContext;
@@ -46,7 +44,7 @@ public class RedoAction extends ProgramContextAction {
menuData.setMenuSubGroup("2Redo"); // make this appear below the undo menu item
setMenuBarData(menuData);
setToolBarData(new ToolBarData(icon, group));
setKeyBindingData(new KeyBindingData('Z', InputEvent.CTRL_MASK | InputEvent.SHIFT_MASK));
setKeyBindingData(new KeyBindingData("ctrl shift Z"));
setDescription("Redo");
}
@@ -62,18 +60,41 @@ public class RedoAction extends ProgramContextAction {
}
}
@Override
protected boolean isEnabledForContext(ProgramActionContext context) {
Program program = context.getProgram();
if (program.canRedo()) {
/**
* updates the menu name of the action as the undo stack changes
* <P>
* NOTE: currently, we must manage the enablement explicitly
* because contextChanged is not called for data changes. Ideally, the enablement
* would be handled by the context, but for now it doesn't work
*
* @param program the program
*/
public void update(Program program) {
if (program == null) {
getMenuBarData().setMenuItemName("Redo ");
setDescription("");
setEnabled(false);
}
else if (program.canRedo()) {
String programName = program.getDomainFile().getName();
getMenuBarData().setMenuItemName("Redo " + programName);
String tip = HTMLUtilities.toWrappedHTML(
"Redo " + HTMLUtilities.escapeHTML(program.getRedoName()));
setDescription(tip);
return true;
setEnabled(true);
}
return false;
else {
setDescription("Redo");
setEnabled(false);
}
}
@Override
protected boolean isEnabledForContext(ProgramActionContext context) {
Program program = context.getProgram();
return program.canRedo();
}
private void saveCurrentLocationToHistory() {
@@ -84,13 +105,4 @@ public class RedoAction extends ProgramContextAction {
}
}
@Override
public boolean isEnabledForContext(ActionContext actionContext) {
if (!super.isEnabledForContext(actionContext)) {
setDescription("Redo");
getMenuBarData().setMenuItemName("Redo");
return false;
}
return true;
}
}
@@ -15,12 +15,10 @@
*/
package ghidra.app.plugin.core.progmgr;
import java.awt.event.InputEvent;
import java.io.IOException;
import javax.swing.Icon;
import docking.ActionContext;
import docking.action.*;
import docking.tool.ToolConstants;
import ghidra.app.context.ProgramActionContext;
@@ -46,7 +44,7 @@ public class UndoAction extends ProgramContextAction {
setMenuBarData(menuData);
setToolBarData(new ToolBarData(icon, "Undo"));
setDescription("Undo");
setKeyBindingData(new KeyBindingData('Z', InputEvent.CTRL_MASK));
setKeyBindingData(new KeyBindingData("ctrl Z"));
}
@Override
@@ -69,27 +67,39 @@ public class UndoAction extends ProgramContextAction {
}
}
@Override
protected boolean isEnabledForContext(ProgramActionContext context) {
Program program = context.getProgram();
if (program.canUndo()) {
/**
* updates the menu name of the action as the undo stack changes
* <P>
* NOTE: currently, we must manage the enablement explicitly
* because contextChanged is not called for data changes. Ideally, the enablement
* would be handled by the context, but for now it doesn't work
*
* @param program the program
*/
public void update(Program program) {
if (program == null) {
getMenuBarData().setMenuItemName("Undo ");
setDescription("");
setEnabled(false);
}
if (program != null && program.canUndo()) {
String programName = program.getDomainFile().getName();
getMenuBarData().setMenuItemName("Undo " + programName);
String tip = HTMLUtilities.toWrappedHTML(
"Undo " + HTMLUtilities.escapeHTML(program.getUndoName()));
setDescription(tip);
return true;
setEnabled(true);
}
else {
setDescription("Undo");
setEnabled(false);
}
return false;
}
@Override
public boolean isEnabledForContext(ActionContext actionContext) {
if (!super.isEnabledForContext(actionContext)) {
setDescription("Undo");
getMenuBarData().setMenuItemName("Undo");
return false;
}
return true;
protected boolean isEnabledForContext(ProgramActionContext context) {
Program program = context.getProgram();
return program.canUndo();
}
}
@@ -145,7 +145,7 @@ public class ScalarSearchPlugin extends ProgramPlugin implements DomainObjectLis
}
@Override
protected boolean isValidNavigationContext(NavigatableActionContext context) {
protected boolean isEnabledForContext(NavigatableActionContext context) {
return !(context instanceof RestrictedAddressSetContext);
}
};
@@ -350,7 +350,7 @@ public class MemSearchPlugin extends Plugin implements OptionsChangeListener,
}
@Override
protected boolean isValidNavigationContext(NavigatableActionContext context) {
protected boolean isEnabledForContext(NavigatableActionContext context) {
return !(context instanceof RestrictedAddressSetContext);
}
};
@@ -369,13 +369,8 @@ public class MemSearchPlugin extends Plugin implements OptionsChangeListener,
}
@Override
public boolean isEnabledForContext(NavigatableActionContext context) {
return searchInfo != null;
}
@Override
protected boolean isValidNavigationContext(NavigatableActionContext context) {
return !(context instanceof RestrictedAddressSetContext);
protected boolean isEnabledForContext(NavigatableActionContext context) {
return !(context instanceof RestrictedAddressSetContext) && searchInfo != null;
}
};
searchAgainAction.setHelpLocation(
@@ -16,8 +16,6 @@
package ghidra.app.plugin.core.searchtext;
import java.awt.*;
import java.awt.event.InputEvent;
import java.awt.event.KeyEvent;
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Matcher;
@@ -26,13 +24,15 @@ import java.util.regex.Pattern;
import javax.swing.ImageIcon;
import docking.*;
import docking.action.*;
import docking.action.DockingAction;
import docking.action.builder.ActionBuilder;
import docking.tool.ToolConstants;
import docking.widgets.fieldpanel.support.Highlight;
import docking.widgets.table.threaded.*;
import ghidra.GhidraOptions;
import ghidra.app.CorePluginPackage;
import ghidra.app.context.*;
import ghidra.app.context.ListingActionContext;
import ghidra.app.context.NavigatableActionContext;
import ghidra.app.nav.Navigatable;
import ghidra.app.nav.NavigatableRemovalListener;
import ghidra.app.plugin.PluginCategoryNames;
@@ -379,49 +379,34 @@ public class SearchTextPlugin extends ProgramPlugin implements OptionsChangeList
private void createActions() {
String subGroup = getClass().getName();
searchAction = new ListingContextAction("Search Text", getName()) {
@Override
public void actionPerformed(ListingActionContext context) {
setNavigatable(context.getNavigatable());
displayDialog(context);
}
};
searchAction.setHelpLocation(new HelpLocation(HelpTopics.SEARCH, searchAction.getName()));
String[] menuPath = new String[] { "&Search", "Program &Text..." };
MenuData menuData = new MenuData(menuPath, "search");
menuData.setMenuSubGroup(subGroup);
searchAction.setMenuBarData(menuData);
searchAction.setKeyBindingData(new KeyBindingData(KeyEvent.VK_E,
InputEvent.CTRL_DOWN_MASK | InputEvent.SHIFT_DOWN_MASK));
searchAction = new ActionBuilder("Search Text", getName())
.menuPath("&Search", "Program &Text...")
.menuGroup("search", subGroup)
.keyBinding("ctrl shift E")
.description(DESCRIPTION)
.helpLocation(new HelpLocation(HelpTopics.SEARCH, "Search Text"))
.withContext(NavigatableActionContext.class)
.supportsDefaultToolContext(true)
.onAction(c -> {
setNavigatable(c.getNavigatable());
displayDialog(c);
})
.buildAndInstall(tool);
searchAction.setDescription(DESCRIPTION);
searchAction.setEnabled(false);
//searchAction.setAddToPopup(false);
tool.addAction(searchAction);
searchAgainAction = new ListingContextAction("Repeat Text Search", getName()) {
@Override
public void actionPerformed(ListingActionContext context) {
setNavigatable(context.getNavigatable());
searchDialog.repeatSearch();
}
@Override
public boolean isEnabledForContext(ListingActionContext context) {
return searchedOnce;
}
};
searchAgainAction.setHelpLocation(
new HelpLocation(HelpTopics.SEARCH, searchAgainAction.getName()));
menuPath = new String[] { "&Search", "Repeat Text Search" };
menuData = new MenuData(menuPath, "search");
menuData.setMenuSubGroup(subGroup);
searchAgainAction.setMenuBarData(menuData);
searchAgainAction.setKeyBindingData(new KeyBindingData(KeyEvent.VK_F3,
InputEvent.CTRL_DOWN_MASK | InputEvent.SHIFT_DOWN_MASK));
searchAgainAction.setDescription(DESCRIPTION);
tool.addAction(searchAgainAction);
searchAgainAction = new ActionBuilder("Repeat Text Search", getName())
.menuPath("&Search", "Repeat Text Search")
.menuGroup("search", subGroup)
.keyBinding("ctrl shift F3")
.description(DESCRIPTION)
.supportsDefaultToolContext(true)
.helpLocation(new HelpLocation(HelpTopics.SEARCH, "Repeat Text Search"))
.withContext(NavigatableActionContext.class)
.enabledWhen(c -> searchedOnce)
.onAction(c -> {
setNavigatable(c.getNavigatable());
searchDialog.repeatSearch();
})
.buildAndInstall(tool);
}
protected void updateNavigatable(ActionContext context) {
@@ -15,14 +15,14 @@
*/
package ghidra.app.plugin.core.select.flow;
import docking.action.MenuData;
import docking.tool.ToolConstants;
import ghidra.app.context.ListingActionContext;
import ghidra.app.context.ListingContextAction;
import ghidra.app.util.HelpTopics;
import ghidra.program.model.address.Address;
import ghidra.program.model.listing.CodeUnit;
import ghidra.util.HelpLocation;
import docking.action.MenuData;
import docking.tool.ToolConstants;
/**
* <CODE>SelectByFlowAction</CODE> allows the user to Select Code By Flowing from
@@ -63,6 +63,9 @@ class SelectByFlowAction extends ListingContextAction {
this.selectByFlowPlugin = plugin;
this.selectionType = selectionType;
// this is in the main tool menu, so make it a tool action
setSupportsDefaultToolContext(true);
String[] menuPath = null;
if (selectionType == SelectByFlowPlugin.SELECT_FUNCTIONS) {
menuPath = new String[] { ToolConstants.MENU_SELECTION, "Function" };
@@ -91,11 +94,6 @@ class SelectByFlowAction extends ListingContextAction {
setHelpLocation(new HelpLocation(HelpTopics.SELECTION, getName()));
}
/**
* Method called when the action is invoked.
*
* @param ActionEvent details regarding the invocation of this action
*/
@Override
public void actionPerformed(ListingActionContext context) {
// Either select by following all flows or all flows except calls
@@ -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,8 +15,13 @@
*/
package ghidra.app.plugin.core.select.reference;
import ghidra.app.context.ListingContextAction;
import ghidra.app.context.ListingActionContext;
import java.awt.event.InputEvent;
import java.awt.event.KeyEvent;
import docking.action.KeyBindingData;
import docking.action.MenuData;
import ghidra.app.context.NavigatableActionContext;
import ghidra.app.context.NavigatableContextAction;
import ghidra.app.nav.NavigationUtils;
import ghidra.app.util.HelpTopics;
import ghidra.framework.plugintool.PluginTool;
@@ -27,13 +31,7 @@ import ghidra.program.model.symbol.Reference;
import ghidra.program.util.ProgramSelection;
import ghidra.util.HelpLocation;
import java.awt.event.InputEvent;
import java.awt.event.KeyEvent;
import docking.action.KeyBindingData;
import docking.action.MenuData;
public class SelectForwardRefsAction extends ListingContextAction {
public class SelectForwardRefsAction extends NavigatableContextAction {
private final PluginTool tool;
@@ -42,47 +40,47 @@ public class SelectForwardRefsAction extends ListingContextAction {
this.tool = tool;
String group = "references";
setMenuBarData( new MenuData( new String[] {"Select", "Forward Refs"}, null, group ) );
setKeyBindingData( new KeyBindingData( KeyEvent.VK_PERIOD, InputEvent.CTRL_MASK ) );
setMenuBarData(new MenuData(new String[] { "Select", "Forward Refs" }, null, group));
setKeyBindingData(new KeyBindingData(KeyEvent.VK_PERIOD, InputEvent.CTRL_MASK));
setHelpLocation(new HelpLocation(HelpTopics.SELECTION, "Forward"));
// setKeyBindingData( new KeyBindingData(KeyEvent.VK_SEMICOLON, InputEvent.CTRL_MASK ) );
// setHelpLocation(new HelpLocation(HelpTopics.SELECTION, "Backward"));
}
@Override
protected boolean isEnabledForContext(ListingActionContext context) {
protected boolean isEnabledForContext(NavigatableActionContext context) {
return context.getAddress() != null || context.hasSelection();
}
/**
* Method called when the action is invoked.
* @param ActionEvent details regarding the invocation of this action
*/
@Override
public void actionPerformed(ListingActionContext context) {
AddressSetView addressSet = context.hasSelection() ?
context.getSelection() :
new AddressSet(context.getAddress());
public void actionPerformed(NavigatableActionContext context) {
AddressSetView addressSet =
context.hasSelection() ? context.getSelection() : new AddressSet(context.getAddress());
ProgramSelection selection = getSelection(context.getProgram(), addressSet);
NavigationUtils.setSelection(tool, context.getNavigatable(), selection);
}
private ProgramSelection getSelection(Program program, AddressSetView addressSetView){
private ProgramSelection getSelection(Program program, AddressSetView addressSetView) {
AddressSet addressSet = new AddressSet();
CodeUnitIterator iter = program.getListing().getCodeUnits(addressSetView,true);
CodeUnitIterator iter = program.getListing().getCodeUnits(addressSetView, true);
while (iter.hasNext()){
CodeUnit cu=iter.next();
Reference[] memRef=cu.getReferencesFrom();
for (int i=0;i<memRef.length;i++){
Address addr = memRef[i].getToAddress();
if ( addr.isMemoryAddress() ) {
addressSet.addRange(addr,addr);
while (iter.hasNext()) {
CodeUnit cu = iter.next();
Reference[] memRef = cu.getReferencesFrom();
for (Reference element : memRef) {
Address addr = element.getToAddress();
if (addr.isMemoryAddress()) {
addressSet.addRange(addr, addr);
}
}
}
return new ProgramSelection(addressSet);
@@ -220,7 +220,10 @@ public class DecompilerProvider extends NavigatableComponentProviderAdapter
return null;
}
Function function = controller.getFunction();
Address entryPoint = function != null ? function.getEntryPoint() : null;
if (function == null) {
return null;
}
Address entryPoint = function.getEntryPoint();
boolean isDecompiling = controller.isDecompiling();
return new DecompilerActionContext(this, entryPoint, isDecompiling);
}
@@ -253,7 +253,7 @@ public class ActionContext {
public ActionContext getGlobalContext() {
if (globalContext == null) {
Tool tool = getTool();
globalContext = tool == null ? new ActionContext() : tool.getGlobalActionContext();
globalContext = tool == null ? new ActionContext() : tool.getDefaultToolContext();
}
return globalContext;
}
@@ -228,4 +228,14 @@ public class DockingActionProxy
public String toString() {
return dockingAction.toString();
}
@Override
public void setSupportsDefaultToolContext(boolean newValue) {
dockingAction.setSupportsDefaultToolContext(newValue);
}
@Override
public boolean supportsDefaultToolContext() {
return dockingAction.supportsDefaultToolContext();
}
}
@@ -2161,14 +2161,45 @@ public class DockingWindowManager implements PropertyChangeListener, Placeholder
}
/**
* Returns the global action context for the tool
* @return the global action context for the tool
* Returns the default action context for the tool
* @return the default action context for the tool
*/
public ActionContext getGlobalActionContext() {
public ActionContext getDefaultToolContext() {
return defaultProvider == null ? new ActionContext()
: defaultProvider.getActionContext(null);
}
/**
* Gets the {@link ActionContext} appropriate for the given action. This will normally
* be the context from the currently focused {@link ComponentProvider}. If that
* context is not valid for the given action and the action supports using the default
* tool context, then the default tool context will be returned. Otherwise, returns null.
*
* @param action the action for which to get an {@link ActionContext}
* @return the {@link ActionContext} appropriate for the given action or null
*/
public ActionContext getActionContext(DockingActionIf action) {
ComponentProvider provider = getActiveComponentProvider();
ActionContext context = provider == null ? null : provider.getActionContext(null);
if (context == null) {
context = new ActionContext(provider, null);
}
if (action.isValidContext(context)) {
return context;
}
if (action.supportsDefaultToolContext()) {
ActionContext toolContext = getDefaultToolContext();
if (action.isValidContext(toolContext)) {
return toolContext;
}
}
return context;
}
void notifyContextListeners(ComponentPlaceholder placeHolder, ActionContext actionContext) {
if (placeHolder == focusedPlaceholder) {
@@ -19,12 +19,12 @@ import docking.action.DockingActionIf;
import docking.action.ToggleDockingActionIf;
import generic.json.Json;
public class ExecutableKeyActionAdapter {
public class ExecutableAction {
DockingActionIf action;
ActionContext context;
public ExecutableKeyActionAdapter(DockingActionIf action, ActionContext context) {
public ExecutableAction(DockingActionIf action, ActionContext context) {
this.action = action;
this.context = context;
}
@@ -46,9 +46,10 @@ public class MenuBarMenuHandler extends MenuHandler {
DockingWindowManager.clearMouseOverHelp();
ComponentProvider provider = windowManager.getActiveComponentProvider();
ActionContext providerContext = provider == null ? null : provider.getActionContext(null);
ActionContext context = providerContext == null ? new ActionContext() : providerContext;
ActionContext context = windowManager.getActionContext(action);
if (context == null) {
return; // nothing to do
}
context.setSourceObject(event.getSource());
@@ -33,7 +33,7 @@ import docking.widgets.label.GLabel;
public class MultiActionDialog extends DialogComponentProvider {
private String keystrokeName;
private List<ExecutableKeyActionAdapter> list;
private List<ExecutableAction> list;
private JList<String> actionList;
private DefaultListModel<String> listModel;
@@ -42,7 +42,7 @@ public class MultiActionDialog extends DialogComponentProvider {
* @param keystrokeName keystroke name
* @param list list of actions
*/
public MultiActionDialog(String keystrokeName, List<ExecutableKeyActionAdapter> list) {
public MultiActionDialog(String keystrokeName, List<ExecutableAction> list) {
super("Select Action", true);
this.keystrokeName = keystrokeName;
init();
@@ -65,7 +65,7 @@ public class MultiActionDialog extends DialogComponentProvider {
close();
ExecutableKeyActionAdapter actionProxy = list.get(index);
ExecutableAction actionProxy = list.get(index);
actionProxy.execute();
}
@@ -73,12 +73,12 @@ public class MultiActionDialog extends DialogComponentProvider {
* Set the list of actions that are enabled
* @param list list of actions selected
*/
public void setActionList(List<ExecutableKeyActionAdapter> list) {
public void setActionList(List<ExecutableAction> list) {
okButton.setEnabled(false);
this.list = list;
listModel.clear();
for (int i = 0; i < list.size(); i++) {
ExecutableKeyActionAdapter actionProxy = list.get(i);
ExecutableAction actionProxy = list.get(i);
DockingActionIf action = actionProxy.getAction();
listModel.addElement(action.getName() + " (" + action.getOwnerDescription() + ")");
}
@@ -305,11 +305,10 @@ public interface Tool extends ServiceProvider {
public void close();
/**
* Returns the global action context for the tool. The global context is the context of
* the default focused component, instead of the normal action context which is the current
* focused component.
* @return the global action context for the tool
* Returns the default {@link ActionContext} for the tool. The default context is the context
* the default ComponentProvider for the tool.
* @return the default {@link ActionContext} for the tool
*/
public ActionContext getGlobalActionContext();
public ActionContext getDefaultToolContext();
}
@@ -120,12 +120,8 @@ public class WindowActionManager {
return;
}
ComponentProvider provider = placeHolderForScheduledActionUpdate == null ? null
: placeHolderForScheduledActionUpdate.getProvider();
ActionContext localContext = provider == null ? null : provider.getActionContext(null);
if (localContext == null) {
localContext = new ActionContext();
}
ActionContext localContext = getContext();
ActionContext globalContext = winMgr.getDefaultToolContext();
// Update actions - make a copy so that we don't get concurrent modification exceptions
List<DockingActionIf> list = new ArrayList<>(actionToProxyMap.values());
@@ -133,6 +129,9 @@ public class WindowActionManager {
if (action.isValidContext(localContext)) {
action.setEnabled(action.isEnabledForContext(localContext));
}
else if (isValidDefaultToolContext(action, globalContext)) {
action.setEnabled(action.isEnabledForContext(globalContext));
}
else {
action.setEnabled(false);
}
@@ -140,4 +139,21 @@ public class WindowActionManager {
// Notify listeners if the context provider is the focused provider
winMgr.notifyContextListeners(placeHolderForScheduledActionUpdate, localContext);
}
private boolean isValidDefaultToolContext(DockingActionIf action, ActionContext toolContext) {
return action.supportsDefaultToolContext() &&
action.isValidContext(toolContext);
}
private ActionContext getContext() {
ComponentProvider provider = placeHolderForScheduledActionUpdate == null ? null
: placeHolderForScheduledActionUpdate.getProvider();
ActionContext context = provider == null ? null : provider.getActionContext(null);
if (context == null) {
context = new ActionContext();
}
return context;
}
}
@@ -77,6 +77,8 @@ public abstract class DockingAction implements DockingActionIf {
private Predicate<ActionContext> popupPredicate;
private Predicate<ActionContext> validContextPredicate;
private boolean supportsDefaultToolContext;
public DockingAction(String name, String owner) {
this.name = name;
this.owner = owner;
@@ -224,6 +226,16 @@ public abstract class DockingAction implements DockingActionIf {
return !isEnabled;
}
@Override
public void setSupportsDefaultToolContext(boolean newValue) {
supportsDefaultToolContext = newValue;
}
@Override
public boolean supportsDefaultToolContext() {
return supportsDefaultToolContext;
}
@Override
public final JButton createButton() {
JButton button = doCreateButton();
@@ -33,6 +33,26 @@ import docking.help.HelpDescriptor;
* 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.
*
* <p>ActionContext is a key concept for tool actions so that they can be context sensitive if
* appropriate. The context provides a
* consistent way for plugins and components to share tool state with actions. Actions can then
* use that context to make decisions, such as if they should be enabled or added to a popup menu.
* The context information is also typically used when the action is invoked. For example, an
* action context from a table element may provide the row in a table component that is selected and
* then a "delete table row" action can use that information to be enabled when a table selection
* exists and then delete that row if the action is invoked.
*
* <p> To make the overall action experience more convenient for the user, action processing
* supports the concept of a "default tool context". This allows actions to work on a more global
* level than just the component that is focused. The idea is that if an action is not valid for
* the current focused context (and it has be declared to work this way using
* the {@link #setSupportsDefaultToolContext(boolean)}), then it can be validated against the default
* tool context. The "default tool context" is defined to be the action context of the tool's
* primary component. This is primarily intended for tool-level actions which are the ones that appear
* in the tool's main menu bar or toolbar. This allows the tool actions to mostly work on the
* tool's main component context regardless of what has focus, and yet still work on the
* focused component if appropriate (such as a snapshot of the main component).
*/
public interface DockingActionIf extends HelpDescriptor {
public static final String ENABLEMENT_PROPERTY = "enabled";
@@ -97,6 +117,26 @@ public interface DockingActionIf extends HelpDescriptor {
*/
public boolean setEnabled(boolean newValue);
/**
* Sets whether or not this action should be activated using the default tool context if the
* current focused provider's context is not valid for this action. Typically, this should
* be set on actions that are mostly independent of which component has focus such as those
* on the tool's main toolbar.
*
* @param newValue if true, the action will be activated using the default tool context if the
* local context is not valid for this action. If false, the action will only ever be
* activated using the focused context.
*/
public void setSupportsDefaultToolContext(boolean newValue);
/**
* Returns true if this action can be activated using the default tool context if the focused
* context is invalid for this action. See {@link #setSupportsDefaultToolContext(boolean)}
* @return true if this action can be activated using the default tool context if the local
* context is invalid for this action.
*/
public boolean supportsDefaultToolContext();
/**
* Returns true if the action is enabled.
*
@@ -120,7 +160,7 @@ public interface DockingActionIf extends HelpDescriptor {
/**
* Returns the {@link ToolBarData} to be used to put this action in a toolbar. The ToolBarData will be
* null if the action in not set to be in a tool bar.
* null if the action in not set to be in a toolbar.
* @return the {@link ToolBarData} for the popup menu or null if the action is not in a popup menu.
*/
public ToolBarData getToolBarData();
@@ -36,6 +36,18 @@ public class KeyBindingData {
this(KeyStroke.getKeyStroke(keyCode, modifiers));
}
public KeyBindingData(String keyStrokeString) {
this(parseKeyStrokeString(keyStrokeString));
}
private static KeyStroke parseKeyStrokeString(String keyStrokeString) {
KeyStroke keyStroke = KeyBindingUtils.parseKeyStroke(keyStrokeString);
if (keyStroke == null) {
throw new IllegalArgumentException("Invalid keystroke string: " + keyStrokeString);
}
return keyStroke;
}
public KeyBindingData(KeyStroke keyStroke, KeyBindingPrecedence precedence) {
if (precedence == KeyBindingPrecedence.ReservedActionsLevel) {
throw new IllegalArgumentException(
@@ -114,7 +114,7 @@ public class MultipleKeyAction extends DockingKeyBindingAction {
@Override
public void actionPerformed(final ActionEvent event) {
// Build list of actions which are valid in current context
List<ExecutableKeyActionAdapter> list = getActionsForCurrentContext(event.getSource());
List<ExecutableAction> list = getActionsForCurrentOrDefaultContext(event.getSource());
// If menu active, disable all key bindings
if (ignoreActionWhileMenuShowing()) {
@@ -137,7 +137,7 @@ public class MultipleKeyAction extends DockingKeyBindingAction {
Swing.runLater(() -> DockingWindowManager.showDialog(dialog));
}
else if (list.size() == 1) {
final ExecutableKeyActionAdapter actionProxy = list.get(0);
ExecutableAction actionProxy = list.get(0);
tool.setStatusInfo("");
actionProxy.execute();
}
@@ -156,8 +156,9 @@ public class MultipleKeyAction extends DockingKeyBindingAction {
return menuManager.getSelectedPath().length != 0;
}
private List<ExecutableKeyActionAdapter> getValidContextActions(ActionContext localContext) {
List<ExecutableKeyActionAdapter> list = new ArrayList<>();
private List<ExecutableAction> getValidContextActions(ActionContext localContext,
ActionContext globalContext) {
List<ExecutableAction> list = new ArrayList<>();
boolean hasLocalActionsForKeyBinding = false;
//
@@ -167,14 +168,15 @@ public class MultipleKeyAction extends DockingKeyBindingAction {
if (actionData.isMyProvider(localContext)) {
hasLocalActionsForKeyBinding = true;
if (isValidAndEnabled(actionData, localContext)) {
list.add(new ExecutableKeyActionAdapter(actionData.action, localContext));
list.add(new ExecutableAction(actionData.action, localContext));
}
}
}
if (hasLocalActionsForKeyBinding) {
// We have locals, ignore the globals. This prevents global actions from processing
// the given keybinding when a local action exits, regardless of enablement.
// At this point, we have local actions that may or may not be enabled. Return here
// so that any component specific actions found below will not interfere with the
// provider's local actions
return list;
}
@@ -191,7 +193,7 @@ public class MultipleKeyAction extends DockingKeyBindingAction {
if (componentAction.isValidComponentContext(localContext)) {
hasLocalActionsForKeyBinding = true;
if (isValidAndEnabled(actionData, localContext)) {
list.add(new ExecutableKeyActionAdapter(actionData.action, localContext));
list.add(new ExecutableAction(actionData.action, localContext));
}
}
}
@@ -211,16 +213,28 @@ public class MultipleKeyAction extends DockingKeyBindingAction {
// is a 'global' action. This allows more specific context to be used when
// available
if (isValidAndEnabled(actionData, localContext)) {
list.add(new ExecutableKeyActionAdapter(actionData.action, localContext));
list.add(new ExecutableAction(actionData.action, localContext));
}
else if (isValidAndEnabledGlobally(actionData, globalContext)) {
list.add(new ExecutableAction(actionData.action, globalContext));
}
}
}
return list;
}
private boolean isValidAndEnabled(ActionData actionData, ActionContext localContext) {
private boolean isValidAndEnabled(ActionData actionData, ActionContext context) {
DockingActionIf a = actionData.action;
return a.isValidContext(localContext) && a.isEnabledForContext(localContext);
return a.isValidContext(context) && a.isEnabledForContext(context);
}
private boolean isValidAndEnabledGlobally(ActionData actionData, ActionContext context) {
// the context may be null when we don't want global action such as when getting actions
// for a dialog
if (context == null) {
return false;
}
return actionData.supportsDefaultToolContext() && isValidAndEnabled(actionData, context);
}
@Override
@@ -242,7 +256,7 @@ public class MultipleKeyAction extends DockingKeyBindingAction {
*/
public KeyBindingPrecedence geValidKeyBindingPrecedence(Component source) {
List<ExecutableKeyActionAdapter> validActions = getActionsForCurrentContext(source);
List<ExecutableAction> validActions = getActionsForCurrentOrDefaultContext(source);
if (validActions.isEmpty()) {
return null; // a signal that no actions are valid for the current context
}
@@ -251,31 +265,36 @@ public class MultipleKeyAction extends DockingKeyBindingAction {
return KeyBindingPrecedence.DefaultLevel;
}
ExecutableKeyActionAdapter actionProxy = validActions.get(0);
ExecutableAction actionProxy = validActions.get(0);
DockingActionIf action = actionProxy.getAction();
return action.getKeyBindingData().getKeyBindingPrecedence();
}
private List<ExecutableKeyActionAdapter> getActionsForCurrentContext(Object eventSource) {
private List<ExecutableAction> getActionsForCurrentOrDefaultContext(Object eventSource) {
DockingWindowManager dwm = tool.getWindowManager();
Window window = getWindow(dwm, eventSource);
if (window instanceof DockingDialog) {
DockingDialog dockingDialog = (DockingDialog) window;
DialogComponentProvider provider = dockingDialog.getDialogComponent();
if (provider == null) {
// this can happen if the dialog is closed during key event processing
return Collections.emptyList();
}
ActionContext context = provider.getActionContext(null);
List<ExecutableKeyActionAdapter> validActions = getValidContextActions(context);
return validActions;
return getDialogActions(window);
}
ComponentProvider localProvider = getProvider(dwm, eventSource);
ActionContext localContext = getLocalContext(localProvider);
localContext.setSourceObject(eventSource);
List<ExecutableKeyActionAdapter> validActions = getValidContextActions(localContext);
ActionContext globalContext = tool.getDefaultToolContext();
List<ExecutableAction> validActions = getValidContextActions(localContext, globalContext);
return validActions;
}
private List<ExecutableAction> getDialogActions(Window window) {
DockingDialog dockingDialog = (DockingDialog) window;
DialogComponentProvider provider = dockingDialog.getDialogComponent();
if (provider == null) {
// this can happen if the dialog is closed during key event processing
return Collections.emptyList();
}
ActionContext context = provider.getActionContext(null);
List<ExecutableAction> validActions = getValidContextActions(context, null);
return validActions;
}
@@ -337,10 +356,15 @@ public class MultipleKeyAction extends DockingKeyBindingAction {
return provider == otherProvider;
}
boolean supportsDefaultToolContext() {
return action.supportsDefaultToolContext();
}
@Override
public String toString() {
String providerString = provider == null ? "" : provider.toString() + " - ";
return providerString + action;
}
}
}
@@ -15,6 +15,7 @@
*/
package docking.action.builder;
import java.util.Objects;
import java.util.function.Consumer;
import java.util.function.Predicate;
@@ -23,6 +24,7 @@ import javax.swing.KeyStroke;
import docking.*;
import docking.action.*;
import docking.actions.KeyBindingUtils;
import ghidra.util.HelpLocation;
import ghidra.util.Msg;
import resources.ResourceManager;
@@ -50,7 +52,7 @@ import resources.ResourceManager;
* the {@link #withContext(Class)} call.
*/
public abstract class AbstractActionBuilder<T extends DockingActionIf, C extends ActionContext, B extends AbstractActionBuilder<T, C, B>> {
private final Predicate<C> ALWAYS_TRUE = e -> true;
/**
* Name for the {@code DockingAction}
*/
@@ -159,17 +161,22 @@ public abstract class AbstractActionBuilder<T extends DockingActionIf, C extends
/**
* Predicate for determining if an action is enabled for a given context
*/
private Predicate<C> enabledPredicate;
private Predicate<C> enabledPredicate = ALWAYS_TRUE;
/**
* Predicate for determining if an action should be included on the pop-up menu
*/
private Predicate<C> popupPredicate;
private Predicate<C> popupPredicate = ALWAYS_TRUE;
/**
* Predicate for determining if an action is applicable for a given context
*/
private Predicate<C> validContextPredicate;
private Predicate<C> validContextPredicate = ALWAYS_TRUE;
/**
* Set to true if the action supports using the default tool context if the local context is invalid
*/
private boolean supportsDefaultToolContext;
/**
* Builder constructor
@@ -484,7 +491,7 @@ public abstract class AbstractActionBuilder<T extends DockingActionIf, C extends
* @return this builder (for chaining)
*/
public B keyBinding(String keyStrokeString) {
this.keyBinding = KeyStroke.getKeyStroke(keyStrokeString);
this.keyBinding = KeyBindingUtils.parseKeyStroke(keyStrokeString);
if (keyBinding == null && keyStrokeString != null) {
Msg.warn(this, "Can't parse KeyStroke: " + keyStrokeString);
}
@@ -517,7 +524,7 @@ public abstract class AbstractActionBuilder<T extends DockingActionIf, C extends
* @return this builder (for chaining)
*/
public B enabledWhen(Predicate<C> predicate) {
enabledPredicate = predicate;
enabledPredicate = Objects.requireNonNull(predicate);
return self();
}
@@ -540,7 +547,7 @@ public abstract class AbstractActionBuilder<T extends DockingActionIf, C extends
* @see #popupMenuPath(String...)
*/
public B popupWhen(Predicate<C> predicate) {
popupPredicate = predicate;
popupPredicate = Objects.requireNonNull(predicate);
return self();
}
@@ -556,7 +563,23 @@ public abstract class AbstractActionBuilder<T extends DockingActionIf, C extends
* @return this builder (for chaining)
*/
public B validContextWhen(Predicate<C> predicate) {
validContextPredicate = predicate;
validContextPredicate = Objects.requireNonNull(predicate);
return self();
}
/**
* Sets whether the action will support using the default tool context if the focused provider's
* context is invalid.
* <P>
* By default, actions only work on the current focused provider's context. Setting this
* to true will cause the action to be evaluated against the default tool context if the
* focused context is not valid for this action.
*
* @param b the new value
* @return this builder (for chaining)
*/
public B supportsDefaultToolContext(boolean b) {
supportsDefaultToolContext = b;
return self();
}
@@ -603,6 +626,10 @@ public abstract class AbstractActionBuilder<T extends DockingActionIf, C extends
public <AC2 extends ActionContext, B2 extends AbstractActionBuilder<T, AC2, B2>> B2 withContext(
Class<AC2> newActionContextClass) {
if (actionContextClass != ActionContext.class) {
throw new IllegalStateException("Can't set the ActionContext type more than once");
}
// To make this work, we need to return a builder whose ActionContext is AC2 and not AC
// (which is what this builder is now)
//
@@ -627,6 +654,7 @@ public abstract class AbstractActionBuilder<T extends DockingActionIf, C extends
protected void decorateAction(DockingAction action) {
action.setEnabled(isEnabled);
action.setDescription(description);
action.setSupportsDefaultToolContext(supportsDefaultToolContext);
setMenuData(action);
setToolbarData(action);
@@ -637,15 +665,9 @@ public abstract class AbstractActionBuilder<T extends DockingActionIf, C extends
action.setHelpLocation(helpLocation);
}
if (enabledPredicate != null) {
action.enabledWhen(adaptPredicate(enabledPredicate));
}
if (validContextPredicate != null) {
action.validContextWhen(adaptPredicate(validContextPredicate));
}
if (popupPredicate != null) {
action.popupWhen(adaptPredicate(popupPredicate));
}
action.enabledWhen(adaptPredicate(enabledPredicate));
action.validContextWhen(adaptPredicate(validContextPredicate));
action.popupWhen(adaptPredicate(popupPredicate));
}
/**
@@ -14,6 +14,7 @@
* limitations under the License.
*/
package docking.action.builder;
import docking.ActionContext;
import docking.action.DockingAction;
@@ -22,7 +22,8 @@ import java.util.List;
import javax.swing.Icon;
import javax.swing.JButton;
import docking.*;
import docking.ActionContext;
import docking.DockingWindowManager;
import docking.action.*;
import docking.widgets.EventTrigger;
import ghidra.util.HelpLocation;
@@ -148,10 +149,13 @@ public abstract class MultiStateDockingAction<T> extends DockingAction {
private ActionContext getActionContext() {
DockingWindowManager manager = DockingWindowManager.getActiveInstance();
ComponentProvider provider = manager.getActiveComponentProvider();
ActionContext localContext = provider == null ? null : provider.getActionContext(null);
ActionContext actionContext = localContext == null ? new ActionContext() : localContext;
return actionContext;
ActionContext context = manager.getActionContext(this);
if (context == null) {
context = new ActionContext();
}
return context;
}
protected List<DockingActionIf> getStateActions() {
@@ -113,11 +113,7 @@ public class ToolBarItemManager implements PropertyChangeListener, ActionListene
@Override
public void actionPerformed(ActionEvent event) {
DockingWindowManager.clearMouseOverHelp();
ActionContext context = getActionContext();
if (!toolBarAction.isValidContext(context)) {
return;
}
ActionContext context = windowManager.getActionContext(toolBarAction);
context.setSourceObject(event.getSource());
@@ -139,14 +135,6 @@ public class ToolBarItemManager implements PropertyChangeListener, ActionListene
return toolBarAction.getName();
}
private ActionContext getActionContext() {
ComponentProvider provider = getComponentProvider();
ActionContext context = provider == null ? null : provider.getActionContext(null);
final ActionContext actionContext =
context == null ? new ActionContext(provider, null) : context;
return actionContext;
}
private ComponentProvider getComponentProvider() {
DockingWindowManager manager = windowManager;
if (manager == null) {
@@ -80,7 +80,7 @@ public class FakeDockingTool extends AbstractDockingTool {
}
@Override
public ActionContext getGlobalActionContext() {
public ActionContext getDefaultToolContext() {
return null;
}
}
@@ -1472,8 +1472,8 @@ public abstract class PluginTool extends AbstractDockingTool {
}
@Override
public ActionContext getGlobalActionContext() {
return winMgr.getGlobalActionContext();
public ActionContext getDefaultToolContext() {
return winMgr.getDefaultToolContext();
}
@Override
@@ -95,10 +95,13 @@ class DataComponent extends DataDB {
}
DataType pdt = parent.getBaseDataType();
if (pdt instanceof Composite) {
DataTypeComponent c = ((Composite) pdt).getComponent(indexInParent);
if (c == null) {
Composite composite = (Composite) pdt;
// if we are deleted, the parent may not have as many components as it used to,
// so if our index is bigger than the number of components, then we are deleted.
if (indexInParent >= composite.getNumComponents()) {
return true;
}
DataTypeComponent c = composite.getComponent(indexInParent);
component = c;
dataType = c.getDataType();
offset = component.getOffset();