GP-759 - providing control when using the ActionBuilder for actions to determine which windows they should appear on. Also, cleaned up various actions to take advantage of this.

This commit is contained in:
ghidravore 2021-05-19 11:20:12 -04:00
parent df72f24b58
commit 1f3f086ac9
51 changed files with 366 additions and 697 deletions

View file

@ -15,8 +15,6 @@
*/
package ghidra.app.context;
import java.util.Set;
import docking.ActionContext;
import docking.action.DockingAction;
import docking.action.KeyBindingType;
@ -75,15 +73,4 @@ public abstract class ListingContextAction extends DockingAction {
protected void actionPerformed(ListingActionContext context) {
// clients need to override this method
}
@Override
public boolean shouldAddToWindow(boolean isMainWindow, Set<Class<?>> contextTypes) {
for (Class<?> class1 : contextTypes) {
if (ListingActionContext.class.isAssignableFrom(class1)) {
return true;
}
}
return false;
}
}

View file

@ -15,8 +15,6 @@
*/
package ghidra.app.context;
import java.util.Set;
import docking.ActionContext;
import docking.action.DockingAction;
import docking.action.KeyBindingType;
@ -71,14 +69,4 @@ public abstract class NavigatableContextAction extends DockingAction {
}
protected abstract void actionPerformed(NavigatableActionContext context);
@Override
public boolean shouldAddToWindow(boolean isMainWindow, Set<Class<?>> contextTypes) {
for (Class<?> class1 : contextTypes) {
if (NavigatableActionContext.class.isAssignableFrom(class1)) {
return true;
}
}
return false;
}
}

View file

@ -1,6 +1,5 @@
/* ###
* IP: GHIDRA
* REVIEWED: YES
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -16,8 +15,6 @@
*/
package ghidra.app.context;
import java.util.Set;
import docking.ActionContext;
import docking.action.DockingAction;
@ -51,15 +48,7 @@ public abstract class ProgramContextAction extends DockingAction {
}
return isValidContext((ProgramActionContext)context);
}
@Override
public boolean shouldAddToWindow(boolean isMainWindow, Set<Class<?>> contextTypes) {
for (Class<?> class1 : contextTypes) {
if (ProgramActionContext.class.isAssignableFrom(class1)) {
return true;
}
}
return false;
}
@Override
public boolean isAddToPopup(ActionContext context) {
if (!(context instanceof ProgramActionContext)) {

View file

@ -15,8 +15,6 @@
*/
package ghidra.app.context;
import java.util.Set;
import docking.ActionContext;
import docking.action.DockingAction;
@ -71,14 +69,4 @@ public abstract class ProgramLocationContextAction extends DockingAction {
// a version of actionPerformed() that takes a more specific context than our parent
protected abstract void actionPerformed(ProgramLocationActionContext context);
@Override
public boolean shouldAddToWindow(boolean isMainWindow, Set<Class<?>> contextTypes) {
for (Class<?> class1 : contextTypes) {
if (ProgramLocationActionContext.class.isAssignableFrom(class1)) {
return true;
}
}
return false;
}
}

View file

@ -15,8 +15,6 @@
*/
package ghidra.app.nav;
import java.util.Set;
import ghidra.app.context.*;
import ghidra.app.plugin.core.navigation.NavigationOptions;
import ghidra.app.services.GoToService;
@ -36,6 +34,7 @@ public abstract class NextRangeAction extends NavigatableContextAction {
this.tool = tool;
this.navOptions = navOptions;
setEnabled(false);
addToWindowWhen(NavigatableActionContext.class);
}
@Override
@ -99,14 +98,4 @@ public abstract class NextRangeAction extends NavigatableContextAction {
}
abstract protected ProgramSelection getSelection(ProgramLocationActionContext context);
@Override
public boolean shouldAddToWindow(boolean isMainWindow, Set<Class<?>> contextTypes) {
for (Class<?> class1 : contextTypes) {
if (NavigatableRangeActionContext.class.isAssignableFrom(class1)) {
return true;
}
}
return false;
}
}

View file

@ -15,8 +15,6 @@
*/
package ghidra.app.nav;
import java.util.Set;
import ghidra.app.context.*;
import ghidra.app.plugin.core.navigation.NavigationOptions;
import ghidra.app.services.GoToService;
@ -35,6 +33,7 @@ public abstract class PreviousRangeAction extends NavigatableContextAction {
this.tool = tool;
this.navOptions = navOptions;
setEnabled(false);
addToWindowWhen(NavigatableActionContext.class);
}
@Override
@ -91,14 +90,4 @@ public abstract class PreviousRangeAction extends NavigatableContextAction {
}
abstract protected ProgramSelection getSelection(ProgramLocationActionContext context);
@Override
public boolean shouldAddToWindow(boolean isMainWindow, Set<Class<?>> contextTypes) {
for (Class<?> class1 : contextTypes) {
if (NavigatableRangeActionContext.class.isAssignableFrom(class1)) {
return true;
}
}
return false;
}
}

View file

