Merge remote-tracking branch 'origin/GP-3080_ghidra1_DefaultToolOpen--SQUASHED'

This commit is contained in:
Ryan Kurtz
2023-02-13 15:05:23 -05:00
12 changed files with 117 additions and 108 deletions
@@ -359,7 +359,11 @@
<LI>To open a file in the tool that was <A href=
"help/topics/Tool/Ghidra_Tool_Administration.htm#Set_Tool_Associations">specified as the
"default,"</A> double click on the Program that you want to open, OR right mouse click on
the file and choose <B>Open in Default Tool.</B></LI>
the file and choose <B>Open in Default Tool.</B> Either a new tool will be launched
or an existing running tool will be reused based upon the Tool option setting (see
<A href="help/topics/Tool/ToolOptions_Dialog.htm#Front_End_Tool_Options">
Front-End Tool Options</A>.
</LI>
</UL>
<H4><A name="Open_File_With"></A>Open a File With a Specific Tool</H4>
@@ -413,6 +413,15 @@
startup.</TD>
</TR>
<TR>
<TD valign="top" width="200" align="left">Default Tool Launch Mode</TD>
<TD valign="top" align="left">This controls
if a new or already running tool should be used during default launch.
Tool "reuse" mode will open selected file within a suitable running tool
if one can be identified, otherwise a new tool will be launched.
</TD>
</TR>
<TR>
<TD valign="top" width="200" align="left"><A name="Use_Inverted_Colors"></A>Use
@@ -316,18 +316,7 @@ public final class LanguageProviderPlugin extends Plugin implements ApplicationL
try {
SwingUtilities.invokeAndWait(() -> {
ToolServices toolServices = tool.getToolServices();
ToolTemplate defaultToolTemplate = toolServices.getDefaultToolTemplate(file);
if (defaultToolTemplate != null) {
String defaultToolName = defaultToolTemplate.getName();
for (PluginTool t : toolServices.getRunningTools()) {
if (t.getName().equals(defaultToolName)) {
openTool = t;
break;
}
}
}
if (openTool == null ||
!openTool.acceptDomainFiles(new DomainFile[] { file })) {
if (toolServices.launchDefaultTool(domainFile) == null) {
Msg.showError(this, tool.getToolFrame(), "Failed to Open Program",
"A suitable default tool could not found!");
}
@@ -185,8 +185,8 @@ public interface ContentHandler<T extends DomainObjectAdapter> extends Extension
Icon getIcon();
/**
* Returns the name of the default tool that should be used to open this content type.
* @return associated default tool for this content type
* Returns the name of the default tool/template that should be used to open this content type.
* @return associated default tool name for this content type
*/
String getDefaultToolName();
@@ -1102,14 +1102,9 @@ public class FrontEndPlugin extends Plugin
}
Project project = tool.getProject();
final ToolServices toolServices = project.getToolServices();
ToolTemplate defaultToolTemplate = toolServices.getDefaultToolTemplate(domainFile);
if (defaultToolTemplate != null) {
ToolButton button = toolBar.getToolButtonForToolConfig(defaultToolTemplate);
if (button != null) {
button.launchTool(domainFile);
return;
}
ToolServices toolServices = project.getToolServices();
if (toolServices.launchDefaultTool(domainFile) != null) {
return;
}
Msg.showInfo(this, tool.getToolFrame(), "Cannot Find Tool",
@@ -87,6 +87,7 @@ import help.HelpService;
* manner.
*/
public class FrontEndTool extends PluginTool implements OptionsChangeListener {
public static final String DEFAULT_TOOL_LAUNCH_MODE = "Default Tool Launch Mode";
public static final String AUTOMATICALLY_SAVE_TOOLS = "Automatically Save Tools";
private static final String USE_ALERT_ANIMATION_OPTION_NAME = "Use Notification Animation";
@@ -122,6 +123,8 @@ public class FrontEndTool extends PluginTool implements OptionsChangeListener {
private WeakSet<ProjectListener> listeners;
private FrontEndPlugin plugin;
private DefaultLaunchMode defaultLaunchMode = DefaultLaunchMode.DEFAULT;
private ComponentProvider compProvider;
private LogComponentProvider logProvider;
@@ -315,11 +318,21 @@ public class FrontEndTool extends PluginTool implements OptionsChangeListener {
showComponentHeader(compProvider, false);
}
/**
* Get the preferred default tool launch mode
* @return default tool launch mode
*/
public DefaultLaunchMode getDefaultLaunchMode() {
return defaultLaunchMode;
}
private void initFrontEndOptions() {
ToolOptions options = getOptions(ToolConstants.TOOL_OPTIONS);
HelpLocation help =
new HelpLocation(ToolConstants.TOOL_HELP_TOPIC, "Front_End_Tool_Options");
options.registerOption(DEFAULT_TOOL_LAUNCH_MODE, DefaultLaunchMode.DEFAULT, help,
"Indicates if a new or already running tool should be used during default launch.");
options.registerOption(AUTOMATICALLY_SAVE_TOOLS, true, help,
"When enabled tools will be saved when they are closed");
options.registerOption(USE_ALERT_ANIMATION_OPTION_NAME, true, help,
@@ -332,6 +345,8 @@ public class FrontEndTool extends PluginTool implements OptionsChangeListener {
options.registerOption(RESTORE_PREVIOUS_PROJECT_NAME, Boolean.TRUE, help,
"Restore the previous project when Ghidra starts.");
defaultLaunchMode = options.getEnum(DEFAULT_TOOL_LAUNCH_MODE, defaultLaunchMode);
boolean autoSave = options.getBoolean(AUTOMATICALLY_SAVE_TOOLS, true);
GhidraTool.autoSave = autoSave;
@@ -350,6 +365,9 @@ public class FrontEndTool extends PluginTool implements OptionsChangeListener {
@Override
public void optionsChanged(ToolOptions options, String optionName, Object oldValue,
Object newValue) {
if (DEFAULT_TOOL_LAUNCH_MODE.equals(optionName)) {
defaultLaunchMode = (DefaultLaunchMode) newValue;
}
if (AUTOMATICALLY_SAVE_TOOLS.equals(optionName)) {
GhidraTool.autoSave = (Boolean) newValue;
}
@@ -67,7 +67,6 @@ class ToolButton extends EmptyBorderButton implements Draggable, Droppable {
private ToolTemplate template;
private PluginTool associatedRunningTool;
private DefaultToolChangeListener toolChangeListener;
private ToolServices toolServices;
/**
@@ -132,8 +131,6 @@ class ToolButton extends EmptyBorderButton implements Draggable, Droppable {
}
if (!isRunningTool()) {
toolChangeListener = new ToolChangeListener(template);
toolServices.addDefaultToolChangeListener(toolChangeListener);
setIcon(generateIcon());
}
}
@@ -503,8 +500,6 @@ class ToolButton extends EmptyBorderButton implements Draggable, Droppable {
}
void dispose() {
toolServices.removeDefaultToolChangeListener(toolChangeListener);
plugin = null;
template = null;
associatedRunningTool = null;
@@ -679,22 +674,6 @@ class ToolButton extends EmptyBorderButton implements Draggable, Droppable {
// Inner Classes
//==================================================================================================
private class ToolChangeListener implements DefaultToolChangeListener {
private final ToolTemplate toolTemplate;
public ToolChangeListener(ToolTemplate toolTemplate) {
this.toolTemplate = toolTemplate;
}
@Override
public void defaultToolChanged(String oldName, String newName) {
String myName = toolTemplate.getName();
if (myName.equals(oldName) || myName.equals(newName)) {
setIcon(generateIcon());
}
}
}
private class ToolButtonDropTgtAdapter extends DropTgtAdapter {
private boolean draggingOverValidDropTarget = false;
@@ -21,8 +21,8 @@ import java.util.List;
import docking.action.KeyBindingData;
import docking.action.MenuData;
import ghidra.framework.main.AppInfo;
import ghidra.framework.main.datatable.ProjectDataContext;
import ghidra.framework.main.datatable.FrontendProjectTreeAction;
import ghidra.framework.main.datatable.ProjectDataContext;
import ghidra.framework.model.DomainFile;
public class ProjectDataOpenDefaultToolAction extends FrontendProjectTreeAction {
@@ -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,15 +15,28 @@
*/
package ghidra.framework.model;
/**
* Listener that is notified when the default tool specification changes.
*/
public interface DefaultToolChangeListener {
import ghidra.framework.options.Options;
/**
* {@link DefaultLaunchMode} provides an {@link Options} value which indicates how a default tool
* launch should be performed.
*/
public enum DefaultLaunchMode {
REUSE_TOOL("Reuse acceptable running tool"),
NEW_TOOL("Launch new default tool");
public static DefaultLaunchMode DEFAULT = NEW_TOOL;
private String str;
private DefaultLaunchMode(String str) {
this.str = str;
}
@Override
public String toString() {
return str;
}
/**
* Notification that the default tool specification changed
* @param oldName name of the old default tool
* @param newName name of the new default tool
*/
void defaultToolChanged(String oldName, String newName);
}
@@ -119,6 +119,7 @@ public interface ToolServices {
/**
* Launch the default tool and open the specified domainFile.
* NOTE: running tool re-use is implementation dependent
* @param domainFile the file to open
* @return the launched tool. Null returned if a suitable default tool
* for the file content type was not found.
@@ -136,7 +137,8 @@ public interface ToolServices {
/**
* Launch the default tool and open the specified Ghidra URL resource.
* The tool choosen well be based upon the content type of the specified resource.
* The tool choosen will be based upon the content type of the specified resource.
* NOTE: running tool re-use is implementation dependent
* @param ghidraUrl resource to be opened (see {@link GhidraURL})
* @return the launched tool. Null returned if a failure occurs while accessing the specified
* resource or a suitable default tool for the file content type was not found.
@@ -155,18 +157,6 @@ public interface ToolServices {
*/
public PluginTool launchToolWithURL(String toolName, URL ghidraUrl);
/**
* Add a listener that will be notified when the default tool specification changes
* @param listener the listener
*/
public void addDefaultToolChangeListener(DefaultToolChangeListener listener);
/**
* Remove the listener
* @param listener the listener
*/
public void removeDefaultToolChangeListener(DefaultToolChangeListener listener);
/**
* Return array of running tools
* @return array of Tools
@@ -23,10 +23,6 @@ import ghidra.framework.model.*;
public class ToolServicesAdapter implements ToolServices {
@Override
public void addDefaultToolChangeListener(DefaultToolChangeListener listener) {
}
@Override
public boolean canAutoSave(PluginTool tool) {
return true;
@@ -97,11 +93,6 @@ public class ToolServicesAdapter implements ToolServices {
return null;
}
@Override
public void removeDefaultToolChangeListener(DefaultToolChangeListener listener) {
// override
}
@Override
public void saveTool(PluginTool tool) {
// override
@@ -18,6 +18,7 @@ package ghidra.framework.project.tool;
import java.io.*;
import java.net.URL;
import java.util.*;
import java.util.function.Function;
import org.jdom.Document;
import org.jdom.output.XMLOutputter;
@@ -26,6 +27,8 @@ import docking.widgets.OptionDialog;
import docking.widgets.filechooser.GhidraFileChooser;
import ghidra.framework.ToolUtils;
import ghidra.framework.data.*;
import ghidra.framework.main.AppInfo;
import ghidra.framework.main.FrontEndTool;
import ghidra.framework.model.*;
import ghidra.framework.plugintool.PluginEvent;
import ghidra.framework.plugintool.PluginTool;
@@ -49,7 +52,6 @@ class ToolServicesImpl implements ToolServices {
private ToolChest toolChest;
private ToolManagerImpl toolManager;
private List<DefaultToolChangeListener> listeners = new ArrayList<>();
private ToolChestChangeListener toolChestChangeListener;
private Set<ContentHandler<?>> contentHandlers;
@@ -187,22 +189,60 @@ class ToolServicesImpl implements ToolServices {
matchingTool.firePluginEvent(event);
}
@Override
public PluginTool launchDefaultTool(DomainFile domainFile) {
ToolTemplate template = getDefaultToolTemplate(domainFile);
if (template == null) {
return null;
private static DefaultLaunchMode getDefaultLaunchMode() {
DefaultLaunchMode defaultLaunchMode = DefaultLaunchMode.DEFAULT;
FrontEndTool frontEndTool = AppInfo.getFrontEndTool();
if (frontEndTool != null) {
defaultLaunchMode = frontEndTool.getDefaultLaunchMode();
}
return defaultLaunchMode;
}
private PluginTool defaultLaunch(ToolTemplate template,
Function<PluginTool, Boolean> openFunction) {
DefaultLaunchMode defaultLaunchMode = getDefaultLaunchMode();
if (defaultLaunchMode == DefaultLaunchMode.REUSE_TOOL) {
if (template != null) {
// attempt to reuse running tool with default name
String defaultToolName = template.getName();
for (PluginTool tool : getRunningTools()) {
if (tool.getName().equals(defaultToolName) && openFunction.apply(tool)) {
return tool;
}
}
}
// attempt to reuse any running tool
for (PluginTool tool : getRunningTools()) {
if (openFunction.apply(tool)) {
return tool;
}
}
}
if (template == null) {
return null; // unable to launch new tool
}
Workspace workspace = toolManager.getActiveWorkspace();
PluginTool tool = workspace.runTool(template);
if (tool == null) {
return null;
return null; // tool launch failed
}
tool.setVisible(true);
tool.acceptDomainFiles(new DomainFile[] { domainFile });
openFunction.apply(tool);
return tool;
}
@Override
public PluginTool launchDefaultTool(DomainFile domainFile) {
ToolTemplate template = getDefaultToolTemplate(domainFile);
return defaultLaunch(template, t -> {
return t.acceptDomainFiles(new DomainFile[] { domainFile });
});
}
@Override
public PluginTool launchTool(String toolName, DomainFile domainFile) {
ToolTemplate template = findToolChestToolTemplate(toolName);
@@ -228,17 +268,9 @@ class ToolServicesImpl implements ToolServices {
return null;
}
ToolTemplate template = getDefaultToolTemplate(contentType);
if (template == null) {
return null;
}
Workspace workspace = toolManager.getActiveWorkspace();
PluginTool tool = workspace.runTool(template);
if (tool == null) {
return null;
}
tool.setVisible(true);
tool.accept(ghidraUrl);
return tool;
return defaultLaunch(template, t -> {
return t.accept(ghidraUrl);
});
}
@Override
@@ -475,16 +507,6 @@ class ToolServicesImpl implements ToolServices {
return contentHandlers;
}
@Override
public void addDefaultToolChangeListener(DefaultToolChangeListener listener) {
listeners.add(listener);
}
@Override
public void removeDefaultToolChangeListener(DefaultToolChangeListener listener) {
listeners.remove(listener);
}
private GhidraToolTemplate findToolChestToolTemplate(String toolName) {
if (toolName != null) {
return (GhidraToolTemplate) toolChest.getToolTemplate(toolName);