diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/context/NavigatableContextAction.java b/Ghidra/Features/Base/src/main/java/ghidra/app/context/NavigatableContextAction.java index 7106e32182..4dbeae78eb 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/context/NavigatableContextAction.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/context/NavigatableContextAction.java @@ -17,11 +17,9 @@ package ghidra.app.context; import java.util.Set; -import docking.*; +import docking.ActionContext; import docking.action.DockingAction; import docking.action.KeyBindingType; -import ghidra.app.nav.Navigatable; -import ghidra.app.services.GoToService; public abstract class NavigatableContextAction extends DockingAction { @@ -52,7 +50,11 @@ public abstract class NavigatableContextAction extends DockingAction { isValidNavigationContext((NavigatableActionContext) context)) { return (NavigatableActionContext) context; } - return getGlobalNavigationContext(context); + ActionContext globalContext = context.getGlobalContext(); + if (globalContext instanceof NavigatableActionContext) { + return (NavigatableActionContext) globalContext; + } + return null; } @Override @@ -64,34 +66,6 @@ public abstract class NavigatableContextAction extends DockingAction { return true; } - private NavigatableActionContext getGlobalNavigationContext(ActionContext context) { - Tool tool = getTool(context.getComponentProvider()); - - if (tool == null) { - return null; - } - GoToService service = tool.getService(GoToService.class); - if (service == null) { - return null; - } - Navigatable defaultNavigatable = service.getDefaultNavigatable(); - if (defaultNavigatable.getProgram() == null) { - return null; - } - return new NavigatableActionContext(null, defaultNavigatable); - } - - private Tool getTool(ComponentProvider provider) { - if (provider != null) { - return provider.getTool(); - } - DockingWindowManager manager = DockingWindowManager.getActiveInstance(); - if (manager != null) { - return manager.getTool(); - } - return null; - } - @Override public boolean isAddToPopup(ActionContext context) { if (!(context instanceof NavigatableActionContext)) { diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/analysis/AutoAnalysisPlugin.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/analysis/AutoAnalysisPlugin.java index ed3362a521..f16f335b85 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/analysis/AutoAnalysisPlugin.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/analysis/AutoAnalysisPlugin.java @@ -21,12 +21,13 @@ import javax.swing.SwingUtilities; import docking.ActionContext; import docking.DockingWindowManager; -import docking.action.*; +import docking.action.DockingAction; +import docking.action.MenuData; +import docking.action.builder.ActionBuilder; import docking.widgets.dialogs.MultiLineMessageDialog; import ghidra.GhidraOptions; import ghidra.app.CorePluginPackage; import ghidra.app.context.ListingActionContext; -import ghidra.app.context.ListingContextAction; import ghidra.app.events.*; import ghidra.app.plugin.PluginCategoryNames; import ghidra.app.services.Analyzer; @@ -107,53 +108,57 @@ public class AutoAnalysisPlugin extends Plugin implements AutoAnalysisManagerLis // use this index to make sure that the following actions are ordered in the way that // they are inserted int subGroupIndex = 0; + + autoAnalyzeAction = new ActionBuilder("Auto Analyze", getName()) + .menuPath("&Analysis", "&Auto Analyze...") + .menuGroup(ANALYZE_GROUP_NAME, "" + subGroupIndex++) + .keyBinding("A") + .onAction(this::analyzeCallback) + .enabledWhen(this::canAnalyze) + .buildAndInstall(tool); - autoAnalyzeAction = new ListingContextAction("Auto Analyze", getName()) { - @Override - protected void actionPerformed(ListingActionContext programContext) { - analyzeCallback(programContext.getProgram(), programContext.getSelection()); - } - - @Override - public boolean isEnabledForContext(ListingActionContext context) { - Program program = context.getProgram(); - getMenuBarData().setMenuItemName( - "&Auto Analyze '" + program.getDomainFile().getName() + "'..."); - return true; - } - }; - String[] menuPath = { "&Analysis", "&Auto Analyze..." }; - MenuData menuData = new MenuData(menuPath, null, ANALYZE_GROUP_NAME); - menuData.setMenuSubGroup("" + subGroupIndex++); - autoAnalyzeAction.setMenuBarData(menuData); - - autoAnalyzeAction.setKeyBindingData(new KeyBindingData('A', 0)); - - tool.addAction(autoAnalyzeAction); - - analyzeAllAction = new DockingAction("Analyze All Open", getName()) { - @Override - public void actionPerformed(ActionContext context) { - analyzeAllCallback(); - } - - @Override - public boolean isEnabledForContext(ActionContext context) { - return context.getContextObject() instanceof ListingActionContext; - } - }; - analyzeAllAction.setEnabled(false); - menuData = - new MenuData(new String[] { "&Analysis", "Analyze All &Open..." }, ANALYZE_GROUP_NAME); - menuData.setMenuSubGroup("" + subGroupIndex++); - analyzeAllAction.setMenuBarData(menuData); - - tool.addAction(analyzeAllAction); + analyzeAllAction = new ActionBuilder("Analyze All Open", getName()) + .menuPath("&Analysis", "Analyze All &Open...") + .menuGroup(ANALYZE_GROUP_NAME, "" + subGroupIndex++) + .onAction(c -> analyzeAllCallback()) + .enabledWhen(c -> getListingContext(c) != null) + .buildAndInstall(tool); tool.setMenuGroup(new String[] { "Analysis", "One Shot" }, ANALYZE_GROUP_NAME); } + private boolean canAnalyze(ActionContext context) { + ListingActionContext listingContext = getListingContext(context); + updateActionName(listingContext); + return listingContext != null; + } + + private void updateActionName(ListingActionContext listingContext) { + String programName = ""; + if (listingContext != null) { + programName = listingContext.getProgram().getDomainFile().getName(); + } + MenuData menuBarData = autoAnalyzeAction.getMenuBarData(); + menuBarData.setMenuItemName("&Auto Analyze '" + programName + "'..."); + } + + private ListingActionContext getListingContext(ActionContext context) { + if (context instanceof ListingActionContext) { + return (ListingActionContext) context; + } + ActionContext globalContext = context.getGlobalContext(); + if (globalContext instanceof ListingActionContext) { + return (ListingActionContext) globalContext; + } + return null; + } + + private void analyzeCallback(ActionContext context) { + ListingActionContext listingContext = getListingContext(context); + analyzeCallback(listingContext.getProgram(), listingContext.getSelection()); + } + private void addOneShotActions(Program program) { removeOneShotActions(); for (Analyzer analyzer : analyzers) { @@ -322,7 +327,7 @@ public class AutoAnalysisPlugin extends Plugin implements AutoAnalysisManagerLis } } - class OneShotAnalyzerAction extends ListingContextAction { + class OneShotAnalyzerAction extends DockingAction { private Analyzer analyzer; private Program canAnalyzeProgram; private boolean canAnalyze; @@ -338,7 +343,8 @@ public class AutoAnalysisPlugin extends Plugin implements AutoAnalysisManagerLis } @Override - public void actionPerformed(ListingActionContext programContext) { + public void actionPerformed(ActionContext context) { + ListingActionContext programContext = getListingContext(context); AddressSetView set; if (programContext.hasSelection()) { set = programContext.getSelection(); @@ -363,7 +369,8 @@ public class AutoAnalysisPlugin extends Plugin implements AutoAnalysisManagerLis } @Override - protected boolean isEnabledForContext(ListingActionContext programContext) { + public boolean isEnabledForContext(ActionContext context) { + ListingActionContext programContext = getListingContext(context); Program p = programContext.getProgram(); if (p != canAnalyzeProgram) { canAnalyzeProgram = p; diff --git a/Ghidra/Framework/Docking/src/main/java/docking/ActionContext.java b/Ghidra/Framework/Docking/src/main/java/docking/ActionContext.java index 3deb7fc1fc..a5c6244618 100644 --- a/Ghidra/Framework/Docking/src/main/java/docking/ActionContext.java +++ b/Ghidra/Framework/Docking/src/main/java/docking/ActionContext.java @@ -78,6 +78,7 @@ public class ActionContext { private MouseEvent mouseEvent; private Object contextObject; private Object sourceObject; + private ActionContext globalContext; // Note: the setting of this object is delayed. This allows clients to build-up the state // of this context. This object will be set when getSourceComponent() is called if it @@ -243,4 +244,29 @@ public class ActionContext { //@formatter:on } + /** + * Returns the global action context for the tool. The global context is the context of + * the default focused component, instead of the normal action context which is the current + * focused component. + * @return the global action context for the tool + */ + public ActionContext getGlobalContext() { + if (globalContext == null) { + Tool tool = getTool(); + globalContext = tool == null ? new ActionContext() : tool.getGlobalActionContext(); + } + return globalContext; + } + + private Tool getTool() { + if (provider != null) { + return provider.getTool(); + } + DockingWindowManager manager = DockingWindowManager.getActiveInstance(); + if (manager != null) { + return manager.getTool(); + } + return null; + } + } diff --git a/Ghidra/Framework/Docking/src/main/java/docking/DockingWindowManager.java b/Ghidra/Framework/Docking/src/main/java/docking/DockingWindowManager.java index f83f1812f2..24a6132904 100644 --- a/Ghidra/Framework/Docking/src/main/java/docking/DockingWindowManager.java +++ b/Ghidra/Framework/Docking/src/main/java/docking/DockingWindowManager.java @@ -2140,6 +2140,15 @@ public class DockingWindowManager implements PropertyChangeListener, Placeholder contextListeners.remove(listener); } + /** + * Returns the global action context for the tool + * @return the global action context for the tool + */ + public ActionContext getGlobalActionContext() { + return defaultProvider == null ? new ActionContext() + : defaultProvider.getActionContext(null); + } + void notifyContextListeners(ComponentPlaceholder placeHolder, ActionContext actionContext) { if (placeHolder == focusedPlaceholder) { diff --git a/Ghidra/Framework/Docking/src/main/java/docking/Tool.java b/Ghidra/Framework/Docking/src/main/java/docking/Tool.java index b0a6d08277..82d9298534 100644 --- a/Ghidra/Framework/Docking/src/main/java/docking/Tool.java +++ b/Ghidra/Framework/Docking/src/main/java/docking/Tool.java @@ -304,4 +304,12 @@ public interface Tool extends ServiceProvider { */ public void close(); + /** + * Returns the global action context for the tool. The global context is the context of + * the default focused component, instead of the normal action context which is the current + * focused component. + * @return the global action context for the tool + */ + public ActionContext getGlobalActionContext(); + } diff --git a/Ghidra/Framework/Docking/src/test/java/docking/FakeDockingTool.java b/Ghidra/Framework/Docking/src/test/java/docking/FakeDockingTool.java index e62cbb8b2a..2d5703fb6d 100644 --- a/Ghidra/Framework/Docking/src/test/java/docking/FakeDockingTool.java +++ b/Ghidra/Framework/Docking/src/test/java/docking/FakeDockingTool.java @@ -78,4 +78,9 @@ public class FakeDockingTool extends AbstractDockingTool { public void removeServiceListener(ServiceListener listener) { // stub } + + @Override + public ActionContext getGlobalActionContext() { + return null; + } } diff --git a/Ghidra/Framework/Project/src/main/java/ghidra/framework/plugintool/PluginTool.java b/Ghidra/Framework/Project/src/main/java/ghidra/framework/plugintool/PluginTool.java index f4576ad477..773542856c 100644 --- a/Ghidra/Framework/Project/src/main/java/ghidra/framework/plugintool/PluginTool.java +++ b/Ghidra/Framework/Project/src/main/java/ghidra/framework/plugintool/PluginTool.java @@ -1471,6 +1471,11 @@ public abstract class PluginTool extends AbstractDockingTool { winMgr.removePreferenceState(name); } + @Override + public ActionContext getGlobalActionContext() { + return winMgr.getGlobalActionContext(); + } + //================================================================================================== // Inner Classes //==================================================================================================