@ -25,7 +25,7 @@ import docking.action.MenuData;
import docking.action.builder.ActionBuilder;
import docking.tool.ToolConstants;
import ghidra.app.CorePluginPackage;
import ghidra.app.context.*;
import ghidra.app.context.NavigatableActionContext;
import ghidra.app.events.ProgramClosedPluginEvent;
import ghidra.app.events.ProgramSelectionPluginEvent;
import ghidra.app.plugin.PluginCategoryNames;
@ -103,14 +103,15 @@ public class FindPossibleReferencesPlugin extends Plugin {
.supportsDefaultToolContext(true)
.helpLocation(new HelpLocation(HelpTopics.SEARCH, SEARCH_DIRECT_REFS_ACTION_NAME))
.description(getPluginDescription().getDescription())
.withContext(ListingActionContext.class)
.withContext(NavigatableActionContext.class)
.inWindow(ActionBuilder.When.CONTEXT_MATCHES)
.onAction(this::findReferences)
.enabledWhen(this::hasCorrectAddressSize)
.buildAndInstall(tool);
}
private boolean hasCorrectAddressSize(ListingActionContext context) {
private boolean hasCorrectAddressSize(NavigatableActionContext context) {
int size =
context.getProgram().getAddressFactory().getDefaultAddressSpace().getSize();
if ((size == 64) || (size == 32) || (size == 24) || (size == 16) || (size == 20) ||
@ -120,7 +121,7 @@ public class FindPossibleReferencesPlugin extends Plugin {
return false;
}
private void createLocalActions(ProgramLocationActionContext context, ComponentProvider p,
private void createLocalActions(NavigatableActionContext context, ComponentProvider p,
FindReferencesTableModel model) {
addLocalAlignment(p, model, 1);

View file

@ -15,14 +15,10 @@
*/
package ghidra.app.plugin.core.clear;
import java.awt.event.KeyEvent;
import docking.ActionContext;
import docking.action.*;
import docking.action.builder.ActionBuilder;
import docking.tool.ToolConstants;
import ghidra.app.CorePluginPackage;
import ghidra.app.context.ListingActionContext;
import ghidra.app.context.ListingContextAction;
import ghidra.app.plugin.PluginCategoryNames;
import ghidra.framework.cmd.Command;
import ghidra.framework.plugintool.*;
@ -46,12 +42,10 @@ import ghidra.program.util.*;
)
//@formatter:on
public class ClearPlugin extends Plugin {
private static final String CLEAR_WITH_OPTIONS_NAME = "Clear With Options";
private static final String CLEAR_CODE_BYTES_NAME = "Clear Code Bytes";
private static final String CLEAR_FLOW_AND_REPAIR = "Clear Flow and Repair";
private DockingAction clearAllAction;
private DockingAction clearAction;
private DockingAction clearAndRepairAction;
private ClearDialog clearDialog;
private ClearFlowDialog clearFlowDialog;
@ -215,123 +209,71 @@ public class ClearPlugin extends Plugin {
* Create the actions.
*/
private void createActions() {
new ActionBuilder(CLEAR_CODE_BYTES_NAME, getName())
.menuPath(ToolConstants.MENU_EDIT, CLEAR_CODE_BYTES_NAME)
.menuGroup(CLEAR_CODE_BYTES_NAME, "1")
.popupMenuPath(CLEAR_CODE_BYTES_NAME)
.popupMenuGroup(CLEAR_CODE_BYTES_NAME, "1")
.keyBinding("C")
.withContext(ListingActionContext.class)
.inWindow(ActionBuilder.When.CONTEXT_MATCHES)
.enabledWhen(this::isClearCodeBytesEnabled)
.onAction(this::clearCodeBytes)
.buildAndInstall(tool);
// new context aware version
clearAction = new ListingContextAction(CLEAR_CODE_BYTES_NAME, getName()) {
new ActionBuilder(CLEAR_WITH_OPTIONS_NAME, getName())
.menuPath(ToolConstants.MENU_EDIT, CLEAR_WITH_OPTIONS_NAME + "...")
.menuGroup(CLEAR_CODE_BYTES_NAME, "2")
.popupMenuPath(CLEAR_WITH_OPTIONS_NAME)
.popupMenuGroup(CLEAR_CODE_BYTES_NAME, "2")
.withContext(ListingActionContext.class)
.inWindow(ActionBuilder.When.CONTEXT_MATCHES)
.onAction(this::showClearAllDialog)
.buildAndInstall(tool);
@Override
public void actionPerformed(ListingActionContext context) {
ClearOptions opts = new ClearOptions();
opts.setClearCode(true);
opts.setClearSymbols(false);
opts.setClearComments(false);
opts.setClearProperties(false);
opts.setClearFunctions(false);
opts.setClearRegisters(false);
opts.setClearEquates(false);
opts.setClearUserReferences(true);
opts.setClearAnalysisReferences(true);
opts.setClearImportReferences(true);
opts.setClearDefaultReferences(false);
opts.setClearBookmarks(false);
if (clearWithContext(context, opts)) {
return;
}
}
private boolean clearWithContext(ListingActionContext context, ClearOptions opts) {
clear(opts, context);
return true;
}
@Override
public boolean isAddToPopup(ListingActionContext context) {
return true;
}
@Override
public boolean isEnabledForContext(ListingActionContext context) {
ProgramLocation loc = context.getLocation();
ProgramSelection currentSelection = context.getSelection();
if (currentSelection != null && !currentSelection.isEmpty()) {
return true;
}
else if ((loc != null) && (loc.getAddress() != null) &&
(loc instanceof CodeUnitLocation)) {
return true;
}
return false;
}
};
int menuOrdinal = 1;
MenuData menuData =
new MenuData(new String[] { ToolConstants.MENU_EDIT, CLEAR_CODE_BYTES_NAME }, null,
"Clear Code Bytes");
menuData.setMenuSubGroup(Integer.toString(menuOrdinal));
clearAction.setMenuBarData(menuData);
MenuData popupMenuData =
new MenuData(new String[] { CLEAR_CODE_BYTES_NAME }, null, "Clear Code Bytes");
popupMenuData.setMenuSubGroup(Integer.toString(menuOrdinal));
clearAction.setPopupMenuData(popupMenuData);
clearAction.setKeyBindingData(new KeyBindingData(KeyEvent.VK_C, 0));
String clearWithOptionsName = "Clear With Options";
clearAllAction = new DockingAction(clearWithOptionsName, getName()) {
@Override
public void actionPerformed(ActionContext context) {
showClearAllDialog((ListingActionContext) context.getContextObject());
}
@Override
public boolean isEnabledForContext(ActionContext context) {
return context.getContextObject() instanceof ListingActionContext;
}
};
menuOrdinal++;
menuData =
new MenuData(new String[] { ToolConstants.MENU_EDIT, clearWithOptionsName + "..." },
null, "Clear Code Bytes");
menuData.setMenuSubGroup(Integer.toString(menuOrdinal));
clearAllAction.setMenuBarData(menuData);
popupMenuData =
new MenuData(new String[] { clearWithOptionsName + "..." }, null, "Clear Code Bytes");
popupMenuData.setMenuSubGroup(Integer.toString(menuOrdinal));
clearAllAction.setPopupMenuData(popupMenuData);
clearAndRepairAction = new DockingAction(CLEAR_FLOW_AND_REPAIR, getName()) {
@Override
public void actionPerformed(ActionContext context) {
showClearFlowDialog((ListingActionContext) context.getContextObject());
}
@Override
public boolean isEnabledForContext(ActionContext context) {
return context.getContextObject() instanceof ListingActionContext;
}
};
menuOrdinal++;
menuData = new MenuData(new String[] { ToolConstants.MENU_EDIT, CLEAR_FLOW_AND_REPAIR },
null, "Clear Code Bytes");
menuData.setMenuSubGroup(Integer.toString(menuOrdinal));
clearAndRepairAction.setMenuBarData(menuData);
popupMenuData =
new MenuData(new String[] { CLEAR_FLOW_AND_REPAIR + "..." }, null, "Clear Code Bytes");
popupMenuData.setMenuSubGroup(Integer.toString(menuOrdinal));
clearAndRepairAction.setPopupMenuData(popupMenuData);
//clearAndRepairAction.setAcceleratorKey(KeyStroke.getKeyStroke(KeyEvent.VK_C, 0));
tool.addAction(clearAction);
tool.addAction(clearAllAction);
tool.addAction(clearAndRepairAction);
new ActionBuilder(CLEAR_FLOW_AND_REPAIR, getName())
.menuPath(ToolConstants.MENU_EDIT, CLEAR_FLOW_AND_REPAIR + "...")
.menuGroup(CLEAR_CODE_BYTES_NAME, "3")
.popupMenuPath(CLEAR_FLOW_AND_REPAIR)
.popupMenuGroup(CLEAR_CODE_BYTES_NAME, "3")
.withContext(ListingActionContext.class)
.inWindow(ActionBuilder.When.CONTEXT_MATCHES)
.onAction(this::showClearFlowDialog)
.buildAndInstall(tool);
}
private boolean isClearCodeBytesEnabled(ListingActionContext context) {
ProgramLocation loc = context.getLocation();
ProgramSelection currentSelection = context.getSelection();
if (currentSelection != null && !currentSelection.isEmpty()) {
return true;
}
else if ((loc != null) && (loc.getAddress() != null) && (loc instanceof CodeUnitLocation)) {
return true;
}
return false;
}
private void clearCodeBytes(ListingActionContext context) {
ClearOptions opts = new ClearOptions();
opts.setClearCode(true);
opts.setClearSymbols(false);
opts.setClearComments(false);
opts.setClearProperties(false);
opts.setClearFunctions(false);
opts.setClearRegisters(false);
opts.setClearEquates(false);
opts.setClearUserReferences(true);
opts.setClearAnalysisReferences(true);
opts.setClearImportReferences(true);
opts.setClearDefaultReferences(false);
opts.setClearBookmarks(false);
clear(opts, context);
}
/**
* Pop up the clear with options dialog.
*/

View file

@ -43,7 +43,6 @@ import ghidra.app.context.ListingActionContext;
import ghidra.app.events.*;
import ghidra.app.nav.Navigatable;
import ghidra.app.plugin.PluginCategoryNames;
import ghidra.app.plugin.core.codebrowser.actions.*;
import ghidra.app.plugin.core.codebrowser.hover.ListingHoverService;
import ghidra.app.plugin.core.table.TableComponentProvider;
import ghidra.app.services.*;
@ -169,17 +168,38 @@ public class CodeBrowserPlugin extends Plugin
}
private void createActions() {
DockingAction selectAllAction = new SelectAllAction(getName());
selectAllAction.getMenuBarData().setMenuSubGroup("a");
tool.addAction(selectAllAction);
new ActionBuilder("Select All", getName())
.menuPath(ToolConstants.MENU_SELECTION, "&All in View")
.menuGroup("Select Group", "a")
.keyBinding("ctrl A")
.supportsDefaultToolContext(true)
.helpLocation(new HelpLocation(HelpTopics.SELECTION, getName()))
.withContext(CodeViewerActionContext.class)
.inWindow(ActionBuilder.When.CONTEXT_MATCHES)
.onAction(c -> ((CodeViewerProvider) c.getComponentProvider()).selectAll())
.buildAndInstall(tool);
DockingAction selectNoneAction = new ClearSelectionAction(getName());
selectNoneAction.getMenuBarData().setMenuSubGroup("a");
tool.addAction(selectNoneAction);
new ActionBuilder("Clear Selection", getName())
.menuPath(ToolConstants.MENU_SELECTION, "&Clear Selection")
.menuGroup("Select Group", "b")
.supportsDefaultToolContext(true)
.helpLocation(new HelpLocation(HelpTopics.SELECTION, getName()))
.withContext(CodeViewerActionContext.class)
.inWindow(ActionBuilder.When.CONTEXT_MATCHES)
.onAction(c -> ((CodeViewerProvider) c.getComponentProvider())
.setSelection(new ProgramSelection()))
.buildAndInstall(tool);
new ActionBuilder("Select Complement", getName())
.menuPath(ToolConstants.MENU_SELECTION, "&Complement")
.menuGroup("Select Group", "c")
.supportsDefaultToolContext(true)
.helpLocation(new HelpLocation(HelpTopics.SELECTION, getName()))
.withContext(CodeViewerActionContext.class)
.inWindow(ActionBuilder.When.CONTEXT_MATCHES)
.onAction(c -> ((CodeViewerProvider) c.getComponentProvider()).selectComplement())
.buildAndInstall(tool);
DockingAction selectComplementAction = new SelectComplementAction(getName());
selectComplementAction.getMenuBarData().setMenuSubGroup("b");
tool.addAction(selectComplementAction);
}
protected void viewChanged(AddressSetView addrSet) {

View file

@ -1,45 +0,0 @@
/* ###
* IP: GHIDRA
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package ghidra.app.plugin.core.codebrowser.actions;
import docking.ActionContext;
import docking.action.MenuData;
import docking.tool.ToolConstants;
import ghidra.app.plugin.core.codebrowser.CodeViewerProvider;
import ghidra.app.util.HelpTopics;
import ghidra.program.util.ProgramSelection;
import ghidra.util.HelpLocation;
/**
* Action for clearing the current selection
*/
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"));
setHelpLocation(new HelpLocation(HelpTopics.SELECTION, getName()));
}
@Override
public void actionPerformed(ActionContext context) {
CodeViewerProvider provider = (CodeViewerProvider) context.getComponentProvider();
provider.setSelection(new ProgramSelection());
}
}

View file

@ -1,85 +0,0 @@
/* ###
* IP: GHIDRA
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package ghidra.app.plugin.core.codebrowser.actions;
import java.util.Set;
import docking.ActionContext;
import docking.action.DockingAction;
import ghidra.app.plugin.core.codebrowser.CodeViewerActionContext;
public abstract class CodeViewerContextAction extends DockingAction {
public CodeViewerContextAction(String name, String owner) {
super(name, owner);
}
@Override
public boolean isEnabledForContext(ActionContext context) {
if (!(context instanceof CodeViewerActionContext)) {
return false;
}
return isEnabledForContext((CodeViewerActionContext) context);
}
@Override
public boolean isValidContext(ActionContext context) {
if (!(context instanceof CodeViewerActionContext)) {
return false;
}
return isValidContext((CodeViewerActionContext) context);
}
@Override
public boolean isAddToPopup(ActionContext context) {
if (!(context instanceof CodeViewerActionContext)) {
return false;
}
return isAddToPopup((CodeViewerActionContext) context);
}
@Override
public void actionPerformed(ActionContext context) {
actionPerformed((CodeViewerActionContext) context);
}
protected boolean isAddToPopup(CodeViewerActionContext context) {
return isEnabledForContext(context);
}
protected boolean isValidContext(CodeViewerActionContext context) {
return true;
}
protected boolean isEnabledForContext(CodeViewerActionContext context) {
return true;
}
protected void actionPerformed(CodeViewerActionContext context) {
}
@Override
public boolean shouldAddToWindow(boolean isMainWindow, Set<Class<?>> contextTypes) {
for (Class<?> class1 : contextTypes) {
if (CodeViewerActionContext.class.isAssignableFrom(class1)) {
return true;
}
}
return false;
}
}

View file

@ -45,6 +45,9 @@ public class ExpandAllDataAction extends ProgramLocationContextAction {
setHelpLocation(new HelpLocation("CodeBrowserPlugin", "ExpandCollapseActions"));
setEnabled(true);
// make sure the action is in all windows that can provide the needed context
addToWindowWhen(ProgramLocationActionContext.class);
}
@Override

View file

@ -50,6 +50,7 @@ public class GotoNextFunctionAction extends NavigatableContextAction {
KeyStroke keyStroke = KeyStroke.getKeyStroke(KeyEvent.VK_DOWN, InputEvent.CTRL_DOWN_MASK);
setKeyBindingData(new KeyBindingData(keyStroke));
setHelpLocation(new HelpLocation(HelpTopics.NAVIGATION, "Next_Previous_Function"));
addToWindowWhen(NavigatableActionContext.class);
}
private Function getNextFunction(Program program, Address address) {

View file

@ -50,6 +50,7 @@ public class GotoPreviousFunctionAction extends NavigatableContextAction {
KeyStroke keyStroke = KeyStroke.getKeyStroke(KeyEvent.VK_UP, InputEvent.CTRL_DOWN_MASK);
setKeyBindingData(new KeyBindingData(keyStroke));
setHelpLocation(new HelpLocation(HelpTopics.NAVIGATION, "Next_Previous_Function"));
addToWindowWhen(NavigatableActionContext.class);
}
private Function getPreviousFunction(Program program, Address address) {

View file

@ -1,53 +0,0 @@
/* ###
* IP: GHIDRA
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package ghidra.app.plugin.core.codebrowser.actions;
import java.awt.event.InputEvent;
import java.awt.event.KeyEvent;
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);
// 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();
}
}

View file

@ -1,62 +0,0 @@
/* ###
* IP: GHIDRA
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package ghidra.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;
/**
* Action for changing the selection to the complement of all the currently
* selected addresses and restricting this new selection to the current view.
*/
public class SelectComplementAction extends CodeViewerContextAction {
public SelectComplementAction(String owner) {
super("Select Complement", owner);
// 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;
}
}

View file

@ -23,6 +23,7 @@ import docking.widgets.table.GTable;
import docking.widgets.table.threaded.ThreadedTableModelListener;
import ghidra.app.CorePluginPackage;
import ghidra.app.cmd.disassemble.DisassembleCommand;
import ghidra.app.context.NavigatableActionContext;
import ghidra.app.plugin.PluginCategoryNames;
import ghidra.app.plugin.ProgramPlugin;
import ghidra.app.services.GoToService;
@ -151,7 +152,7 @@ public class AutoTableDisassemblerPlugin extends ProgramPlugin implements Domain
findTableAction.setMenuBarData(new MenuData(
new String[] { ToolConstants.MENU_SEARCH, "For Address Tables" }, null, "search for"));
findTableAction.setDescription(getPluginDescription().getDescription());
findTableAction.addToWindowWhen(NavigatableActionContext.class);
tool.addAction(findTableAction);
} // end of createActions()

View file

@ -115,6 +115,7 @@ public class AboutProgramPlugin extends Plugin implements FrontEndable {
return false;
}
};
aboutAction.addToWindowWhen(ProgramActionContext.class);
aboutAction.setSupportsDefaultToolContext(true);
aboutAction.setMenuBarData(

View file

@ -101,6 +101,8 @@ public class SetHighlightPlugin extends Plugin {
HIGHLIGHT_GROUP));
setHighlightFromSelectionAction.setKeyBindingData(new KeyBindingData(KeyEvent.VK_H,
InputEvent.CTRL_DOWN_MASK));
setHighlightFromSelectionAction
.addToWindowWhen(NavigatableActionContext.class);
tool.addAction(setHighlightFromSelectionAction);
clearHighlightAction = new NavigatableContextAction("Remove Highlight", getName()) {
@ -121,6 +123,7 @@ public class SetHighlightPlugin extends Plugin {
clearHighlightAction.setMenuBarData(menuData);
clearHighlightAction.setPopupMenuData(new MenuData(CLEAR_HIGHLIGHT_POPUPPATH,
HIGHLIGHT_GROUP));
clearHighlightAction.addToWindowWhen(NavigatableActionContext.class);
tool.addAction(clearHighlightAction);
addSelectionAction = new NavigatableContextAction("Add Selection To Highlight", getName()) {
@ -142,7 +145,7 @@ public class SetHighlightPlugin extends Plugin {
menuData.setMenuSubGroup(Integer.toString(programHighlightSubMenuPosition++));
addSelectionAction.setMenuBarData(menuData);
addSelectionAction.setPopupMenuData(new MenuData(ADD_SELECTION_POPUPPATH, HIGHLIGHT_GROUP));
addSelectionAction.addToWindowWhen(NavigatableActionContext.class);
tool.addAction(addSelectionAction);
subtractSelectionAction =
@ -163,6 +166,7 @@ public class SetHighlightPlugin extends Plugin {
new MenuData(new String[] { ToolConstants.MENU_SELECTION, MENU_HIGHLIGHT,
"Subtract Selection" }, HIGHLIGHT_GROUP);
menuData.setMenuSubGroup(Integer.toString(programHighlightSubMenuPosition++));
subtractSelectionAction.addToWindowWhen(NavigatableActionContext.class);
subtractSelectionAction.setMenuBarData(menuData);
subtractSelectionAction.setPopupMenuData(new MenuData(SUBTRACT_SELECTION_POPUPPATH,
HIGHLIGHT_GROUP));
@ -185,11 +189,11 @@ public class SetHighlightPlugin extends Plugin {
ToolConstants.MENU_SELECTION, "From Highlight" }, HIGHLIGHT_GROUP));
setSelectionFromHighlightAction.setPopupMenuData(new MenuData(SET_SELECTION_POPUPPATH,
HIGHLIGHT_GROUP));
setSelectionFromHighlightAction
.addToWindowWhen(NavigatableActionContext.class);
tool.addAction(setSelectionFromHighlightAction);
tool.setMenuGroup(new String[] { MENU_HIGHLIGHT }, HIGHLIGHT_GROUP);
tool.setMenuGroup(new String[] { MENU_SELECTION }, HIGHLIGHT_GROUP);
tool.setMenuGroup(new String[] { MENU_SELECTION, MENU_HIGHLIGHT }, HIGHLIGHT_GROUP);
}
protected void setHighlight(Navigatable navigatable, ProgramSelection highlight) {

View file

@ -250,6 +250,7 @@ public class InstructionSearchPlugin extends ProgramPlugin {
}
};
searchAction.addToWindowWhen(NavigatableActionContext.class);
searchAction.setHelpLocation(new HelpLocation("Search", "Instruction_Pattern_Search"));
searchAction.setMenuBarData(
new MenuData(new String[] { ToolConstants.MENU_SEARCH, "For Instruction Patterns" },

View file

@ -15,15 +15,14 @@
*/
package ghidra.app.plugin.core.label;
import ghidra.app.context.ListingActionContext;
import ghidra.app.context.ListingContextAction;
import ghidra.framework.plugintool.PluginTool;
import java.awt.event.KeyEvent;
import docking.action.KeyBindingData;
import docking.action.MenuData;
import docking.tool.ToolConstants;
import ghidra.app.context.ListingActionContext;
import ghidra.app.context.ListingContextAction;
import ghidra.framework.plugintool.PluginTool;
public class AllHistoryAction extends ListingContextAction {
@ -36,7 +35,7 @@ public class AllHistoryAction extends ListingContextAction {
null, "Search"));
setKeyBindingData(new KeyBindingData(KeyEvent.VK_H, 0));
addToWindowWhen(ListingActionContext.class);
}
@Override

View file

@ -50,6 +50,7 @@ public abstract class AbstractNextPreviousAction extends NavigatableContextActio
setKeyBindingData(new KeyBindingData(getKeyStroke()));
setHelpLocation(new HelpLocation(HelpTopics.NAVIGATION, name));
setDescription(getDescriptionString());
addToWindowWhen(NavigatableActionContext.class);
}
protected abstract Icon getIcon();

View file

@ -103,6 +103,7 @@ public class GoToAddressLabelPlugin extends Plugin implements OptionsChangeListe
return true;
}
};
action.addToWindowWhen(NavigatableActionContext.class);
action.setHelpLocation(new HelpLocation(HelpTopics.NAVIGATION, action.getName()));
action.setMenuBarData(
new MenuData(new String[] { ToolConstants.MENU_NAVIGATION, "Go To..." }, null, "GoTo",

View file

@ -17,7 +17,8 @@ package ghidra.app.plugin.core.navigation;
import java.awt.event.InputEvent;
import java.awt.event.KeyEvent;
import java.util.*;
import java.util.ArrayList;
import java.util.List;
import javax.swing.Icon;
import javax.swing.ImageIcon;
@ -27,7 +28,8 @@ import docking.action.*;
import docking.menu.MultiActionDockingAction;
import docking.tool.ToolConstants;
import ghidra.app.CorePluginPackage;
import ghidra.app.context.*;
import ghidra.app.context.NavigatableActionContext;
import ghidra.app.context.ProgramActionContext;
import ghidra.app.nav.LocationMemento;
import ghidra.app.nav.Navigatable;
import ghidra.app.plugin.PluginCategoryNames;
@ -182,16 +184,6 @@ public class NextPrevAddressPlugin extends Plugin {
historyService.clear(getNavigatable(context));
}
@Override
public boolean shouldAddToWindow(boolean isMainWindow, Set<Class<?>> contextTypes) {
for (Class<?> class1 : contextTypes) {
if (NavigationActionContext.class.isAssignableFrom(class1)) {
return true;
}
}
return false;
}
@Override
public boolean isEnabledForContext(ActionContext context) {
if (!(context instanceof ProgramActionContext)) {
@ -204,6 +196,7 @@ public class NextPrevAddressPlugin extends Plugin {
return hasNext || hasPrevious;
}
};
clearAction.addToWindowWhen(NavigatableActionContext.class);
clearAction.setHelpLocation(new HelpLocation(HelpTopics.NAVIGATION, clearAction.getName()));
MenuData menuData = new MenuData(CLEAR_MENUPATH, HISTORY_MENU_GROUP);
menuData.setMenuSubGroup("1"); // first in menu!
@ -314,6 +307,7 @@ public class NextPrevAddressPlugin extends Plugin {
int keycode = isNext ? KeyEvent.VK_RIGHT : KeyEvent.VK_LEFT;
setKeyBindingData(new KeyBindingData(keycode, InputEvent.ALT_DOWN_MASK));
setDescription(isNext ? "Go to next location" : "Go to previous location");
addToWindowWhen(NavigatableActionContext.class);
}
@Override
@ -339,16 +333,6 @@ public class NextPrevAddressPlugin extends Plugin {
}
}
@Override
public boolean shouldAddToWindow(boolean isMainWindow, Set<Class<?>> contextTypes) {
for (Class<?> class1 : contextTypes) {
if (NavigationActionContext.class.isAssignableFrom(class1)) {
return true;
}
}
return false;
}
@Override
public List<DockingActionIf> getActionList(ActionContext context) {
Navigatable navigatable = getNavigatable(context);
@ -414,6 +398,7 @@ public class NextPrevAddressPlugin extends Plugin {
new MenuData(new String[] { "Navigation", menuItemName }, HISTORY_MENU_GROUP);
menuData.setMenuSubGroup("2"); // after clear
setMenuBarData(menuData);
addToWindowWhen(NavigatableActionContext.class);
}
@Override
@ -438,16 +423,6 @@ public class NextPrevAddressPlugin extends Plugin {
historyService.previousFunction(navigatable);
}
}
@Override
public boolean shouldAddToWindow(boolean isMainWindow, Set<Class<?>> contextTypes) {
for (Class<?> class1 : contextTypes) {
if (NavigationActionContext.class.isAssignableFrom(class1)) {
return true;
}
}
return false;
}
}
}

View file

@ -135,6 +135,7 @@ public class NextPrevCodeUnitPlugin extends Plugin {
setHelpLocation(
new HelpLocation(HelpTopics.NAVIGATION, longName));
setDescription(longName);
addToWindowWhen(NavigatableActionContext.class);
}

View file

@ -18,7 +18,6 @@ package ghidra.app.plugin.core.navigation;
import java.awt.event.InputEvent;
import java.awt.event.KeyEvent;
import java.util.Iterator;
import java.util.Set;
import javax.swing.*;
@ -64,6 +63,7 @@ public class NextPreviousBookmarkAction extends MultiStateDockingAction<String>
toolBarData.setToolBarSubGroup(subGroup);
setToolBarData(toolBarData);
addToWindowWhen(CodeViewerActionContext.class);
setKeyBindingData(new KeyBindingData(getKeyStroke()));
setHelpLocation(new HelpLocation(HelpTopics.NAVIGATION, getName()));
@ -258,14 +258,4 @@ public class NextPreviousBookmarkAction extends MultiStateDockingAction<String>
public boolean isEnabledForContext(ActionContext context) {
return context instanceof ListingActionContext;
}
@Override
public boolean shouldAddToWindow(boolean isMainWindow, Set<Class<?>> contextTypes) {
for (Class<?> class1 : contextTypes) {
if (CodeViewerActionContext.class.isAssignableFrom(class1)) {
return true;
}
}
return false;
}
}

View file

@ -17,7 +17,6 @@ package ghidra.app.plugin.core.navigation;
import java.awt.event.InputEvent;
import java.awt.event.KeyEvent;
import java.util.Set;
import javax.swing.ImageIcon;
import javax.swing.KeyStroke;
@ -83,9 +82,11 @@ public class NextPreviousMarkerAction extends MultiStateDockingAction<String> {
setMenuBarData(menuData);
setKeyBindingData(new KeyBindingData(getKeyStroke()));
addToWindowWhen(CodeViewerActionContext.class);
setHelpLocation(new HelpLocation(HelpTopics.NAVIGATION, getName()));
setDescription("Set marker options");
addToWindowWhen(CodeViewerActionContext.class);
ActionState<String> allMarkers =
new ActionState<String>("All Types", markerIcon, "All Types");
@ -310,13 +311,4 @@ public class NextPreviousMarkerAction extends MultiStateDockingAction<String> {
return isEnabledForContext(context);
}
@Override
public boolean shouldAddToWindow(boolean isMainWindow, Set<Class<?>> contextTypes) {
for (Class<?> class1 : contextTypes) {
if (CodeViewerActionContext.class.isAssignableFrom(class1)) {
return true;
}
}
return false;
}
}

View file

@ -523,10 +523,12 @@ public class ProgramManagerPlugin extends Plugin implements ProgramManager {
int subMenuGroupOrder = 1;
openAction = new ActionBuilder("Open File", getName())
.onAction(c -> open())
.menuPath(ToolConstants.MENU_FILE, "&Open...")
.menuGroup(OPEN_GROUP, Integer.toString(subMenuGroupOrder++))
.keyBinding("ctrl O")
.withContext(ProgramActionContext.class)
.inWindow(ActionBuilder.When.CONTEXT_MATCHES)
.onAction(c -> open())
.buildAndInstall(tool);
closeAction = new ActionBuilder("Close File", getName())
@ -534,6 +536,7 @@ public class ProgramManagerPlugin extends Plugin implements ProgramManager {
.menuGroup(OPEN_GROUP, Integer.toString(subMenuGroupOrder++))
.withContext(ProgramActionContext.class)
.supportsDefaultToolContext(true)
.inWindow(ActionBuilder.When.CONTEXT_MATCHES)
.onAction(c -> closeProgram(c.getProgram(), false))
.keyBinding("ctrl W")
.buildAndInstall(tool);
@ -542,12 +545,16 @@ public class ProgramManagerPlugin extends Plugin implements ProgramManager {
.menuPath(ToolConstants.MENU_FILE, "Close &Others")
.menuGroup(OPEN_GROUP, Integer.toString(subMenuGroupOrder++))
.enabled(false)
.withContext(ProgramActionContext.class)
.inWindow(ActionBuilder.When.CONTEXT_MATCHES)
.onAction(c -> closeOtherPrograms(false))
.buildAndInstall(tool);
closeAllAction = new ActionBuilder("Close All", getName())
.menuPath(ToolConstants.MENU_FILE, "Close &All")
.menuGroup(OPEN_GROUP, Integer.toString(subMenuGroupOrder++))
.withContext(ProgramActionContext.class)
.inWindow(ActionBuilder.When.CONTEXT_MATCHES)
.onAction(c -> closeAllPrograms(false))
.enabled(false)
.buildAndInstall(tool);
@ -561,6 +568,7 @@ public class ProgramManagerPlugin extends Plugin implements ProgramManager {
.toolBarGroup(ToolConstants.TOOLBAR_GROUP_ONE)
.keyBinding("ctrl S")
.withContext(ProgramActionContext.class)
.inWindow(ActionBuilder.When.CONTEXT_MATCHES)
.supportsDefaultToolContext(true)
.enabledWhen(c -> c.getProgram() != null && c.getProgram().isChanged())
.onAction(c -> programSaveMgr.saveProgram(c.getProgram()))
@ -570,6 +578,7 @@ public class ProgramManagerPlugin extends Plugin implements ProgramManager {
.menuPath(ToolConstants.MENU_FILE, "Save &As...")
.menuGroup(SAVE_GROUP, Integer.toString(subMenuGroupOrder++))
.withContext(ProgramActionContext.class)
.inWindow(ActionBuilder.When.CONTEXT_MATCHES)
.supportsDefaultToolContext(true)
.onAction(c -> programSaveMgr.saveAs(c.getProgram()))
.buildAndInstall(tool);
@ -578,6 +587,8 @@ public class ProgramManagerPlugin extends Plugin implements ProgramManager {
.menuPath(ToolConstants.MENU_FILE, "Save All")
.description("Save All Programs")
.menuGroup(SAVE_GROUP, Integer.toString(subMenuGroupOrder++))
.withContext(ProgramActionContext.class)
.inWindow(ActionBuilder.When.CONTEXT_MATCHES)
.onAction(c -> programSaveMgr.saveChangedPrograms())
.buildAndInstall(tool);
@ -587,6 +598,7 @@ public class ProgramManagerPlugin extends Plugin implements ProgramManager {
.menuGroup(ToolConstants.TOOL_OPTIONS_MENU_GROUP,
ToolConstants.TOOL_OPTIONS_MENU_GROUP + "b")
.withContext(ProgramActionContext.class)
.inWindow(ActionBuilder.When.CONTEXT_MATCHES)
.supportsDefaultToolContext(true)
.onAction(c -> showProgramOptions(c.getProgram()))
.buildAndInstall(tool);

View file

@ -47,6 +47,9 @@ public class RedoAction extends ProgramContextAction {
setKeyBindingData(new KeyBindingData("ctrl shift Z"));
setDescription("Redo");
setSupportsDefaultToolContext(true);
// we want this action to appear in all windows that can produce a program context
addToWindowWhen(ProgramActionContext.class);
}
@Override

View file

@ -46,6 +46,9 @@ public class UndoAction extends ProgramContextAction {
setDescription("Undo");
setKeyBindingData(new KeyBindingData("ctrl Z"));
setSupportsDefaultToolContext(true);
// we want this action to appear in all windows that can produce a program context
addToWindowWhen(ProgramActionContext.class);
}
@Override

View file

@ -154,6 +154,7 @@ public class ScalarSearchPlugin extends ProgramPlugin implements DomainObjectLis
searchAction.setMenuBarData(new MenuData(
new String[] { ToolConstants.MENU_SEARCH, "For Scalars..." }, null, "search for"));
searchAction.setDescription("Search program for scalars");
searchAction.addToWindowWhen(NavigatableActionContext.class);
tool.addAction(searchAction);
//

View file

@ -263,31 +263,11 @@ class GhidraScriptActionManager {
.onAction(context -> showGhidraScriptJavadoc())
.buildAndInstallLocal(provider);
// XXX In order to override a method of the new DockingAction and use the builder, we
// need to override the build method of the ActionBuilder. When the ActionBuilder is
// updated, this code can be cleaned up.
new ActionBuilder("Ghidra API Help", plugin.getName()) {
@Override
public DockingAction build() {
validate();
DockingAction action = new DockingAction(name, owner, keyBindingType) {
@Override
public void actionPerformed(ActionContext context) {
actionCallback.accept(context);
}
@Override
public boolean shouldAddToWindow(boolean isMainWindow,
Set<Class<?>> contextTypes) {
return true;
}
};
decorateAction(action);
return action;
}
}.menuGroup(ToolConstants.HELP_CONTENTS_MENU_GROUP)
new ActionBuilder("Ghidra API Help", plugin.getName())
.menuGroup(ToolConstants.HELP_CONTENTS_MENU_GROUP)
.menuPath(ToolConstants.MENU_HELP, "Ghidra API Help")
.helpLocation(new HelpLocation("Misc", "Welcome_to_Ghidra_Help"))
.inWindow(ActionBuilder.When.ALWAYS)
.onAction(context -> showGhidraScriptJavadoc())
.buildAndInstall(plugin.getTool());
}

View file

@ -359,6 +359,7 @@ public class MemSearchPlugin extends Plugin implements OptionsChangeListener,
searchAction.setMenuBarData(new MenuData(menuPath, "search"));
searchAction.setKeyBindingData(new KeyBindingData('S', 0));
searchAction.setDescription("Search Memory for byte sequence");
searchAction.addToWindowWhen(NavigatableActionContext.class);
tool.addAction(searchAction);
searchAgainAction = new NavigatableContextAction("Repeat Memory Search", getName()) {
@ -379,6 +380,7 @@ public class MemSearchPlugin extends Plugin implements OptionsChangeListener,
searchAgainAction.setMenuBarData(new MenuData(menuPath, "search"));
searchAgainAction.setKeyBindingData(new KeyBindingData(KeyEvent.VK_F3, 0));
searchAgainAction.setDescription("Search Memory for byte sequence");
searchAgainAction.addToWindowWhen(NavigatableActionContext.class);
tool.addAction(searchAgainAction);
}

View file

@ -153,6 +153,8 @@ public class MnemonicSearchPlugin extends Plugin {
MENU_PULLRIGHT, "Include Operands (except constants)" }, null, group,
MenuData.NO_MNEMONIC, "3"));
setSearchMnemonicOpsNoConstAction.setHelpLocation(helpLocation);
setSearchMnemonicOpsNoConstAction
.addToWindowWhen(NavigatableActionContext.class);
//
// ACTION 2: Search for instructions, including operands.
@ -174,6 +176,8 @@ public class MnemonicSearchPlugin extends Plugin {
setSearchMnemonicOpsConstAction.setMenuBarData(new MenuData(new String[] { "&Search",
MENU_PULLRIGHT, "Include Operands" }, null, group, MenuData.NO_MNEMONIC, "2"));
setSearchMnemonicOpsConstAction.setHelpLocation(helpLocation);
setSearchMnemonicOpsConstAction
.addToWindowWhen(NavigatableActionContext.class);
//
// ACTION 3: Search for instructions, excluding constants.
@ -195,6 +199,8 @@ public class MnemonicSearchPlugin extends Plugin {
setSearchMnemonicNoOpsNoConstAction.setMenuBarData(new MenuData(new String[] { "&Search",
MENU_PULLRIGHT, "Exclude Operands" }, null, group, MenuData.NO_MNEMONIC, "1"));
setSearchMnemonicNoOpsNoConstAction.setHelpLocation(helpLocation);
setSearchMnemonicNoOpsNoConstAction
.addToWindowWhen(NavigatableActionContext.class);
// Add the actions to the tool...
tool.addAction(setSearchMnemonicOpsNoConstAction);

View file

@ -383,6 +383,7 @@ public class SearchTextPlugin extends ProgramPlugin implements OptionsChangeList
.description(DESCRIPTION)
.helpLocation(new HelpLocation(HelpTopics.SEARCH, "Search Text"))
.withContext(NavigatableActionContext.class)
.inWindow(ActionBuilder.When.CONTEXT_MATCHES)
.supportsDefaultToolContext(true)
.onAction(c -> {
setNavigatable(c.getNavigatable());
@ -398,6 +399,7 @@ public class SearchTextPlugin extends ProgramPlugin implements OptionsChangeList
.supportsDefaultToolContext(true)
.helpLocation(new HelpLocation(HelpTopics.SEARCH, "Repeat Text Search"))
.withContext(NavigatableActionContext.class)
.inWindow(ActionBuilder.When.CONTEXT_MATCHES)
.enabledWhen(c -> searchedOnce)
.onAction(c -> {
setNavigatable(c.getNavigatable());

View file

@ -15,19 +15,19 @@
*/
package ghidra.app.plugin.core.select;
import docking.ActionContext;
import docking.ComponentProvider;
import docking.action.DockingAction;
import docking.action.MenuData;
import docking.tool.ToolConstants;
import ghidra.app.CorePluginPackage;
import ghidra.app.context.NavigatableActionContext;
import ghidra.app.context.NavigatableContextAction;
import ghidra.app.nav.Navigatable;
import ghidra.app.plugin.PluginCategoryNames;
import ghidra.framework.plugintool.*;
import ghidra.framework.plugintool.util.*;
import ghidra.framework.plugintool.util.PluginStatus;
import ghidra.util.HelpLocation;
import docking.ActionContext;
import docking.ComponentProvider;
import docking.action.DockingAction;
import docking.action.MenuData;
import docking.tool.ToolConstants;
/**
* This plugin class contains the structure needed for the user to
@ -72,9 +72,11 @@ public class SelectBlockPlugin extends Plugin {
}
};
MenuData menuData =
new MenuData(new String[] { ToolConstants.MENU_SELECTION, "Bytes..." }, null, "Select");
new MenuData(new String[] { ToolConstants.MENU_SELECTION, "Bytes..." }, null,
"Select Group 2");
menuData.setMenuSubGroup("1");
toolBarAction.setMenuBarData(menuData);
toolBarAction.addToWindowWhen(NavigatableActionContext.class);
toolBarAction.setEnabled(false);
toolBarAction.setDescription("Allows user to select blocks of data.");

View file

@ -15,10 +15,14 @@
*/
package ghidra.app.plugin.core.select.flow;
import java.util.ArrayList;
import java.util.Iterator;
import docking.action.DockingAction;
import docking.action.MenuData;
import ghidra.GhidraOptions;
import ghidra.app.CorePluginPackage;
import ghidra.app.context.NavigatableActionContext;
import ghidra.app.context.NavigatableContextAction;
import ghidra.app.context.*;
import ghidra.app.events.ProgramSelectionPluginEvent;
import ghidra.app.nav.NavigationUtils;
import ghidra.app.plugin.PluginCategoryNames;
@ -38,12 +42,6 @@ import ghidra.util.exception.CancelledException;
import ghidra.util.exception.InvalidInputException;
import ghidra.util.task.*;
import java.util.ArrayList;
import java.util.Iterator;
import docking.action.DockingAction;
import docking.action.MenuData;
/**
* The SelectByFlowPlugin adds selection of code based on program flow to a
* tool. Selection is based on the initial selection or if there is no selection
@ -484,9 +482,9 @@ public class SelectByFlowPlugin extends Plugin implements OptionsChangeListener
selectProgramChangesAction.setHelpLocation(new HelpLocation(HelpTopics.SELECTION,
selectProgramChangesAction.getName()));
selectProgramChangesAction.getMenuBarData().setMenuSubGroup(
Integer.toString(subMenuGroupPosition++));
selectProgramChangesAction.addToWindowWhen(NavigatableActionContext.class);
tool.addAction(selectProgramChangesAction);
/**
@ -496,6 +494,7 @@ public class SelectByFlowPlugin extends Plugin implements OptionsChangeListener
new SelectByFlowAction("Select All Flows From", this, SELECT_ALL_FLOWS_FROM);
selectAllFlowsFromAction.getMenuBarData().setMenuSubGroup(
Integer.toString(subMenuGroupPosition++));
selectAllFlowsFromAction.addToWindowWhen(ListingActionContext.class);
tool.addAction(selectAllFlowsFromAction);
/**
@ -505,6 +504,7 @@ public class SelectByFlowPlugin extends Plugin implements OptionsChangeListener
new SelectByFlowAction("Select All Flows To", this, SELECT_ALL_FLOWS_TO);
selectAllFlowsToAction.getMenuBarData().setMenuSubGroup(
Integer.toString(subMenuGroupPosition++));
selectAllFlowsToAction.addToWindowWhen(ListingActionContext.class);
tool.addAction(selectAllFlowsToAction);
/**
@ -514,6 +514,7 @@ public class SelectByFlowPlugin extends Plugin implements OptionsChangeListener
new SelectByFlowAction("Select Limited Flows From", this, SELECT_LIMITED_FLOWS_FROM);
selectLimitedFlowsFromAction.getMenuBarData().setMenuSubGroup(
Integer.toString(subMenuGroupPosition++));
selectLimitedFlowsFromAction.addToWindowWhen(ListingActionContext.class);
tool.addAction(selectLimitedFlowsFromAction);
/**
@ -523,6 +524,7 @@ public class SelectByFlowPlugin extends Plugin implements OptionsChangeListener
new SelectByFlowAction("Select Limited Flows To", this, SELECT_LIMITED_FLOWS_TO);
selectLimitedFlowsToAction.getMenuBarData().setMenuSubGroup(
Integer.toString(subMenuGroupPosition++));
selectLimitedFlowsToAction.addToWindowWhen(ListingActionContext.class);
tool.addAction(selectLimitedFlowsToAction);
/**
@ -532,6 +534,7 @@ public class SelectByFlowPlugin extends Plugin implements OptionsChangeListener
new SelectByFlowAction("Select Subroutine", this, SELECT_SUBROUTINES);
selectSubroutineAction.getMenuBarData().setMenuSubGroup(
Integer.toString(subMenuGroupPosition++));
selectSubroutineAction.addToWindowWhen(ListingActionContext.class);
tool.addAction(selectSubroutineAction);
/**
@ -541,6 +544,7 @@ public class SelectByFlowPlugin extends Plugin implements OptionsChangeListener
new SelectByFlowAction("Select Dead Subroutine", this, SELECT_DEAD_SUBROUTINES);
selectDeadSubroutineAction.getMenuBarData().setMenuSubGroup(
Integer.toString(subMenuGroupPosition++));
selectDeadSubroutineAction.addToWindowWhen(ListingActionContext.class);
tool.addAction(selectDeadSubroutineAction);
/**
@ -549,6 +553,7 @@ public class SelectByFlowPlugin extends Plugin implements OptionsChangeListener
selectFunctionAction = new SelectByFlowAction("Select Function", this, SELECT_FUNCTIONS);
selectFunctionAction.getMenuBarData().setMenuSubGroup(
Integer.toString(subMenuGroupPosition++));
selectFunctionAction.addToWindowWhen(ListingActionContext.class);
tool.addAction(selectFunctionAction);
}

View file

@ -98,7 +98,7 @@ public class SelectByScopedFlowPlugin extends ProgramPlugin {
action.setMenuBarData(new MenuData(
new String[] { ToolConstants.MENU_SELECTION, "Scoped Flow", "Forward Scoped Flow" },
null, "Select"));
action.addToWindowWhen(NavigatableActionContext.class);
action.setDescription("Allows user to select scoped flow from current location.");
action.setHelpLocation(new HelpLocation("FlowSelection", "Scoped_Flow"));
tool.addAction(action);
@ -131,7 +131,7 @@ public class SelectByScopedFlowPlugin extends ProgramPlugin {
action.setMenuBarData(new MenuData(
new String[] { ToolConstants.MENU_SELECTION, "Scoped Flow", "Reverse Scoped Flow" },
null, "Select"));
action.addToWindowWhen(NavigatableActionContext.class);
action.setDescription("Allows user to select scoped flow to the current location.");
action.setHelpLocation(new HelpLocation("FlowSelection", "Scoped_Flow"));
tool.addAction(action);

View file

@ -25,7 +25,7 @@ import ghidra.app.nav.NavigationUtils;
import ghidra.app.plugin.PluginCategoryNames;
import ghidra.app.util.HelpTopics;
import ghidra.framework.plugintool.*;
import ghidra.framework.plugintool.util.*;
import ghidra.framework.plugintool.util.PluginStatus;
import ghidra.program.model.address.*;
import ghidra.program.model.listing.*;
import ghidra.program.util.ProgramSelection;
@ -301,8 +301,8 @@ public class QualifiedSelectionPlugin extends Plugin {
setHelpLocation(new HelpLocation(HelpTopics.SELECTION, name));
setEnabled(false);
setMenuBarData(new MenuData(new String[] { ToolConstants.MENU_SELECTION, name }, null,
"Select"));
"Select Group 2"));
addToWindowWhen(NavigatableActionContext.class);
}
}

View file

@ -1,6 +1,5 @@
/* ###
* IP: GHIDRA
* REVIEWED: YES
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -16,24 +15,23 @@
*/
package ghidra.app.plugin.core.select.reference;
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;
import ghidra.program.model.address.*;
import ghidra.program.model.listing.*;
import ghidra.program.model.listing.Program;
import ghidra.program.model.symbol.Reference;
import ghidra.program.model.symbol.ReferenceIterator;
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 SelectBackRefsAction extends NavigatableContextAction {
private final PluginTool tool;
@ -47,6 +45,7 @@ public class SelectBackRefsAction extends NavigatableContextAction {
setKeyBindingData( new KeyBindingData(KeyEvent.VK_SEMICOLON, InputEvent.CTRL_MASK ) );
setHelpLocation(new HelpLocation(HelpTopics.SELECTION, "Backward"));
addToWindowWhen(NavigatableActionContext.class);
}
@Override

View file

@ -46,6 +46,7 @@ public class SelectForwardRefsAction extends NavigatableContextAction {
setHelpLocation(new HelpLocation(HelpTopics.SELECTION, "Forward"));
// setKeyBindingData( new KeyBindingData(KeyEvent.VK_SEMICOLON, InputEvent.CTRL_MASK ) );
// setHelpLocation(new HelpLocation(HelpTopics.SELECTION, "Backward"));
addToWindowWhen(NavigatableActionContext.class);
}
@Override

View file

@ -80,7 +80,7 @@ public class StringTablePlugin extends ProgramPlugin {
new String[] { ToolConstants.MENU_SEARCH, "For &Strings..." }, null, "search for"));
stringSearchAction.setDescription(getPluginDescription().getDescription());
stringSearchAction.addToWindowWhen(NavigatableActionContext.class);
tool.addAction(stringSearchAction);
}

View file

@ -24,8 +24,7 @@ import docking.action.MenuData;
import docking.tool.ToolConstants;
import docking.widgets.conditiontestpanel.ConditionTester;
import ghidra.app.CorePluginPackage;
import ghidra.app.context.ProgramActionContext;
import ghidra.app.context.ProgramContextAction;
import ghidra.app.context.*;
import ghidra.app.plugin.PluginCategoryNames;
import ghidra.app.plugin.core.analysis.validator.PostAnalysisValidator;
import ghidra.framework.plugintool.*;
@ -95,7 +94,7 @@ public class ValidateProgramPlugin extends Plugin {
return true;
}
};
validateAction.addToWindowWhen(ListingActionContext.class);
validateAction.setMenuBarData(new MenuData(new String[] { ToolConstants.MENU_ANALYSIS,
ACTION_NAME }, null, "ZZZ"));

View file

@ -15,19 +15,11 @@
*/
package ghidra.app.plugin.prototype.debug;
import ghidra.app.DeveloperPluginPackage;
import ghidra.app.plugin.PluginCategoryNames;
import ghidra.app.plugin.ProgramPlugin;
import ghidra.framework.plugintool.PluginInfo;
import ghidra.framework.plugintool.PluginTool;
import ghidra.framework.plugintool.util.*;
import java.awt.*;
import java.awt.event.InputEvent;
import java.awt.event.KeyEvent;
import java.awt.image.RenderedImage;
import java.io.File;
import java.util.Set;
import javax.imageio.ImageIO;
import javax.swing.*;
@ -36,6 +28,12 @@ import javax.swing.filechooser.FileNameExtensionFilter;
import docking.*;
import docking.action.*;
import docking.tool.ToolConstants;
import ghidra.app.DeveloperPluginPackage;
import ghidra.app.plugin.PluginCategoryNames;
import ghidra.app.plugin.ProgramPlugin;
import ghidra.framework.plugintool.PluginInfo;
import ghidra.framework.plugintool.PluginTool;
import ghidra.framework.plugintool.util.PluginStatus;
//@formatter:off
@PluginInfo(
@ -93,13 +91,8 @@ public class ScreenshotPlugin extends ProgramPlugin {
writeFile(image, file);
}
}
@Override
public boolean shouldAddToWindow(boolean isMainWindow, Set<Class<?>> contextTypes) {
return true;// this is a global-level action
}
};
captureActiveWindowAction.setAddToAllWindows(true);
captureActiveWindowAction.setDescription("Takes a screenshot of the active component provider and exports it to PNG format.");
captureActiveWindowAction.setKeyBindingData(new KeyBindingData(KeyEvent.VK_F11,
InputEvent.ALT_DOWN_MASK));
@ -123,13 +116,8 @@ public class ScreenshotPlugin extends ProgramPlugin {
writeFile(image, file);
}
}
@Override
public boolean shouldAddToWindow(boolean isMainWindow, Set<Class<?>> contextTypes) {
return true;// this is a global-level action
}
};
captureToolFrameAction.setAddToAllWindows(true);
captureToolFrameAction.setDescription("Takes a screenshot of the active tool and exports it to PNG format.");
captureToolFrameAction.setKeyBindingData(new KeyBindingData(KeyEvent.VK_F12,
InputEvent.ALT_DOWN_MASK));

View file

@ -21,6 +21,7 @@ import java.awt.Window;
import org.junit.*;
import docking.ActionContext;
import docking.action.DockingActionIf;
import docking.action.ToggleDockingAction;
import docking.util.image.ToolIconURL;
@ -175,7 +176,8 @@ public class DiffSaveSettingsTest extends DiffApplyTestAdapter {
ProgramManagerPlugin pm = getPlugin(tool, ProgramManagerPlugin.class);
DockingActionIf closeAllProgramAction = getAction(pm, "Close All");
assertNotNull(closeAllProgramAction);
performAction(closeAllProgramAction, true);
ActionContext defaultContext = tool.getDefaultToolContext();
performAction(closeAllProgramAction, defaultContext, true);
openProgram(p3);

View file

@ -50,6 +50,7 @@ public class WindowActionManager {
public void setActions(List<DockingActionIf> actionList) {
menuBarMgr.clearActions();
toolBarMgr.clearActions();
actionToProxyMap.clear();
for (DockingActionIf action : actionList) {
addAction(action);
}

View file

@ -15,8 +15,6 @@
*/
package docking.action;
import java.util.Set;
import docking.ActionContext;
/**
@ -68,16 +66,6 @@ public abstract class ContextSpecificAction<T> extends DockingAction {
return false;
}
@Override
public boolean shouldAddToWindow(boolean isMainWindow, Set<Class<?>> contextTypes) {
for (Class<?> class1 : contextTypes) {
if (contextClass.isAssignableFrom(class1)) {
return true;
}
}
return false;
}
@Override
public void actionPerformed(ActionContext actionContext) {
actionPerformed(contextClass.cast(actionContext));

View file

@ -83,6 +83,8 @@ public abstract class DockingAction implements DockingActionIf {
private Predicate<ActionContext> enabledPredicate;
private Predicate<ActionContext> popupPredicate;
private Predicate<ActionContext> validContextPredicate;
private boolean shouldAddToAllWindows = false;
private Class<? extends ActionContext> addToWindowWhenContextClass = null;
private boolean supportsDefaultToolContext;
@ -193,15 +195,42 @@ public abstract class DockingAction implements DockingActionIf {
}
/**
* Default behavior is to add to main window;
* Determines if this action should be added to a window.
* <P>
* If the client wants the action on all windows, then they can call {@link #shouldAddToAllWindows}
* <P>
* If the client wants the action to be on a window only when the window can produce
* a certain context type, the the client should call
* {@link #addToWindowWhen(Class)}
* <P>
* Otherwise, by default, the action will only be on the main window.
*
*/
@Override
public boolean shouldAddToWindow(boolean isMainWindow, Set<Class<?>> contextTypes) {
if (isMainWindow) {
// only return true if it is a tool menu or toolbar action
return menuBarData != null || toolBarData != null;
public final boolean shouldAddToWindow(boolean isMainWindow, Set<Class<?>> contextTypes) {
// this method only applies to actions with top level menus or tool bars.
if (menuBarData == null && toolBarData == null) {
return false;
}
return false;
// clients can specify that the action should be on all windows.
if (shouldAddToAllWindows) {
return true;
}
// clients can specify a context class that determines if an action should
// be added to a window.
if (addToWindowWhenContextClass != null) {
for (Class<?> class1 : contextTypes) {
if (addToWindowWhenContextClass.isAssignableFrom(class1)) {
return true;
}
}
return false;
}
// default to only appearing in main window
return isMainWindow;
}
/**
@ -584,6 +613,30 @@ public abstract class DockingAction implements DockingActionIf {
validContextPredicate = predicate;
}
/**
* Sets the ActionContext class for when this action should be added to a window
* <P>
* If this is set, the the action will only be added to windows that have providers
* that can produce an ActionContext that is appropriate for this action.
* <P>
* @param contextClass the ActionContext class required to be producible by a
* provider that is hosted in that window before this action is added to that
* window.
*
*/
public void addToWindowWhen(Class<? extends ActionContext> contextClass) {
addToWindowWhenContextClass = contextClass;
}
/**
* Tells this action to add itself to all windows
* <P>
* @param b to add to all windows or not
*/
public void setAddToAllWindows(boolean b) {
shouldAddToAllWindows = b;
}
//==================================================================================================
// Non-public methods
//==================================================================================================
@ -611,4 +664,5 @@ public abstract class DockingAction implements DockingActionIf {
String classInfo = trace[0].toString();
return classInfo;
}
}

View file

@ -284,10 +284,9 @@ public interface DockingActionIf extends HelpDescriptor {
/**
* Determines whether this action should be added to a window (either the main window or a
* secondary detached window). By default, this method will return true for the main window
* and false otherwise. Actions that want to also appear in other windows should override this
* method to return true when appropriate for the context types
* @param isMainWindow true if the window in question is the main window. Otherwise, the window
* is a secondary window.
* and false otherwise.
*
* @param isMainWindow true if the window in question is the main window
* @param contextTypes a list of contextTypes (Classes) based on the providers that are currently
* in the window.
* @return true if this action should be added to the window, false otherwise.

View file

@ -176,7 +176,23 @@ public abstract class AbstractActionBuilder<T extends DockingActionIf, C extends
* Set to true if the action supports using the default tool context if the local context is invalid
*/
private boolean supportsDefaultToolContext;
/**
* Specifies when the action should appear in a window.
*/
private When windowWhen;
/**
* For use with the {@link AbstractActionBuilder#inWindow(When)} method to specify which windows (main window
* or secondary windows) a global tool bar or menu action will appear in.
*
*/
public enum When {
MAIN_WINDOW, // action should only appear in the main window
ALWAYS, // action should appear in all windows
CONTEXT_MATCHES // action should appear if and only if the window has
} // has a provider that generates the appropriate context.
/**
* Builder constructor
* @param name the name of the action to be built
@ -197,7 +213,7 @@ public abstract class AbstractActionBuilder<T extends DockingActionIf, C extends
/**
* Builds the action. To build and install the action in one step, use
* {@link #buildAndInstall(Tool)} or {@link #buildAndInstallLocal(ComponentProvider)}.
*
* {@link #inWindow(When)}
* @return the newly build action
*/
public abstract T build();
@ -592,6 +608,29 @@ public abstract class AbstractActionBuilder<T extends DockingActionIf, C extends
supportsDefaultToolContext = b;
return self();
}
/**
* Specifies when a global action should appear in a window (main or secondary).
* <P>
* Global menu or toolbar actions can be configured to appear in 1) only the main
* window, or 2) all windows, or 3) any window that has a provider that
* generates an action context that matches the context that this action
* consumes. If the "context matches" options is chosen, then the
* {@link #withContext(Class)} method must also be called to specify the matching
* context; otherwise an exception will be thrown when the action is built.
* <P>
*
* The default is that the action will only appear in the main window.
*
* @param when use the {@link When} enum to specify the windowing behavior
* of the action.
*
* @return this builder (for chaining)
*/
public B inWindow(When when) {
this.windowWhen = when;
return self();
}
/**
* Sets the specific ActionContext type to use for the various predicate calls
@ -669,6 +708,11 @@ public abstract class AbstractActionBuilder<T extends DockingActionIf, C extends
throw new IllegalStateException(
"Can't build a DockingAction without an action callback");
}
if (windowWhen == When.CONTEXT_MATCHES && actionContextClass == null) {
throw new IllegalStateException("The InWindow state was set to "
+ "\"CONTEXT_MATCHES\", but no context class was set. Use"
+ " the \"withContext\" method");
}
}
protected void decorateAction(DockingAction action) {
@ -691,6 +735,14 @@ public abstract class AbstractActionBuilder<T extends DockingActionIf, C extends
action.validContextWhen(adaptPredicate(validContextPredicate));
action.popupWhen(adaptPredicate(popupPredicate));
if (windowWhen == When.ALWAYS) {
action.setAddToAllWindows(true);
}
else if (windowWhen == When.CONTEXT_MATCHES) {
action.addToWindowWhen(actionContextClass);
}
// else action defaults to main window only
}
/**

View file

@ -32,6 +32,7 @@ import org.jdom.Element;
import docking.*;
import docking.action.*;
import docking.action.builder.ActionBuilder;
import docking.actions.PopupActionProvider;
import docking.actions.ToolActions;
import docking.framework.AboutDialog;
@ -921,11 +922,8 @@ public abstract class PluginTool extends AbstractDockingTool {
optionsMgr.editOptions();
}
@Override
public boolean shouldAddToWindow(boolean isMainWindow, Set<Class<?>> contextTypes) {
return isMainWindow || !contextTypes.isEmpty();
}
};
optionsAction.setAddToAllWindows(true);
optionsAction.setHelpLocation(
new HelpLocation(ToolConstants.FRONT_END_HELP_TOPIC, "Tool Options"));
MenuData menuData =
@ -1016,90 +1014,43 @@ public abstract class PluginTool extends AbstractDockingTool {
}
protected void addHelpActions() {
new ActionBuilder("About Ghidra", ToolConstants.TOOL_OWNER)
.menuPath(ToolConstants.MENU_HELP, "&About Ghidra")
.menuGroup("ZZA")
.helpLocation(new HelpLocation(ToolConstants.ABOUT_HELP_TOPIC, "About_Ghidra"))
.inWindow(ActionBuilder.When.ALWAYS)
.onAction(c -> DockingWindowManager.showDialog(new AboutDialog()))
.buildAndInstall(this);
DockingAction action = new DockingAction("About Ghidra", ToolConstants.TOOL_OWNER) {
@Override
public void actionPerformed(ActionContext context) {
DockingWindowManager.showDialog(new AboutDialog());
}
@Override
public boolean shouldAddToWindow(boolean isMainWindow, Set<Class<?>> contextTypes) {
return true;
}
};
action.setMenuBarData(
new MenuData(new String[] { ToolConstants.MENU_HELP, "&About Ghidra" }, null, "ZZA"));
action.setHelpLocation(new HelpLocation(ToolConstants.ABOUT_HELP_TOPIC, "About_Ghidra"));
action.setEnabled(true);
addAction(action);
DockingAction userAgreementAction = new DockingAction("User Agreement",
ToolConstants.TOOL_OWNER, KeyBindingType.UNSUPPORTED) {
@Override
public void actionPerformed(ActionContext context) {
DockingWindowManager.showDialog(new UserAgreementDialog(false, false));
}
@Override
public boolean shouldAddToWindow(boolean isMainWindow, Set<Class<?>> contextTypes) {
return true;
}
};
userAgreementAction.setMenuBarData(
new MenuData(new String[] { ToolConstants.MENU_HELP, "&User Agreement" }, null,
ToolConstants.HELP_CONTENTS_MENU_GROUP));
userAgreementAction.setHelpLocation(
new HelpLocation(ToolConstants.ABOUT_HELP_TOPIC, "User_Agreement"));
userAgreementAction.setEnabled(true);
addAction(userAgreementAction);
new ActionBuilder("User Agreement", ToolConstants.TOOL_OWNER)
.menuPath(ToolConstants.MENU_HELP, "&User Agreement")
.menuGroup(ToolConstants.HELP_CONTENTS_MENU_GROUP)
.helpLocation(new HelpLocation(ToolConstants.ABOUT_HELP_TOPIC, "User_Agreement"))
.inWindow(ActionBuilder.When.ALWAYS)
.onAction(
c -> DockingWindowManager.showDialog(new UserAgreementDialog(false, false)))
.buildAndInstall(this);
final ErrorReporter reporter = ErrLogDialog.getErrorReporter();
if (reporter != null) {
action = new DockingAction("Report Bug", ToolConstants.TOOL_OWNER) {
@Override
public void actionPerformed(ActionContext context) {
reporter.report(getToolFrame(), "User Bug Report", null);
}
@Override
public boolean shouldAddToWindow(boolean isMainWindow, Set<Class<?>> contextTypes) {
return true;
}
};
action.setMenuBarData(new MenuData(
new String[] { ToolConstants.MENU_HELP, "&Report Bug..." }, null, "BBB"));
action.setHelpLocation(new HelpLocation("ErrorReporting", "Report_Bug"));
action.setEnabled(true);
addAction(action);
new ActionBuilder("Report Bug", ToolConstants.TOOL_OWNER)
.menuPath(ToolConstants.MENU_HELP, "&Report Bug...")
.menuGroup("BBB")
.helpLocation(new HelpLocation("ErrorReporting", "Report_Bug"))
.inWindow(ActionBuilder.When.ALWAYS)
.onAction(c -> reporter.report(getToolFrame(), "User Bug Report", null))
.buildAndInstall(this);
}
HelpService help = Help.getHelpService();
action = new DockingAction("Contents", ToolConstants.TOOL_OWNER) {
@Override
public void actionPerformed(ActionContext context) {
help.showHelp(null, false, getToolFrame());
}
@Override
public boolean shouldAddToWindow(boolean isMainWindow, Set<Class<?>> contextTypes) {
return true;
}
};
action.setMenuBarData(new MenuData(new String[] { ToolConstants.MENU_HELP, "&Contents" },
null, ToolConstants.HELP_CONTENTS_MENU_GROUP));
action.setEnabled(true);
action.setHelpLocation(new HelpLocation("Misc", "Welcome_to_Ghidra_Help"));
addAction(action);
new ActionBuilder("Contents", ToolConstants.TOOL_OWNER)
.menuPath(ToolConstants.MENU_HELP, "&Contents")
.menuGroup(ToolConstants.HELP_CONTENTS_MENU_GROUP)
.helpLocation(new HelpLocation("Misc", "Welcome_to_Ghidra_Help"))
.inWindow(ActionBuilder.When.ALWAYS)
.onAction(c -> help.showHelp(null, false, getToolFrame()))
.buildAndInstall(this);
}
/**