GT-3485 fixed issue where some global listing and navigation actions

were not enabled when providers other than the listing had focus.  This
was unintentionally broken with the original ticket
This commit is contained in:
ghidravore 2020-03-09 15:43:07 -04:00
parent 83e0ce4091
commit 641745c6e0
36 changed files with 541 additions and 552 deletions

View file

@ -1,6 +1,5 @@
/* ###
* IP: GHIDRA
* REVIEWED: YES
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -16,11 +15,11 @@
*/
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 {
@ -28,13 +27,14 @@ public class ListingActionContext extends NavigatableActionContext {
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 );
ProgramSelection highlight) {
super(provider, navigatable, program, location, selection, highlight);
}
}

View file

@ -24,46 +24,32 @@ import docking.action.KeyBindingType;
public abstract class NavigatableContextAction extends DockingAction {
public NavigatableContextAction(String name, String owner) {
super(name, owner);
this(name, owner, KeyBindingType.INDIVIDUAL);
}
public NavigatableContextAction(String name, String owner, KeyBindingType type) {
super(name, owner, type);
setFallbackToGlobalContext(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));
if (context instanceof NavigatableActionContext) {
actionPerformed((NavigatableActionContext) context);
}
private NavigatableActionContext getAppropriateContext(ActionContext context) {
if (context instanceof NavigatableActionContext &&
isValidNavigationContext((NavigatableActionContext) context)) {
return (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

View file

@ -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();

View file

@ -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);

View file

@ -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,14 +97,20 @@ 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")
.fallbackToGlobalContext(true)
.helpLocation(new HelpLocation(HelpTopics.SEARCH, SEARCH_DIRECT_REFS_ACTION_NAME))
.description(getPluginDescription().getDescription())
.withContext(ListingActionContext.class)
.onAction(this::findReferences)
.enabledWhen(this::checkSize)
.buildAndInstall(tool);
}
@Override
protected boolean isEnabledForContext(ListingActionContext context) {
private boolean checkSize(ListingActionContext context) {
int size =
context.getProgram().getAddressFactory().getDefaultAddressSpace().getSize();
if ((size == 64) || (size == 32) || (size == 24) || (size == 16) || (size == 20) ||
@ -112,17 +119,6 @@ public class FindPossibleReferencesPlugin extends Plugin {
}
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 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;

View file

@ -30,6 +30,7 @@ public class ClearSelectionAction extends CodeViewerContextAction {
public ClearSelectionAction(String owner) {
super("Clear Selection", owner);
setFallbackToGlobalContext(true);
setMenuBarData(new MenuData(
new String[] { ToolConstants.MENU_SELECTION, "&Clear Selection" }, null, "Select"));

View file

@ -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);

View file

@ -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);

View file

@ -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,6 +22,9 @@ 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.
@ -34,19 +33,20 @@ public class SelectAllAction extends CodeViewerContextAction {
public SelectAllAction(String owner) {
super("Select All", owner);
setFallbackToGlobalContext(true);
setMenuBarData(
new MenuData(
new String[] {ToolConstants.MENU_SELECTION, "&All in View" },null,"Select" ) );
new String[] { ToolConstants.MENU_SELECTION, "&All in View" }, null, "Select"));
setKeyBindingData( new KeyBindingData(
KeyEvent.VK_A, InputEvent.CTRL_DOWN_MASK ) );
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();
}
}

View file

@ -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
@ -31,10 +32,11 @@ public class SelectComplementAction extends CodeViewerContextAction {
public SelectComplementAction(String owner) {
super("Select Complement", owner);
setMenuBarData( new MenuData(
new String[]{ToolConstants.MENU_SELECTION, "&Complement" },
setFallbackToGlobalContext(true);
setMenuBarData(new MenuData(
new String[] { ToolConstants.MENU_SELECTION, "&Complement" },
null,
"Select" ) );
"Select"));
setEnabled(false);
setHelpLocation(new HelpLocation(HelpTopics.SELECTION, getName()));
@ -45,6 +47,7 @@ public class SelectComplementAction extends CodeViewerContextAction {
CodeViewerProvider provider = (CodeViewerProvider) context.getComponentProvider();
provider.selectComplement();
}
@Override
public boolean isEnabledForContext(CodeViewerActionContext context) {
ProgramSelection selection = context.getSelection();
@ -54,4 +57,3 @@ public class SelectComplementAction extends CodeViewerContextAction {
return true;
}
}

View file

@ -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(

View file

@ -19,7 +19,7 @@ import javax.swing.*;
import docking.action.*;
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,6 +41,7 @@ public abstract class AbstractNextPreviousAction extends CodeViewerContextAction
public AbstractNextPreviousAction(PluginTool tool, String name, String owner, String subGroup) {
super(name, owner);
this.tool = tool;
setFallbackToGlobalContext(true);
ToolBarData toolBarData =
new ToolBarData(getIcon(), ToolConstants.TOOLBAR_GROUP_FOUR);
@ -90,7 +91,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.");

View file

@ -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,7 +119,7 @@ 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;
@ -144,7 +144,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);

View file

@ -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,6 +57,7 @@ public class NextPreviousBookmarkAction extends MultiStateDockingAction<String>
public NextPreviousBookmarkAction(PluginTool tool, String owner, String subGroup) {
super("Next Bookmark", owner);
this.tool = tool;
setFallbackToGlobalContext(true);
ToolBarData toolBarData =
new ToolBarData(bookmarkIcon, ToolConstants.TOOLBAR_GROUP_FOUR);
@ -119,8 +121,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 +214,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 +228,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 +267,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

View file

@ -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(
@ -90,9 +84,9 @@ public class ProgramManagerPlugin extends Plugin implements ProgramManager {
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 +95,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 +520,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("DomainObjectOpen", 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("DomainObjectOpen", 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("DomainObjectOpen", 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("DomainObjectOpen", 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("DomainObjectSave", 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("DomainObjectSave", 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("DomainObjectSave", 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 +650,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 +668,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 +786,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() {

View file

@ -20,7 +20,6 @@ import java.io.IOException;
import javax.swing.Icon;
import docking.ActionContext;
import docking.action.*;
import docking.tool.ToolConstants;
import ghidra.app.context.ProgramActionContext;
@ -62,18 +61,31 @@ public class RedoAction extends ProgramContextAction {
}
}
@Override
protected boolean isEnabledForContext(ProgramActionContext context) {
Program program = context.getProgram();
if (program.canRedo()) {
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 +96,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;
}
}

View file

@ -20,7 +20,6 @@ import java.io.IOException;
import javax.swing.Icon;
import docking.ActionContext;
import docking.action.*;
import docking.tool.ToolConstants;
import ghidra.app.context.ProgramActionContext;
@ -69,27 +68,29 @@ public class UndoAction extends ProgramContextAction {
}
}
@Override
protected boolean isEnabledForContext(ProgramActionContext context) {
Program program = context.getProgram();
if (program.canUndo()) {
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();
}
}

View file

@ -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);
}
};

View file

@ -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(

View file

@ -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,33 @@ 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)
.fallbackToGlobalContext(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());
searchAgainAction = new ActionBuilder("Repeat Text Search", getName())
.menuPath("&Search", "Repeat Text Search")
.menuGroup("search", subGroup)
.keyBinding("ctrl shift F3")
.description(DESCRIPTION)
.helpLocation(new HelpLocation(HelpTopics.SEARCH, "Repeat Text Search"))
.withContext(NavigatableActionContext.class)
.enabledWhen(c -> searchedOnce)
.onAction(c -> {
setNavigatable(c.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);
})
.buildAndInstall(tool);
}
protected void updateNavigatable(ActionContext context) {

View file

@ -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
@ -62,6 +62,7 @@ class SelectByFlowAction extends ListingContextAction {
super(name, plugin.getName());
this.selectByFlowPlugin = plugin;
this.selectionType = selectionType;
setFallbackToGlobalContext(true);
String[] menuPath = null;
if (selectionType == SelectByFlowPlugin.SELECT_FUNCTIONS) {

View file

@ -1,6 +1,5 @@
/* ###
* IP: GHIDRA
* REVIEWED: YES
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -16,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,45 +40,45 @@ public class SelectForwardRefsAction extends ListingContextAction {
this.tool = tool;
String group = "references";
setMenuBarData( new MenuData( new String[] {"Select", "Forward Refs"}, null, group ) );
setMenuBarData(new MenuData(new String[] { "Select", "Forward Refs" }, null, group));
setKeyBindingData( new KeyBindingData( KeyEvent.VK_PERIOD, InputEvent.CTRL_MASK ) );
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) {
public void actionPerformed(NavigatableActionContext context) {
AddressSetView addressSet = context.hasSelection() ?
context.getSelection() :
new AddressSet(context.getAddress());
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);
}
}

View file

@ -29,6 +29,7 @@ import docking.action.*;
import docking.widgets.fieldpanel.support.FieldLocation;
import docking.widgets.fieldpanel.support.ViewerPosition;
import ghidra.GhidraOptions;
import ghidra.app.context.ProgramActionContext;
import ghidra.app.decompiler.*;
import ghidra.app.decompiler.component.*;
import ghidra.app.nav.*;
@ -220,7 +221,10 @@ public class DecompilerProvider extends NavigatableComponentProviderAdapter
return null;
}
Function function = controller.getFunction();
Address entryPoint = function != null ? function.getEntryPoint() : null;
if (function == null) {
return new ProgramActionContext(this, program);
}
Address entryPoint = function.getEntryPoint();
boolean isDecompiling = controller.isDecompiling();
return new DecompilerActionContext(this, entryPoint, isDecompiling);
}

View file

@ -228,4 +228,14 @@ public class DockingActionProxy
public String toString() {
return dockingAction.toString();
}
@Override
public void setFallbackToGlobalContext(boolean newValue) {
dockingAction.setFallbackToGlobalContext(newValue);
}
@Override
public boolean shouldFallbackToGlobalContext() {
return dockingAction.shouldFallbackToGlobalContext();
}
}

View file

@ -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;
}

View file

@ -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 = getActionContext(action);
if (context == null) {
return; // nothing to do
}
context.setSourceObject(event.getSource());
@ -64,4 +65,22 @@ public class MenuBarMenuHandler extends MenuHandler {
}
});
}
private ActionContext getActionContext(DockingActionIf action) {
ComponentProvider provider = windowManager.getActiveComponentProvider();
ActionContext localContext = provider == null ? null : provider.getActionContext(null);
if (localContext == null) {
localContext = new ActionContext();
}
if (action.isValidContext(localContext)) {
return localContext;
}
if (action.shouldFallbackToGlobalContext()) {
ActionContext globalContext = windowManager.getGlobalActionContext();
if (action.isValidContext(globalContext)) {
return globalContext;
}
}
return null;
}
}

View file

@ -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() + ")");
}

View file

@ -118,12 +118,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.getGlobalActionContext();
// Update actions - make a copy so that we don't get concurrent modification exceptions
List<DockingActionIf> list = new ArrayList<>(actionToProxyMap.values());
@ -131,6 +127,9 @@ public class WindowActionManager {
if (action.isValidContext(localContext)) {
action.setEnabled(action.isEnabledForContext(localContext));
}
else if (isValidGlobalContext(action, globalContext)) {
action.setEnabled(action.isEnabledForContext(globalContext));
}
else {
action.setEnabled(false);
}
@ -138,4 +137,21 @@ public class WindowActionManager {
// Notify listeners if the context provider is the focused provider
winMgr.notifyContextListeners(placeHolderForScheduledActionUpdate, localContext);
}
private boolean isValidGlobalContext(DockingActionIf action, ActionContext globalContext) {
return action.shouldFallbackToGlobalContext() &&
action.isValidContext(globalContext);
}
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;
}
}

View file

@ -77,6 +77,8 @@ public abstract class DockingAction implements DockingActionIf {
private Predicate<ActionContext> popupPredicate;
private Predicate<ActionContext> validContextPredicate;
private boolean fallbackToGlobalContext;
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 setFallbackToGlobalContext(boolean newValue) {
fallbackToGlobalContext = newValue;
}
@Override
public boolean shouldFallbackToGlobalContext() {
return fallbackToGlobalContext;
}
@Override
public final JButton createButton() {
JButton button = doCreateButton();

View file

@ -97,6 +97,23 @@ public interface DockingActionIf extends HelpDescriptor {
*/
public boolean setEnabled(boolean newValue);
/**
* Sets whether or not this action should be activated using the global tool context if the
* current focussed provider's context is not valid for this action.
* @param newValue if true, the action will be activated using the global context if the local
* context is not valid for this action. If false, the action will only ever be activated
* using the local context.
*/
public void setFallbackToGlobalContext(boolean newValue);
/**
* Returns true if this action can be activated using the global context if the local context
* is invalid for this action.
* @return true if this action can be activated using the global context if the local context
* is invalid for this action.
*/
public boolean shouldFallbackToGlobalContext();
/**
* Returns true if the action is enabled.
*

View file

@ -112,7 +112,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 = getActionsForCurrentOrGlobalContext(event.getSource());
// If menu active, disable all key bindings
if (ignoreActionWhileMenuShowing()) {
@ -135,7 +135,7 @@ public class MultipleKeyAction extends DockingKeyBindingAction {
Swing.runLater(() -> DockingWindowManager.showDialog(dialog));
}
else if (list.size() == 1) {
final ExecutableKeyActionAdapter actionProxy = list.get(0);
final ExecutableAction actionProxy = list.get(0);
tool.setStatusInfo("");
actionProxy.execute();
}
@ -154,8 +154,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;
//
@ -165,14 +166,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.
// We have locals, ignore the component specific. This prevents component actions
// from processing the given keybinding when a local action exits, regardless of
// enablement.
return list;
}
@ -189,7 +191,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));
}
}
}
@ -209,16 +211,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.supportsGlobalContext() && isValidAndEnabled(actionData, context);
}
@Override
@ -228,7 +242,7 @@ public class MultipleKeyAction extends DockingKeyBindingAction {
@Override
public KeyBindingPrecedence getKeyBindingPrecedence() {
List<ExecutableKeyActionAdapter> validActions = getActionsForCurrentContext(null);
List<ExecutableAction> validActions = getActionsForCurrentOrGlobalContext(null);
if (validActions.isEmpty()) {
return null; // a signal that no actions are valid for the current context
}
@ -237,16 +251,28 @@ 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> getActionsForCurrentOrGlobalContext(Object eventSource) {
DockingWindowManager dwm = tool.getWindowManager();
Window window = dwm.getActiveWindow();
if (window instanceof DockingDialog) {
return getDialogActions(window);
}
ComponentProvider localProvider = dwm.getActiveComponentProvider();
ActionContext localContext = getLocalContext(localProvider);
localContext.setSourceObject(eventSource);
ActionContext globalContext = tool.getGlobalActionContext();
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) {
@ -254,14 +280,7 @@ public class MultipleKeyAction extends DockingKeyBindingAction {
return Collections.emptyList();
}
ActionContext context = provider.getActionContext(null);
List<ExecutableKeyActionAdapter> validActions = getValidContextActions(context);
return validActions;
}
ComponentProvider localProvider = dwm.getActiveComponentProvider();
ActionContext localContext = getLocalContext(localProvider);
localContext.setSourceObject(eventSource);
List<ExecutableKeyActionAdapter> validActions = getValidContextActions(localContext);
List<ExecutableAction> validActions = getValidContextActions(context, null);
return validActions;
}
@ -309,10 +328,15 @@ public class MultipleKeyAction extends DockingKeyBindingAction {
return provider == otherProvider;
}
boolean supportsGlobalContext() {
return action.shouldFallbackToGlobalContext();
}
@Override
public String toString() {
String providerString = provider == null ? "" : provider.toString() + " - ";
return providerString + action;
}
}
}

View file

@ -50,7 +50,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> TRUE_PREDICATE = e -> true;
/**
* Name for the {@code DockingAction}
*/
@ -171,6 +171,11 @@ public abstract class AbstractActionBuilder<T extends DockingActionIf, C extends
*/
private Predicate<C> validContextPredicate;
/**
* Set to true if the action supports using the global context if the local context is invalid
*/
private boolean fallbackToGlobalContext;
/**
* Builder constructor
* @param name the name of the action to be built
@ -501,6 +506,7 @@ public abstract class AbstractActionBuilder<T extends DockingActionIf, C extends
*/
public B onAction(Consumer<C> action) {
actionCallback = action;
// actionCallback = adaptActionConsumer(action);
return self();
}
@ -560,6 +566,11 @@ public abstract class AbstractActionBuilder<T extends DockingActionIf, C extends
return self();
}
public B fallbackToGlobalContext(boolean b) {
fallbackToGlobalContext = b;
return self();
}
/**
* Sets the specific ActionContext type to use for the various predicate calls
* ({@link #validContextWhen(Predicate)}, {@link #enabledWhen(Predicate)}, and
@ -613,6 +624,11 @@ public abstract class AbstractActionBuilder<T extends DockingActionIf, C extends
actionContextClass = newActionContextClass;
// reset the predicates when changing the action context type
validContextWhen(TRUE_PREDICATE);
enabledWhen(TRUE_PREDICATE);
popupWhen(TRUE_PREDICATE);
B2 newSelf = (B2) self();
return newSelf;
}
@ -627,6 +643,7 @@ public abstract class AbstractActionBuilder<T extends DockingActionIf, C extends
protected void decorateAction(DockingAction action) {
action.setEnabled(isEnabled);
action.setDescription(description);
action.setFallbackToGlobalContext(fallbackToGlobalContext);
setMenuData(action);
setToolbarData(action);
@ -668,6 +685,17 @@ public abstract class AbstractActionBuilder<T extends DockingActionIf, C extends
return predicateAdapter;
}
@SuppressWarnings("unchecked")
private Consumer<ActionContext> adaptActionConsumer(Consumer<C> consumer) {
if (actionContextClass == ActionContext.class) {
return (Consumer<ActionContext>) consumer;
}
Consumer<ActionContext> consumerAdapter = (ac) -> {
consumer.accept((C) ac);
};
return consumerAdapter;
}
protected boolean isPopupAction() {
return popupPath != null;
}

View file

@ -14,6 +14,7 @@
* limitations under the License.
*/
package docking.action.builder;
import docking.ActionContext;
import docking.action.DockingAction;

View file

@ -149,9 +149,14 @@ 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 = provider == null ? null : provider.getActionContext(null);
if (context == null && shouldFallbackToGlobalContext()) {
context = manager.getGlobalActionContext();
}
if (context == null) {
context = new ActionContext();
}
return context;
}
protected List<DockingActionIf> getStateActions() {

View file

@ -113,9 +113,10 @@ public class ToolBarItemManager implements PropertyChangeListener, ActionListene
@Override
public void actionPerformed(ActionEvent event) {
DockingWindowManager.clearMouseOverHelp();
ActionContext context = getActionContext();
ActionContext context = getValidActionContext();
if (!toolBarAction.isValidContext(context)) {
// no valid context?
if (context == null) {
return;
}
@ -139,7 +140,22 @@ public class ToolBarItemManager implements PropertyChangeListener, ActionListene
return toolBarAction.getName();
}
private ActionContext getActionContext() {
private ActionContext getValidActionContext() {
ActionContext context = getLocalActionContext();
if (toolBarAction.isValidContext(context)) {
return context;
}
if (toolBarAction.shouldFallbackToGlobalContext()) {
context = windowManager.getGlobalActionContext();
if (toolBarAction.isValidContext(context)) {
return context;
}
}
return null;
}
private ActionContext getLocalActionContext() {
ComponentProvider provider = getComponentProvider();
ActionContext context = provider == null ? null : provider.getActionContext(null);
final ActionContext actionContext =

View file

@ -95,10 +95,11 @@ 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 (indexInParent >= composite.getNumComponents()) {
return true;
}
DataTypeComponent c = composite.getComponent(indexInParent);
component = c;
dataType = c.getDataType();
offset = component.getOffset();