mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2026-05-24 12:45:55 +08:00
Merge branch 'GT-3485_action_context'
Conflicts: Ghidra/Framework/Docking/src/main/java/docking/action/MultipleKeyAction.java
This commit is contained in:
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
+8
-21
@@ -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);
|
||||
|
||||
+25
-27
@@ -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;
|
||||
|
||||
+1
@@ -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"));
|
||||
|
||||
|
||||
+5
-4
@@ -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());
|
||||
|
||||
+4
-3
@@ -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);
|
||||
|
||||
+20
-19
@@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
+30
-25
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+2
-1
@@ -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(
|
||||
|
||||
+5
-8
@@ -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.");
|
||||
|
||||
+4
-9
@@ -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);
|
||||
|
||||
+10
-52
@@ -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
|
||||
|
||||
+120
-213
@@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -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);
|
||||
}
|
||||
};
|
||||
|
||||
+3
-8
@@ -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(
|
||||
|
||||
+31
-46
@@ -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) {
|
||||
|
||||
+5
-7
@@ -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
|
||||
|
||||
+29
-31
@@ -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);
|
||||
|
||||
+4
-1
@@ -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) {
|
||||
|
||||
+2
-2
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
+39
-17
@@ -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
|
||||
|
||||
+5
-2
@@ -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();
|
||||
|
||||
Reference in New Issue
Block a user