mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2026-10-22 18:22:23 -09:00
Merge remote-tracking branch 'origin/GP-2386-dragonmacher-plugin-package-refactor--SQUASHED'
This commit is contained in:
@@ -45,7 +45,7 @@ import ghidra.dbg.*;
|
||||
import ghidra.dbg.target.*;
|
||||
import ghidra.dbg.util.PathUtils;
|
||||
import ghidra.framework.main.AppInfo;
|
||||
import ghidra.framework.main.FrontEndOnly;
|
||||
import ghidra.framework.main.ApplicationLevelOnlyPlugin;
|
||||
import ghidra.framework.options.SaveState;
|
||||
import ghidra.framework.plugintool.*;
|
||||
import ghidra.framework.plugintool.util.PluginStatus;
|
||||
@@ -71,7 +71,7 @@ import ghidra.util.datastruct.ListenerSet;
|
||||
servicesProvided = {
|
||||
DebuggerModelService.class, })
|
||||
public class DebuggerModelServicePlugin extends Plugin
|
||||
implements DebuggerModelServiceInternal, FrontEndOnly {
|
||||
implements DebuggerModelServiceInternal, ApplicationLevelOnlyPlugin {
|
||||
|
||||
private static final String PREFIX_FACTORY = "Factory_";
|
||||
|
||||
|
||||
@@ -31,7 +31,7 @@ import ghidra.app.plugin.core.debug.event.TraceOpenedPluginEvent;
|
||||
import ghidra.app.plugin.core.debug.gui.DebuggerResources;
|
||||
import ghidra.app.services.*;
|
||||
import ghidra.dbg.DebuggerObjectModel;
|
||||
import ghidra.framework.main.FrontEndOnly;
|
||||
import ghidra.framework.main.ApplicationLevelOnlyPlugin;
|
||||
import ghidra.framework.main.FrontEndTool;
|
||||
import ghidra.framework.options.*;
|
||||
import ghidra.framework.plugintool.*;
|
||||
@@ -55,7 +55,7 @@ import ghidra.util.datastruct.CollectionChangeListener;
|
||||
} //
|
||||
)
|
||||
public class DebuggerWorkflowServicePlugin extends Plugin
|
||||
implements DebuggerWorkflowService, FrontEndOnly, OptionsChangeListener {
|
||||
implements DebuggerWorkflowService, ApplicationLevelOnlyPlugin, OptionsChangeListener {
|
||||
|
||||
protected class ForBotsModelsChangeListener
|
||||
implements CollectionChangeListener<DebuggerObjectModel> {
|
||||
|
||||
@@ -49,7 +49,7 @@ import ghidra.util.task.*;
|
||||
description = "The archive plugin provides a menu action from the project window allowing the user to archive a project or restore an archived project. "
|
||||
)
|
||||
//@formatter:on
|
||||
public class ArchivePlugin extends Plugin implements FrontEndOnly, ProjectListener {
|
||||
public class ArchivePlugin extends Plugin implements ApplicationLevelOnlyPlugin, ProjectListener {
|
||||
|
||||
private static final String PROJECT_GROUP_C_2 = "CProject2";
|
||||
|
||||
|
||||
@@ -19,7 +19,7 @@ import java.io.File;
|
||||
|
||||
import ghidra.app.CorePluginPackage;
|
||||
import ghidra.app.plugin.PluginCategoryNames;
|
||||
import ghidra.framework.main.FrontEndOnly;
|
||||
import ghidra.framework.main.ApplicationLevelOnlyPlugin;
|
||||
import ghidra.framework.options.OptionType;
|
||||
import ghidra.framework.options.ToolOptions;
|
||||
import ghidra.framework.plugintool.*;
|
||||
@@ -38,7 +38,7 @@ import ghidra.util.HelpLocation;
|
||||
description = "Options Eclipse Integration"
|
||||
)
|
||||
//@formatter:on
|
||||
public class EclipseIntegrationOptionsPlugin extends Plugin implements FrontEndOnly {
|
||||
public class EclipseIntegrationOptionsPlugin extends Plugin implements ApplicationLevelOnlyPlugin {
|
||||
|
||||
public static final String PLUGIN_OPTIONS_NAME = "Eclipse Integration";
|
||||
|
||||
|
||||
@@ -24,7 +24,7 @@ import ghidra.app.context.NavigatableActionContext;
|
||||
import ghidra.app.context.NavigatableContextAction;
|
||||
import ghidra.app.plugin.PluginCategoryNames;
|
||||
import ghidra.app.services.CodeViewerService;
|
||||
import ghidra.framework.main.FrontEndable;
|
||||
import ghidra.framework.main.ApplicationLevelPlugin;
|
||||
import ghidra.framework.main.datatable.ProjectDataContext;
|
||||
import ghidra.framework.main.datatable.FrontendProjectTreeAction;
|
||||
import ghidra.framework.model.DomainFile;
|
||||
@@ -44,7 +44,7 @@ import ghidra.util.HelpLocation;
|
||||
description = "This plugin exports a program or datatype archive to an external file."
|
||||
)
|
||||
//@formatter:on
|
||||
public class ExporterPlugin extends Plugin implements FrontEndable {
|
||||
public class ExporterPlugin extends Plugin implements ApplicationLevelPlugin {
|
||||
|
||||
public ExporterPlugin(PluginTool tool) {
|
||||
super(tool);
|
||||
|
||||
@@ -28,7 +28,7 @@ import ghidra.app.plugin.PluginCategoryNames;
|
||||
import ghidra.app.util.GenericHelpTopics;
|
||||
import ghidra.app.util.HelpTopics;
|
||||
import ghidra.framework.main.FrontEndTool;
|
||||
import ghidra.framework.main.FrontEndable;
|
||||
import ghidra.framework.main.ApplicationLevelPlugin;
|
||||
import ghidra.framework.main.datatable.FrontendProjectTreeAction;
|
||||
import ghidra.framework.main.datatable.ProjectDataContext;
|
||||
import ghidra.framework.model.DomainFile;
|
||||
@@ -50,7 +50,7 @@ import ghidra.util.HelpLocation;
|
||||
description = "This plugin provides an action that displays information about the currently loaded program"
|
||||
)
|
||||
//@formatter:on
|
||||
public class AboutProgramPlugin extends Plugin implements FrontEndable {
|
||||
public class AboutProgramPlugin extends Plugin implements ApplicationLevelPlugin {
|
||||
public final static String PLUGIN_NAME = "AboutProgramPlugin";
|
||||
public final static String ACTION_NAME = "About Program";
|
||||
|
||||
|
||||
@@ -34,7 +34,7 @@ import docking.widgets.table.GTable;
|
||||
import ghidra.app.CorePluginPackage;
|
||||
import ghidra.app.plugin.PluginCategoryNames;
|
||||
import ghidra.app.util.HelpTopics;
|
||||
import ghidra.framework.main.FrontEndable;
|
||||
import ghidra.framework.main.ApplicationLevelPlugin;
|
||||
import ghidra.framework.plugintool.*;
|
||||
import ghidra.framework.plugintool.util.PluginStatus;
|
||||
import ghidra.program.model.lang.*;
|
||||
@@ -51,7 +51,7 @@ import ghidra.util.SystemUtilities;
|
||||
description = "This plugin provides a Help action that displays a list of installed processor modules"
|
||||
)
|
||||
//@formatter:on
|
||||
public class ProcessorListPlugin extends Plugin implements FrontEndable {
|
||||
public class ProcessorListPlugin extends Plugin implements ApplicationLevelPlugin {
|
||||
|
||||
private DockingAction processorListAction;
|
||||
|
||||
|
||||
@@ -24,7 +24,7 @@ import javax.swing.Timer;
|
||||
|
||||
import ghidra.app.CorePluginPackage;
|
||||
import ghidra.app.plugin.PluginCategoryNames;
|
||||
import ghidra.framework.main.FrontEndOnly;
|
||||
import ghidra.framework.main.ApplicationLevelOnlyPlugin;
|
||||
import ghidra.framework.main.FrontEndTool;
|
||||
import ghidra.framework.model.*;
|
||||
import ghidra.framework.options.OptionsChangeListener;
|
||||
@@ -49,7 +49,7 @@ import ghidra.util.exception.AssertException;
|
||||
)
|
||||
//@formatter:on
|
||||
public class RecoverySnapshotMgrPlugin extends Plugin
|
||||
implements FrontEndOnly, OptionsChangeListener, ProjectListener {
|
||||
implements ApplicationLevelOnlyPlugin, OptionsChangeListener, ProjectListener {
|
||||
|
||||
private final static String OPTIONS_TITLE = "Recovery";
|
||||
private final static String SNAPSHOT_PERIOD_OPTION = "Snapshot period (minutes, 0=disabled)";
|
||||
|
||||
@@ -27,7 +27,7 @@ import docking.widgets.OptionDialog;
|
||||
import ghidra.app.CorePluginPackage;
|
||||
import ghidra.app.plugin.PluginCategoryNames;
|
||||
import ghidra.framework.main.FrontEndTool;
|
||||
import ghidra.framework.main.FrontEndable;
|
||||
import ghidra.framework.main.ApplicationLevelPlugin;
|
||||
import ghidra.framework.main.datatable.ProjectDataContext;
|
||||
import ghidra.framework.model.*;
|
||||
import ghidra.framework.plugintool.*;
|
||||
@@ -52,7 +52,7 @@ import ghidra.util.task.*;
|
||||
description = "This plugin provides the set language feature."
|
||||
)
|
||||
//@formatter:on
|
||||
public final class LanguageProviderPlugin extends Plugin implements FrontEndable {
|
||||
public final class LanguageProviderPlugin extends Plugin implements ApplicationLevelPlugin {
|
||||
|
||||
private DockingAction setLanguageAction;
|
||||
|
||||
|
||||
@@ -26,7 +26,7 @@ import docking.action.MenuData;
|
||||
import docking.tool.ToolConstants;
|
||||
import ghidra.app.CorePluginPackage;
|
||||
import ghidra.app.plugin.PluginCategoryNames;
|
||||
import ghidra.framework.main.FrontEndOnly;
|
||||
import ghidra.framework.main.ApplicationLevelOnlyPlugin;
|
||||
import ghidra.framework.plugintool.*;
|
||||
import ghidra.framework.plugintool.util.PluginStatus;
|
||||
import ghidra.framework.preferences.Preferences;
|
||||
@@ -43,7 +43,7 @@ import utilities.util.FileUtilities;
|
||||
description = "Display a dialog containing 'Tips of the Day'."
|
||||
)
|
||||
//@formatter:on
|
||||
public class TipOfTheDayPlugin extends Plugin implements FrontEndOnly {
|
||||
public class TipOfTheDayPlugin extends Plugin implements ApplicationLevelOnlyPlugin {
|
||||
private static final String TIP_INDEX = "TIP_INDEX";
|
||||
private static final String SHOW_TIPS = "SHOW_TIPS";
|
||||
|
||||
|
||||
@@ -17,7 +17,7 @@ package ghidra.app.plugin.debug;
|
||||
|
||||
import ghidra.app.DeveloperPluginPackage;
|
||||
import ghidra.app.plugin.PluginCategoryNames;
|
||||
import ghidra.framework.main.FrontEndOnly;
|
||||
import ghidra.framework.main.ApplicationLevelOnlyPlugin;
|
||||
import ghidra.framework.main.FrontEndService;
|
||||
import ghidra.framework.model.*;
|
||||
import ghidra.framework.plugintool.*;
|
||||
@@ -34,7 +34,7 @@ import ghidra.framework.plugintool.util.PluginStatus;
|
||||
)
|
||||
//@formatter:on
|
||||
public class DomainFolderChangesDisplayPlugin extends Plugin
|
||||
implements FrontEndOnly, ProjectListener, DomainFolderChangeListener {
|
||||
implements ApplicationLevelOnlyPlugin, ProjectListener, DomainFolderChangeListener {
|
||||
|
||||
private DomainFolderChangesDisplayComponentProvider provider;
|
||||
|
||||
|
||||
@@ -40,7 +40,7 @@ import ghidra.app.DeveloperPluginPackage;
|
||||
import ghidra.app.plugin.PluginCategoryNames;
|
||||
import ghidra.app.util.bean.SelectLanguagePanel;
|
||||
import ghidra.framework.Application;
|
||||
import ghidra.framework.main.FrontEndable;
|
||||
import ghidra.framework.main.ApplicationLevelPlugin;
|
||||
import ghidra.framework.plugintool.*;
|
||||
import ghidra.framework.plugintool.util.PluginStatus;
|
||||
import ghidra.program.model.address.AddressSpace;
|
||||
@@ -64,7 +64,7 @@ import ghidra.util.xml.GenericXMLOutputter;
|
||||
"language which will modify its address spaces or register definitions."
|
||||
)
|
||||
//@formatter:on
|
||||
public class GenerateOldLanguagePlugin extends Plugin implements FrontEndable {
|
||||
public class GenerateOldLanguagePlugin extends Plugin implements ApplicationLevelPlugin {
|
||||
|
||||
private static final ExtensionFileFilter OLD_LANG_FILTER =
|
||||
new ExtensionFileFilter("lang", "Old Language File");
|
||||
|
||||
@@ -30,7 +30,7 @@ import docking.help.*;
|
||||
import docking.tool.ToolConstants;
|
||||
import ghidra.app.DeveloperPluginPackage;
|
||||
import ghidra.app.plugin.PluginCategoryNames;
|
||||
import ghidra.framework.main.FrontEndable;
|
||||
import ghidra.framework.main.ApplicationLevelPlugin;
|
||||
import ghidra.framework.model.Project;
|
||||
import ghidra.framework.plugintool.*;
|
||||
import ghidra.framework.plugintool.util.PluginStatus;
|
||||
@@ -52,7 +52,7 @@ import ghidra.util.task.*;
|
||||
JavaHelpPlugin.infoName + ", is written to your home directory."
|
||||
)
|
||||
//@formatter:on
|
||||
public class JavaHelpPlugin extends Plugin implements FrontEndable {
|
||||
public class JavaHelpPlugin extends Plugin implements ApplicationLevelPlugin {
|
||||
|
||||
static final String infoName = "GhidraHelpInfo.txt";
|
||||
|
||||
|
||||
@@ -25,7 +25,7 @@ import docking.widgets.OptionDialog;
|
||||
import ghidra.app.CorePluginPackage;
|
||||
import ghidra.app.plugin.PluginCategoryNames;
|
||||
import ghidra.docking.util.DockingWindowsLookAndFeelUtils;
|
||||
import ghidra.framework.main.FrontEndOnly;
|
||||
import ghidra.framework.main.ApplicationLevelOnlyPlugin;
|
||||
import ghidra.framework.main.FrontEndTool;
|
||||
import ghidra.framework.options.*;
|
||||
import ghidra.framework.plugintool.*;
|
||||
@@ -44,7 +44,7 @@ import ghidra.util.*;
|
||||
"only in the Ghidra Project Window."
|
||||
)
|
||||
//@formatter:on
|
||||
public class LookAndFeelPlugin extends Plugin implements FrontEndOnly, OptionsChangeListener {
|
||||
public class LookAndFeelPlugin extends Plugin implements ApplicationLevelOnlyPlugin, OptionsChangeListener {
|
||||
|
||||
private String selectedLookAndFeel;
|
||||
private boolean useInvertedColors;
|
||||
|
||||
@@ -73,7 +73,7 @@ import ghidra.util.task.TaskLauncher;
|
||||
)
|
||||
//@formatter:on
|
||||
public class ImporterPlugin extends Plugin
|
||||
implements FileImporterService, FrontEndable, ProjectListener {
|
||||
implements FileImporterService, ApplicationLevelPlugin, ProjectListener {
|
||||
|
||||
private static final String IMPORT_MENU_GROUP = "Import";
|
||||
static final String IMPORTER_PLUGIN_DESC =
|
||||
|
||||
@@ -38,7 +38,7 @@ import ghidra.app.services.*;
|
||||
import ghidra.app.util.opinion.LoaderService;
|
||||
import ghidra.formats.gfilesystem.*;
|
||||
import ghidra.framework.main.FrontEndService;
|
||||
import ghidra.framework.main.FrontEndable;
|
||||
import ghidra.framework.main.ApplicationLevelPlugin;
|
||||
import ghidra.framework.model.Project;
|
||||
import ghidra.framework.model.ProjectListener;
|
||||
import ghidra.framework.plugintool.*;
|
||||
@@ -70,7 +70,7 @@ import utilities.util.FileUtilities;
|
||||
eventsConsumed = { ProgramActivatedPluginEvent.class }
|
||||
)
|
||||
//@formatter:on
|
||||
public class FileSystemBrowserPlugin extends Plugin implements FrontEndable, ProjectListener,
|
||||
public class FileSystemBrowserPlugin extends Plugin implements ApplicationLevelPlugin, ProjectListener,
|
||||
FileSystemBrowserService {
|
||||
|
||||
/* package */ DockingAction openFilesystemAction;
|
||||
|
||||
@@ -67,11 +67,11 @@ public class ManageFrontEndToolTest extends AbstractGhidraHeadedIntegrationTest
|
||||
int count = 0;
|
||||
List<PluginDescription> allPluginDescriptions = pluginModel.getAllPluginDescriptions();
|
||||
for (PluginDescription pluginDescription : allPluginDescriptions) {
|
||||
assertTrue(FrontEndable.class.isAssignableFrom(pluginDescription.getPluginClass()));
|
||||
assertTrue(ApplicationLevelPlugin.class.isAssignableFrom(pluginDescription.getPluginClass()));
|
||||
count++;
|
||||
}
|
||||
|
||||
List<Class<? extends FrontEndable>> classes = ClassSearcher.getClasses(FrontEndable.class);
|
||||
List<Class<? extends ApplicationLevelPlugin>> classes = ClassSearcher.getClasses(ApplicationLevelPlugin.class);
|
||||
assertEquals(count, classes.size());
|
||||
}
|
||||
|
||||
|
||||
@@ -38,7 +38,7 @@ import ghidra.file.formats.ios.prelink.MachoPrelinkFileSystem;
|
||||
import ghidra.file.jad.JadProcessWrapper;
|
||||
import ghidra.file.jad.JarDecompiler;
|
||||
import ghidra.formats.gfilesystem.*;
|
||||
import ghidra.framework.main.FrontEndable;
|
||||
import ghidra.framework.main.ApplicationLevelPlugin;
|
||||
import ghidra.framework.plugintool.*;
|
||||
import ghidra.framework.plugintool.util.PluginStatus;
|
||||
import ghidra.plugins.fsbrowser.*;
|
||||
@@ -60,7 +60,7 @@ import ghidra.util.task.TaskMonitor;
|
||||
description = "This plugin provides file format related actions to the File System Browser."
|
||||
)
|
||||
//@formatter:on
|
||||
public class FileFormatsPlugin extends Plugin implements FrontEndable {
|
||||
public class FileFormatsPlugin extends Plugin implements ApplicationLevelPlugin {
|
||||
|
||||
private GhidraFileChooser chooserEclipse;
|
||||
private GhidraFileChooser chooserJarFolder;
|
||||
|
||||
@@ -20,6 +20,7 @@ src/main/java/ghidra/framework/project/tool/package.html||GHIDRA||||END|
|
||||
src/main/resources/images/Minus.png||GHIDRA||||END|
|
||||
src/main/resources/images/Plus.png||GHIDRA||||END|
|
||||
src/main/resources/images/allInTool.gif||GHIDRA||reviewed||END|
|
||||
src/main/resources/images/applications-development-web.png||Oxygen Icons - LGPL 3.0|||Oxygen icon theme (dual license; LGPL or CC-SA-3.0)|END|
|
||||
src/main/resources/images/applications-science.png||Oxygen Icons - LGPL 3.0||||END|
|
||||
src/main/resources/images/bug.png||FAMFAMFAM Icons - CC 2.5|||famfamfam silk icon set|END|
|
||||
src/main/resources/images/check.png||GHIDRA||reviewed||END|
|
||||
|
||||
@@ -15,32 +15,29 @@
|
||||
*/
|
||||
package ghidra.app.plugin.debug;
|
||||
|
||||
import ghidra.app.CorePluginPackage;
|
||||
import ghidra.app.plugin.PluginCategoryNames;
|
||||
import ghidra.framework.main.FrontEndOnly;
|
||||
import ghidra.framework.plugintool.*;
|
||||
import ghidra.framework.plugintool.util.PluginStatus;
|
||||
import ghidra.util.HelpLocation;
|
||||
import docking.ActionContext;
|
||||
import docking.DialogComponentProvider;
|
||||
import docking.action.DockingAction;
|
||||
import docking.action.MenuData;
|
||||
import ghidra.app.plugin.PluginCategoryNames;
|
||||
import ghidra.framework.main.ApplicationLevelOnlyPlugin;
|
||||
import ghidra.framework.main.UtilityPluginPackage;
|
||||
import ghidra.framework.plugintool.*;
|
||||
import ghidra.framework.plugintool.util.PluginStatus;
|
||||
import ghidra.util.HelpLocation;
|
||||
|
||||
//@formatter:off
|
||||
@PluginInfo(
|
||||
status = PluginStatus.RELEASED,
|
||||
packageName = CorePluginPackage.NAME,
|
||||
packageName = UtilityPluginPackage.NAME,
|
||||
category = PluginCategoryNames.SUPPORT,
|
||||
shortDescription = "VM Memory Display",
|
||||
description = "Plugin for displaying the VM memory information."
|
||||
)
|
||||
//@formatter:on
|
||||
public class MemoryUsagePlugin extends Plugin implements FrontEndOnly {
|
||||
public class MemoryUsagePlugin extends Plugin implements ApplicationLevelOnlyPlugin {
|
||||
private DialogComponentProvider dialog;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*/
|
||||
public MemoryUsagePlugin(PluginTool tool) {
|
||||
|
||||
super(tool);
|
||||
@@ -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,10 +15,10 @@
|
||||
*/
|
||||
package ghidra.framework.main;
|
||||
|
||||
|
||||
/**
|
||||
* Marker interface to indicate plugin is for Front-end use only.
|
||||
* Marker interface to indicate this plugin is application-level tools only (see
|
||||
* {@link ApplicationLevelPlugin}).
|
||||
*/
|
||||
public interface FrontEndOnly extends FrontEndable {
|
||||
|
||||
public interface ApplicationLevelOnlyPlugin extends ApplicationLevelPlugin {
|
||||
// marker interface
|
||||
}
|
||||
@@ -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.
|
||||
@@ -17,10 +16,12 @@
|
||||
package ghidra.framework.main;
|
||||
|
||||
/**
|
||||
* Marker that allows a plugin to be added <i>directly</i> to the Ghidra Project
|
||||
* Window by the user.
|
||||
* Some plugins may get added due to dependencies by FrontEndable
|
||||
* plugins.
|
||||
* Marker that signals the implementing plugin can be added to the system at the application level.
|
||||
* <p>
|
||||
* Some applications have only a single tool while other applications may have multiple tools, with
|
||||
* a top-level tool that manages other sub-tools. A plugin implementing this interface can be used
|
||||
* in any of these tools.
|
||||
*/
|
||||
public interface FrontEndable {
|
||||
public interface ApplicationLevelPlugin {
|
||||
// marker interface
|
||||
}
|
||||
@@ -27,6 +27,7 @@ import java.util.Set;
|
||||
import javax.swing.JFrame;
|
||||
import javax.swing.JPanel;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.jdom.Element;
|
||||
import org.jdom.JDOMException;
|
||||
import org.jdom.input.SAXBuilder;
|
||||
@@ -108,8 +109,11 @@ public class FrontEndTool extends PluginTool implements OptionsChangeListener {
|
||||
private final static String GHIDRA_MAIN_PANEL_DIVIDER_LOC = "GhidraMainPanelDividerLocation";
|
||||
|
||||
private static final String FRONT_END_TOOL_XML_NAME = "FRONTEND";
|
||||
private static final String VERSION_ATTRIBUTE_NAME = "VERSION";
|
||||
private static final String FRONT_END_FILE_NAME = "FrontEndTool.xml";
|
||||
private static final String CONFIGURE_GROUP = "Configure";
|
||||
private static final File TOOL_FILE =
|
||||
new File(Application.getUserSettingsDirectory(), FRONT_END_FILE_NAME);
|
||||
|
||||
private WeakSet<ProjectListener> listeners;
|
||||
private FrontEndPlugin plugin;
|
||||
@@ -123,7 +127,7 @@ public class FrontEndTool extends PluginTool implements OptionsChangeListener {
|
||||
|
||||
/**
|
||||
* Construct a new Ghidra Project Window.
|
||||
*
|
||||
*
|
||||
* @param pm project manager
|
||||
*/
|
||||
public FrontEndTool(ProjectManager pm) {
|
||||
@@ -132,7 +136,7 @@ public class FrontEndTool extends PluginTool implements OptionsChangeListener {
|
||||
|
||||
listeners = WeakDataStructureFactory.createCopyOnWriteWeakSet();
|
||||
|
||||
addFrontEndPlugin();
|
||||
installFrontEndPlugins();
|
||||
createActions();
|
||||
loadToolConfigurationFromDisk();
|
||||
|
||||
@@ -164,7 +168,7 @@ public class FrontEndTool extends PluginTool implements OptionsChangeListener {
|
||||
@Override
|
||||
public PluginClassManager getPluginClassManager() {
|
||||
if (pluginClassManager == null) {
|
||||
pluginClassManager = new PluginClassManager(FrontEndable.class, null);
|
||||
pluginClassManager = new PluginClassManager(ApplicationLevelPlugin.class, null);
|
||||
}
|
||||
return pluginClassManager;
|
||||
}
|
||||
@@ -174,46 +178,97 @@ public class FrontEndTool extends PluginTool implements OptionsChangeListener {
|
||||
}
|
||||
|
||||
private void loadToolConfigurationFromDisk() {
|
||||
File saveFile = new File(Application.getUserSettingsDirectory(), FRONT_END_FILE_NAME);
|
||||
if (!saveFile.exists()) {
|
||||
addFrontEndablePlugins();
|
||||
|
||||
Element root = getToolFileXml();
|
||||
if (root == null) {
|
||||
installDefaultApplicationLevelPlugins();
|
||||
return;
|
||||
}
|
||||
try {
|
||||
InputStream is = new FileInputStream(saveFile);
|
||||
SAXBuilder sax = XmlUtilities.createSecureSAXBuilder(false, false);
|
||||
|
||||
Element root = sax.build(is).getRootElement();
|
||||
GhidraToolTemplate template = new GhidraToolTemplate(
|
||||
(Element) root.getChildren().get(0), saveFile.getAbsolutePath());
|
||||
refresh(template);
|
||||
GhidraToolTemplate template = new GhidraToolTemplate((Element) root.getChildren().get(0),
|
||||
TOOL_FILE.getAbsolutePath());
|
||||
refresh(template);
|
||||
}
|
||||
|
||||
private Element getToolFileXml() {
|
||||
if (!TOOL_FILE.exists()) {
|
||||
return null;
|
||||
}
|
||||
catch (JDOMException e) {
|
||||
Msg.showError(this, null, "Error", "Error in XML reading front end configuration", e);
|
||||
|
||||
try (InputStream is = new FileInputStream(TOOL_FILE)) {
|
||||
SAXBuilder sax = XmlUtilities.createSecureSAXBuilder(false, false);
|
||||
return sax.build(is).getRootElement();
|
||||
}
|
||||
catch (IOException e) {
|
||||
catch (IOException | JDOMException e) {
|
||||
Msg.showError(this, null, "Error", "Error reading front end configuration", e);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
void saveToolConfigurationToDisk() {
|
||||
ToolTemplate template = saveToolToToolTemplate();
|
||||
Element root = new Element(FRONT_END_TOOL_XML_NAME);
|
||||
|
||||
String version = Application.getApplicationVersion();
|
||||
root.setAttribute(VERSION_ATTRIBUTE_NAME, version);
|
||||
root.addContent(template.saveToXml());
|
||||
File saveFile = new File(Application.getUserSettingsDirectory(), FRONT_END_FILE_NAME);
|
||||
try {
|
||||
OutputStream os = new FileOutputStream(saveFile);
|
||||
try (OutputStream os = new FileOutputStream(TOOL_FILE)) {
|
||||
org.jdom.Document doc = new org.jdom.Document(root);
|
||||
XMLOutputter xmlOut = new GenericXMLOutputter();
|
||||
xmlOut.output(doc, os);
|
||||
os.close();
|
||||
}
|
||||
catch (IOException e) {
|
||||
Msg.showError(this, null, "Error", "Error saving front end configuration", e);
|
||||
}
|
||||
}
|
||||
|
||||
private void addFrontEndPlugin() {
|
||||
private void installFrontEndPlugins() {
|
||||
installFrontEndPlugin();
|
||||
|
||||
// manually install for old tool versions that have no knowledge of utility plugins
|
||||
if (isPreUtilityGhidraVersion()) {
|
||||
installUtilityPlugins();
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isPreUtilityGhidraVersion() {
|
||||
|
||||
Element root = getToolFileXml();
|
||||
String version = root.getAttributeValue(VERSION_ATTRIBUTE_NAME);
|
||||
|
||||
// Note: any version implies the tool is newer than the addition of the 'version'
|
||||
// attribute. In that case, the utility plugins are managed by the xml.
|
||||
return StringUtils.isBlank(version);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add those plugins that implement the ApplicationLevelPlugin interface and have a
|
||||
* RELEASED status and not (example || testing) category.
|
||||
*/
|
||||
private void installDefaultApplicationLevelPlugins() {
|
||||
List<String> classNames = new ArrayList<>();
|
||||
for (Class<? extends Plugin> pluginClass : ClassSearcher.getClasses(Plugin.class,
|
||||
c -> ApplicationLevelPlugin.class.isAssignableFrom(c))) {
|
||||
|
||||
PluginDescription pd = PluginDescription.getPluginDescription(pluginClass);
|
||||
String category = pd.getCategory();
|
||||
boolean isBadCategory = category.equals(GenericPluginCategoryNames.EXAMPLES) ||
|
||||
category.equals(GenericPluginCategoryNames.TESTING);
|
||||
if (pd.getStatus() == PluginStatus.RELEASED && !isBadCategory) {
|
||||
classNames.add(pluginClass.getName());
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
addPlugins(classNames);
|
||||
}
|
||||
catch (PluginException e) {
|
||||
Msg.showError(this, getToolFrame(), "Plugin Error", "Error restoring front-end plugins",
|
||||
e);
|
||||
}
|
||||
}
|
||||
|
||||
private void installFrontEndPlugin() {
|
||||
plugin = new FrontEndPlugin(this);
|
||||
plugin.setProjectManager(getProjectManager());
|
||||
try {
|
||||
@@ -280,7 +335,7 @@ public class FrontEndTool extends PluginTool implements OptionsChangeListener {
|
||||
|
||||
/**
|
||||
* Set the active project.
|
||||
*
|
||||
*
|
||||
* @param project may be null if there is no active project
|
||||
*/
|
||||
public void setActiveProject(Project project) {
|
||||
@@ -301,7 +356,7 @@ public class FrontEndTool extends PluginTool implements OptionsChangeListener {
|
||||
|
||||
/**
|
||||
* Add the given project listener.
|
||||
*
|
||||
*
|
||||
* @param l listener to add
|
||||
*/
|
||||
public void addProjectListener(ProjectListener l) {
|
||||
@@ -310,7 +365,7 @@ public class FrontEndTool extends PluginTool implements OptionsChangeListener {
|
||||
|
||||
/**
|
||||
* Remove the given project listener.
|
||||
*
|
||||
*
|
||||
* @param l listener to remove
|
||||
*/
|
||||
public void removeProjectListener(ProjectListener l) {
|
||||
@@ -319,53 +374,54 @@ public class FrontEndTool extends PluginTool implements OptionsChangeListener {
|
||||
|
||||
/**
|
||||
* NOTE: do not call this from a non-Swing thread
|
||||
*
|
||||
*
|
||||
* @param tool the tool
|
||||
* @return true if the repository is null or is connected.
|
||||
*/
|
||||
boolean checkRepositoryConnected(PluginTool tool) {
|
||||
RepositoryAdapter repository = tool.getProject().getRepository();
|
||||
if (repository != null) {
|
||||
if (!repository.verifyConnection()) {
|
||||
if (OptionDialog.showYesNoDialog(tool.getToolFrame(), "Lost Connection to Server",
|
||||
"The connection to the Ghidra Server has been lost.\n" +
|
||||
"Do you want to reconnect now?") == OptionDialog.OPTION_ONE) {
|
||||
try {
|
||||
repository.connect();
|
||||
return true;
|
||||
}
|
||||
catch (NotConnectedException e) {
|
||||
// message displayed by repository server adapter
|
||||
return false;
|
||||
}
|
||||
catch (IOException e) {
|
||||
ClientUtil.handleException(repository, e, "Repository Connection",
|
||||
tool.getToolFrame());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (repository == null) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (repository.verifyConnection()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (OptionDialog.showYesNoDialog(tool.getToolFrame(), "Lost Connection to Server",
|
||||
"The connection to the Ghidra Server has been lost.\n" +
|
||||
"Do you want to reconnect now?") == OptionDialog.OPTION_ONE) {
|
||||
try {
|
||||
repository.connect();
|
||||
return true;
|
||||
}
|
||||
catch (NotConnectedException e) {
|
||||
// message displayed by repository server adapter
|
||||
return false;
|
||||
}
|
||||
catch (IOException e) {
|
||||
ClientUtil.handleException(repository, e, "Repository Connection",
|
||||
tool.getToolFrame());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check in the given domain file.
|
||||
*
|
||||
*
|
||||
* @param tool tool that has the domain file opened
|
||||
* @param domainFile domain file to check in
|
||||
*/
|
||||
public void checkIn(PluginTool tool, DomainFile domainFile) {
|
||||
ArrayList<DomainFile> list = new ArrayList<>();
|
||||
list.add(domainFile);
|
||||
checkIn(tool, list, tool.getToolFrame());
|
||||
checkIn(tool, List.of(domainFile), tool.getToolFrame());
|
||||
}
|
||||
|
||||
/**
|
||||
* Check in the list of domain files.
|
||||
*
|
||||
*
|
||||
* @param tool tool that has the domain files opened
|
||||
* @param fileList list of DomainFile objects
|
||||
* @param parent parent of dialog if an error occurs during checkin
|
||||
@@ -378,8 +434,7 @@ public class FrontEndTool extends PluginTool implements OptionsChangeListener {
|
||||
|
||||
ArrayList<DomainFile> changedList = new ArrayList<>();
|
||||
ArrayList<DomainFile> list = new ArrayList<>();
|
||||
for (int i = 0; i < fileList.size(); i++) {
|
||||
DomainFile df = fileList.get(i);
|
||||
for (DomainFile df : fileList) {
|
||||
if (df != null && df.canCheckin()) {
|
||||
if (!canCloseDomainFile(df)) {
|
||||
continue;
|
||||
@@ -417,7 +472,7 @@ public class FrontEndTool extends PluginTool implements OptionsChangeListener {
|
||||
* Merge the latest version in the repository with the given checked out
|
||||
* domain file. Upon completion of the merge, the domain file appears as
|
||||
* though the latest version was checked out.
|
||||
*
|
||||
*
|
||||
* @param tool tool that has the domain file opened
|
||||
* @param domainFile domain file where latest version will be merged into
|
||||
* @param taskListener listener that is notified when the merge task
|
||||
@@ -433,7 +488,7 @@ public class FrontEndTool extends PluginTool implements OptionsChangeListener {
|
||||
* Merge the latest version (in the repository) of each checked out file in
|
||||
* fileList. Upon completion of the merge, the domain file appears as though
|
||||
* the latest version was checked out.
|
||||
*
|
||||
*
|
||||
* @param tool tool that has the domain files opened
|
||||
* @param fileList list of files that are checked out and are to be merged
|
||||
* @param taskListener listener that is notified when the merge task
|
||||
@@ -447,8 +502,7 @@ public class FrontEndTool extends PluginTool implements OptionsChangeListener {
|
||||
|
||||
ArrayList<DomainFile> list = new ArrayList<>();
|
||||
ArrayList<DomainFile> changedList = new ArrayList<>();
|
||||
for (int i = 0; i < fileList.size(); i++) {
|
||||
DomainFile df = fileList.get(i);
|
||||
for (DomainFile df : fileList) {
|
||||
if (df != null && df.canMerge()) {
|
||||
if (!canCloseDomainFile(df)) {
|
||||
continue;
|
||||
@@ -531,8 +585,8 @@ public class FrontEndTool extends PluginTool implements OptionsChangeListener {
|
||||
menuData.setMenuSubGroup(CONFIGURE_GROUP + 2);
|
||||
installExtensionsAction.setMenuBarData(menuData);
|
||||
|
||||
installExtensionsAction.setHelpLocation(
|
||||
new HelpLocation(GenericHelpTopics.FRONT_END, "Extensions"));
|
||||
installExtensionsAction
|
||||
.setHelpLocation(new HelpLocation(GenericHelpTopics.FRONT_END, "Extensions"));
|
||||
installExtensionsAction.setEnabled(true);
|
||||
addAction(installExtensionsAction);
|
||||
}
|
||||
@@ -558,8 +612,8 @@ public class FrontEndTool extends PluginTool implements OptionsChangeListener {
|
||||
menuData.setMenuSubGroup(CONFIGURE_GROUP + 1);
|
||||
configureToolAction.setMenuBarData(menuData);
|
||||
|
||||
configureToolAction.setHelpLocation(
|
||||
new HelpLocation(GenericHelpTopics.FRONT_END, "Configure"));
|
||||
configureToolAction
|
||||
.setHelpLocation(new HelpLocation(GenericHelpTopics.FRONT_END, "Configure"));
|
||||
configureToolAction.setEnabled(true);
|
||||
addAction(configureToolAction);
|
||||
}
|
||||
@@ -571,11 +625,9 @@ public class FrontEndTool extends PluginTool implements OptionsChangeListener {
|
||||
return toolTemplate;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
|
||||
/**
|
||||
* Get project listeners.
|
||||
*
|
||||
*
|
||||
* @return ProjectListener[]
|
||||
*/
|
||||
Iterable<ProjectListener> getListeners() {
|
||||
@@ -597,50 +649,14 @@ public class FrontEndTool extends PluginTool implements OptionsChangeListener {
|
||||
plugin.readDataState(saveState);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
||||
/**
|
||||
* Add those plugins that implement the FrontEndable interface and have a
|
||||
* RELEASED status and not (example || testing) category.
|
||||
*/
|
||||
private void addFrontEndablePlugins() {
|
||||
List<String> classNames = new ArrayList<>();
|
||||
for (Class<? extends Plugin> pluginClass : ClassSearcher.getClasses(Plugin.class,
|
||||
c -> FrontEndable.class.isAssignableFrom(c))) {
|
||||
|
||||
PluginDescription pd = PluginDescription.getPluginDescription(pluginClass);
|
||||
String category = pd.getCategory();
|
||||
boolean isBadCategory = category.equals(GenericPluginCategoryNames.EXAMPLES) ||
|
||||
category.equals(GenericPluginCategoryNames.TESTING);
|
||||
if (pd.getStatus() == PluginStatus.RELEASED && !isBadCategory) {
|
||||
classNames.add(pluginClass.getName());
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
addPlugins(classNames.toArray(new String[classNames.size()]));
|
||||
}
|
||||
catch (PluginException e) {
|
||||
Msg.showError(this, getToolFrame(), "Plugin Error", "Error restoring front-end plugins",
|
||||
e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Refresh the plugins in the Ghidra Project Window based on what is
|
||||
* contained in the given XML Element.
|
||||
*
|
||||
* @param tc object that contains an entry for each plugin and its
|
||||
* configuration state
|
||||
* Refresh the plugins in the Ghidra Project Window based on what is contained in the given XML
|
||||
* Element.
|
||||
*
|
||||
* @param tc object that contains an entry for each plugin and its configuration state
|
||||
*/
|
||||
private void refresh(ToolTemplate tc) {
|
||||
listeners = WeakDataStructureFactory.createCopyOnWriteWeakSet();
|
||||
List<Plugin> list = getManagedPlugins();
|
||||
list.remove(plugin);
|
||||
Plugin[] plugins = new Plugin[list.size()];
|
||||
plugins = list.toArray(plugins);
|
||||
removePlugins(plugins);
|
||||
|
||||
Element root = tc.saveToXml();
|
||||
Element elem = root.getChild("TOOL");
|
||||
|
||||
@@ -691,7 +707,7 @@ public class FrontEndTool extends PluginTool implements OptionsChangeListener {
|
||||
|
||||
/**
|
||||
* Get the int value for the given string.
|
||||
*
|
||||
*
|
||||
* @param value the string value to parse
|
||||
* @param defaultValue return this value if a NumberFormatException is
|
||||
* thrown during the parseInt() method
|
||||
@@ -866,7 +882,7 @@ public class FrontEndTool extends PluginTool implements OptionsChangeListener {
|
||||
|
||||
/**
|
||||
* Construct a new MergeTask.
|
||||
*
|
||||
*
|
||||
* @param tool tool that has the domain files open
|
||||
* @param list list of DomainFiles to be merged
|
||||
* @param taskListener listener that is notified when this task
|
||||
|
||||
@@ -0,0 +1,29 @@
|
||||
/* ###
|
||||
* 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.framework.main;
|
||||
|
||||
import ghidra.framework.plugintool.util.PluginPackage;
|
||||
import resources.ResourceManager;
|
||||
|
||||
public class UtilityPluginPackage extends PluginPackage {
|
||||
|
||||
public static final String NAME = "Utility";
|
||||
|
||||
public UtilityPluginPackage() {
|
||||
super(NAME, ResourceManager.loadImage("images/applications-development-web.png"),
|
||||
"These plugins provide basic functionality useful to all tools.", UTILITY_PRIORITY);
|
||||
}
|
||||
}
|
||||
@@ -72,7 +72,7 @@ import ghidra.util.classfinder.ExtensionPoint;
|
||||
* {@link PluginTool#getOptions(String)}. (optional)<br>
|
||||
* </OL>
|
||||
* <LI>Other Plugins are constructed, dependencies evaluated, etc.<br>
|
||||
* If your dependencies are not available (ie. not installed, threw an exception during their
|
||||
* If your dependencies are not available (i.e., not installed, threw an exception during their
|
||||
* initialization, etc), your Plugin's {@link #dispose()} will be called and then your Plugin
|
||||
* instance will be discarded.<br>
|
||||
* <LI>Your Plugin's {@link #init()} method is called (when its dependencies are met).
|
||||
@@ -87,8 +87,9 @@ import ghidra.util.classfinder.ExtensionPoint;
|
||||
* <LI>...user uses Ghidra...
|
||||
* <UL>
|
||||
* <LI>Your Plugin's {@link #processEvent(PluginEvent)} is called for events.
|
||||
* <LI>Your Plugin's Action's methods (ie.
|
||||
* {@link DockingAction#actionPerformed(docking.ActionContext) actionPerformed}) are called.
|
||||
* <LI>Your Plugin's Action's methods (i.e.,
|
||||
* {@link DockingAction#actionPerformed(docking.ActionContext) actionPerformed}) are
|
||||
* called.
|
||||
* <LI>Your Plugin's published service methods are called by other Plugins.
|
||||
* <LI>Your Plugin's listener methods are called.
|
||||
* </UL>
|
||||
@@ -113,12 +114,12 @@ import ghidra.util.classfinder.ExtensionPoint;
|
||||
* calls the {@link PluginTool#getService(Class)} method.
|
||||
* <p>
|
||||
* Conversely, any services your Plugin advertises in @PluginInfo must be published via calls to
|
||||
* {@link #registerServiceProvided(Class, Object) registerServiceProvided()} in your Plugin's
|
||||
* {@link #registerServiceProvided(Class, Object) registerServiceProvided()} in your Plugin's
|
||||
* constructor.
|
||||
* <p>
|
||||
* <b>Cyclic dependencies</b> are not allowed and will cause the Plugin management code to fail to
|
||||
* load your Plugin. (ie. PluginA requires a service that PluginB provides, which requires a service
|
||||
* that PluginA provides)
|
||||
* <b>Cyclic dependencies</b> are not allowed and will cause the Plugin management code to fail to
|
||||
* load your Plugin. (i.e., PluginA requires a service that PluginB provides, which requires a
|
||||
* service that PluginA provides)
|
||||
*
|
||||
* <h2>Plugin Service implementation</h2>
|
||||
* A Plugin may provide a service to other Plugins by advertising in its {@link PluginInfo}
|
||||
@@ -161,14 +162,15 @@ import ghidra.util.classfinder.ExtensionPoint;
|
||||
*
|
||||
* <h2>Plugin Events</h2>
|
||||
* <UL>
|
||||
* <LI>Every type of plugin event should be represented by some class extending {@link PluginEvent}.
|
||||
* <LI>One PluginEvent subclass may be used for more than one event type as long as there's some
|
||||
* <LI>Every type of plugin event should be represented by some class extending
|
||||
* {@link PluginEvent}.
|
||||
* <LI>One PluginEvent subclass may be used for more than one event type as long as there's some
|
||||
* natural grouping.
|
||||
* </UL>
|
||||
*
|
||||
* <h2>Component Providers</h2>
|
||||
* <UL>
|
||||
* <LI>A plugin may supply a {@link ComponentProvider} that provides a visual component when
|
||||
* <LI>A plugin may supply a {@link ComponentProvider} that provides a visual component when
|
||||
* the plugin is added to the tool.
|
||||
* </UL>
|
||||
*
|
||||
@@ -176,10 +178,10 @@ import ghidra.util.classfinder.ExtensionPoint;
|
||||
* <UL>
|
||||
* <LI>{@link OptionsChangeListener} - to receive notification when a configuration option
|
||||
* is changed by the user.
|
||||
* <LI>{@link FrontEndable} - marks this Plugin as being suitable for inclusion in the FrontEnd
|
||||
* tool.
|
||||
* <LI>{@link FrontEndOnly} - marks this Plugin as FrontEnd only, not usable in CodeBrowser or
|
||||
* other tools.
|
||||
* <LI>{@link ApplicationLevelPlugin} - marks this Plugin as being suitable for inclusion in the
|
||||
* application-level tool.
|
||||
* <LI>{@link ApplicationLevelOnlyPlugin} - marks this Plugin as application-level only, not
|
||||
* usable in an application's sub-tools.
|
||||
* <LI>{@link ProgramaticUseOnly} - marks this Plugin as special and not for user configuration.
|
||||
* </UL>
|
||||
*
|
||||
@@ -251,7 +253,7 @@ public abstract class Plugin implements ExtensionPoint, PluginEventListener, Ser
|
||||
}
|
||||
|
||||
/**
|
||||
* Auto-registers any services directly implemented by this Plugin instance (ie.
|
||||
* Auto-registers any services directly implemented by this Plugin instance (i.e.,
|
||||
* the MyService in "class MyPlugin extends Plugin implements MyService { }" )
|
||||
*/
|
||||
private void registerPluginImplementedServices() {
|
||||
@@ -377,7 +379,7 @@ public abstract class Plugin implements ExtensionPoint, PluginEventListener, Ser
|
||||
}
|
||||
|
||||
/**
|
||||
* Called after the constructor and before {@link #init()} to publish services to
|
||||
* Called after the constructor and before {@link #init()} to publish services to
|
||||
* the Tool's service registry.
|
||||
* <p>
|
||||
* Services registered during the constructor call will be queued in the services list.
|
||||
@@ -520,7 +522,7 @@ public abstract class Plugin implements ExtensionPoint, PluginEventListener, Ser
|
||||
|
||||
/**
|
||||
* Check if this plugin depends on the given plugin
|
||||
*
|
||||
*
|
||||
* @param plugin the plugin
|
||||
* @return true if this plugin depends on the given plugin
|
||||
*/
|
||||
@@ -836,7 +838,7 @@ public abstract class Plugin implements ExtensionPoint, PluginEventListener, Ser
|
||||
* Close the plugin. This is when the plugin should release resources, such as those from
|
||||
* other services. This method should not close resources being used by others (that should
|
||||
* happen in dispose()).
|
||||
*
|
||||
*
|
||||
* <p>This method will be called before {@link #dispose()}.
|
||||
*/
|
||||
protected void close() {
|
||||
|
||||
@@ -86,7 +86,7 @@ class PluginManager {
|
||||
addPlugins(new Plugin[] { plugin });
|
||||
}
|
||||
|
||||
void addPlugins(List<String> classNames) throws PluginException {
|
||||
void addPlugins(Collection<String> classNames) throws PluginException {
|
||||
PluginException pe = null;
|
||||
List<Plugin> list = new ArrayList<>(classNames.size());
|
||||
List<String> badList = new ArrayList<>();
|
||||
@@ -259,8 +259,8 @@ class PluginManager {
|
||||
|
||||
void restorePluginsFromXml(Element root) throws PluginException {
|
||||
boolean isOld = isOldToolConfig(root);
|
||||
List<String> classNames =
|
||||
isOld ? getPLuginClassNamesFromOldXml(root) : getPluginClassNamesToLoad(root);
|
||||
Collection<String> classNames =
|
||||
isOld ? getPluginClassNamesFromOldXml(root) : getPluginClassNamesToLoad(root);
|
||||
Map<String, SaveState> map = isOld ? getPluginSavedStates(root, "PLUGIN")
|
||||
: getPluginSavedStates(root, "PLUGIN_STATE");
|
||||
|
||||
@@ -295,7 +295,7 @@ class PluginManager {
|
||||
return map;
|
||||
}
|
||||
|
||||
private List<String> getPLuginClassNamesFromOldXml(Element root) {
|
||||
private Set<String> getPluginClassNamesFromOldXml(Element root) {
|
||||
List<String> classNames = new ArrayList<>();
|
||||
List<?> pluginElementList = root.getChildren("PLUGIN");
|
||||
Iterator<?> iter = pluginElementList.iterator();
|
||||
@@ -312,7 +312,7 @@ class PluginManager {
|
||||
return root.getChild("PLUGIN") != null;
|
||||
}
|
||||
|
||||
private List<String> getPluginClassNamesToLoad(Element root) {
|
||||
private Set<String> getPluginClassNamesToLoad(Element root) {
|
||||
PluginClassManager pluginClassManager = tool.getPluginClassManager();
|
||||
return pluginClassManager.getPluginClasses(root);
|
||||
}
|
||||
|
||||
@@ -47,8 +47,7 @@ import ghidra.framework.OperatingSystem;
|
||||
import ghidra.framework.Platform;
|
||||
import ghidra.framework.cmd.BackgroundCommand;
|
||||
import ghidra.framework.cmd.Command;
|
||||
import ghidra.framework.main.AppInfo;
|
||||
import ghidra.framework.main.UserAgreementDialog;
|
||||
import ghidra.framework.main.*;
|
||||
import ghidra.framework.model.*;
|
||||
import ghidra.framework.options.*;
|
||||
import ghidra.framework.plugintool.dialog.ExtensionTableProvider;
|
||||
@@ -226,6 +225,34 @@ public abstract class PluginTool extends AbstractDockingTool {
|
||||
winMgr.setHomeButton(homeIcon, callback);
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads all application-level utility classes into this tool. This should only be called
|
||||
* by tools that represent the global application tool and not for sub-tools.
|
||||
*/
|
||||
protected void installUtilityPlugins() {
|
||||
|
||||
PluginClassManager classManager = getPluginClassManager();
|
||||
PluginPackage utilityPackage = PluginPackage.getPluginPackage(UtilityPluginPackage.NAME);
|
||||
List<PluginDescription> descriptions = classManager.getPluginDescriptions(utilityPackage);
|
||||
|
||||
Set<String> classNames = new HashSet<>();
|
||||
if (descriptions == null) {
|
||||
return;
|
||||
}
|
||||
for (PluginDescription description : descriptions) {
|
||||
String pluginClass = description.getPluginClass().getName();
|
||||
classNames.add(pluginClass);
|
||||
}
|
||||
|
||||
try {
|
||||
addPlugins(classNames);
|
||||
}
|
||||
catch (PluginException e) {
|
||||
Msg.showError(this, null, "Error Adding Utility Plugins",
|
||||
"Unexpected exception adding application utility plugins", e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Placeholder for subclasses to get a chance to install actions before plugins.
|
||||
*
|
||||
@@ -796,9 +823,7 @@ public abstract class PluginTool extends AbstractDockingTool {
|
||||
* class already exists in the tool
|
||||
*/
|
||||
public void addPlugin(String className) throws PluginException {
|
||||
checkedRunSwingNow(() -> {
|
||||
addPlugins(new String[] { className });
|
||||
}, PluginException.class);
|
||||
addPlugins(List.of(className));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -807,37 +832,36 @@ public abstract class PluginTool extends AbstractDockingTool {
|
||||
* @throws PluginException if a plugin could not be constructed, or
|
||||
* there was problem executing its init() method, or if a plugin of this
|
||||
* class already exists in the tool
|
||||
* @deprecated use {@link #addPlugins(List)}
|
||||
* @deprecated use {@link #addPlugins(Collection)}
|
||||
*/
|
||||
@Deprecated(since = "10.2", forRemoval = true)
|
||||
public void addPlugins(String[] classNames) throws PluginException {
|
||||
try {
|
||||
pluginMgr.addPlugins(Arrays.asList(classNames));
|
||||
}
|
||||
finally {
|
||||
setConfigChanged(true);
|
||||
}
|
||||
addPlugins(Arrays.asList(classNames));
|
||||
}
|
||||
|
||||
/**
|
||||
* Add plugins to the tool.
|
||||
* @param classNames array of plugin class names
|
||||
* @param classNames collection of plugin class names
|
||||
* @throws PluginException if a plugin could not be constructed, or
|
||||
* there was problem executing its init() method, or if a plugin of this
|
||||
* class already exists in the tool
|
||||
*/
|
||||
public void addPlugins(List<String> classNames) throws PluginException {
|
||||
try {
|
||||
pluginMgr.addPlugins(classNames);
|
||||
}
|
||||
finally {
|
||||
setConfigChanged(true);
|
||||
}
|
||||
public void addPlugins(Collection<String> classNames) throws PluginException {
|
||||
checkedRunSwingNow(() -> {
|
||||
try {
|
||||
pluginMgr.addPlugins(classNames);
|
||||
}
|
||||
finally {
|
||||
setConfigChanged(true);
|
||||
}
|
||||
}, PluginException.class);
|
||||
}
|
||||
|
||||
public void addPlugin(Plugin p) throws PluginException {
|
||||
pluginMgr.addPlugin(p);
|
||||
setConfigChanged(true);
|
||||
checkedRunSwingNow(() -> {
|
||||
pluginMgr.addPlugin(p);
|
||||
setConfigChanged(true);
|
||||
}, PluginException.class);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -847,14 +871,7 @@ public abstract class PluginTool extends AbstractDockingTool {
|
||||
*/
|
||||
@Deprecated(since = "10.2", forRemoval = true)
|
||||
public void removePlugins(Plugin[] plugins) {
|
||||
SystemUtilities.runSwingNow(() -> {
|
||||
try {
|
||||
pluginMgr.removePlugins(Arrays.asList(plugins));
|
||||
}
|
||||
finally {
|
||||
setConfigChanged(true);
|
||||
}
|
||||
});
|
||||
removePlugins(Arrays.asList(plugins));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -862,7 +879,7 @@ public abstract class PluginTool extends AbstractDockingTool {
|
||||
* @param plugins array of plugins to remove
|
||||
*/
|
||||
public void removePlugins(List<Plugin> plugins) {
|
||||
SystemUtilities.runSwingNow(() -> {
|
||||
Swing.runNow(() -> {
|
||||
try {
|
||||
pluginMgr.removePlugins(plugins);
|
||||
}
|
||||
|
||||
@@ -31,7 +31,7 @@ import docking.framework.*;
|
||||
import ghidra.framework.*;
|
||||
import ghidra.framework.model.ToolServices;
|
||||
import ghidra.util.Msg;
|
||||
import ghidra.util.SystemUtilities;
|
||||
import ghidra.util.Swing;
|
||||
import ghidra.util.classfinder.ClassSearcher;
|
||||
import ghidra.util.exception.CancelledException;
|
||||
import ghidra.util.xml.GenericXMLOutputter;
|
||||
@@ -56,7 +56,7 @@ public abstract class StandAloneApplication implements GenericStandAloneApplicat
|
||||
* {@link ApplicationProperties#APPLICATION_NAME_PROPERTY} and
|
||||
* {@link ApplicationProperties#APPLICATION_VERSION_PROPERTY} properties
|
||||
* set.</b>
|
||||
*
|
||||
*
|
||||
* @param propertiesFilename the name of the properties file.
|
||||
* @throws IOException error causing application initialization failure
|
||||
*/
|
||||
@@ -76,7 +76,7 @@ public abstract class StandAloneApplication implements GenericStandAloneApplicat
|
||||
}
|
||||
|
||||
/**
|
||||
* reates a new application using the given application layout
|
||||
* Creates a new application using the given application layout
|
||||
* and associated application properties.
|
||||
* @param applicationLayout application layout
|
||||
*/
|
||||
@@ -155,7 +155,7 @@ public abstract class StandAloneApplication implements GenericStandAloneApplicat
|
||||
setDockIcon();
|
||||
|
||||
try {
|
||||
SystemUtilities.runSwingNow(() -> tool = createTool());
|
||||
Swing.runNow(() -> tool = createTool());
|
||||
}
|
||||
catch (Exception e) {
|
||||
Msg.error(this, "Error creating tool, exiting...", e);
|
||||
@@ -201,6 +201,7 @@ public abstract class StandAloneApplication implements GenericStandAloneApplicat
|
||||
|
||||
protected void initializeTool(StandAlonePluginTool newTool) {
|
||||
newTool.addExitAction();
|
||||
newTool.installUtilityPlugins();
|
||||
}
|
||||
|
||||
private Element getDefaultToolElement() {
|
||||
|
||||
@@ -33,7 +33,6 @@ public class PluginClassManager {
|
||||
|
||||
public PluginClassManager(Class<?> filterClass, Class<?> exclusionClass) {
|
||||
populatePluginDescriptionMaps(filterClass, exclusionClass);
|
||||
|
||||
}
|
||||
|
||||
public PluginDescription getPluginDescription(String className) {
|
||||
@@ -129,6 +128,7 @@ public class PluginClassManager {
|
||||
PluginPackage pluginPackage = pluginDescription.getPluginPackage();
|
||||
List<Plugin> list = pluginPackageMap.get(pluginPackage);
|
||||
if (list == null) {
|
||||
|
||||
list = new ArrayList<>();
|
||||
pluginPackageMap.put(pluginPackage, list);
|
||||
}
|
||||
@@ -143,7 +143,7 @@ public class PluginClassManager {
|
||||
* @param classNames the list of classNames from from the old XML file
|
||||
* @return the adjusted class names
|
||||
*/
|
||||
public List<String> fillInPackageClasses(List<String> classNames) {
|
||||
public Set<String> fillInPackageClasses(List<String> classNames) {
|
||||
Set<PluginPackage> packages = new HashSet<>();
|
||||
Set<String> adjustedClassNames = new HashSet<>();
|
||||
|
||||
@@ -169,15 +169,19 @@ public class PluginClassManager {
|
||||
}
|
||||
}
|
||||
|
||||
return new ArrayList<>(adjustedClassNames);
|
||||
return adjustedClassNames;
|
||||
}
|
||||
|
||||
public List<String> getPluginClasses(Element element) {
|
||||
List<String> classNames = new ArrayList<>();
|
||||
public Set<String> getPluginClasses(Element element) {
|
||||
|
||||
Set<String> classNames = new HashSet<>();
|
||||
List<?> children = element.getChildren("PACKAGE");
|
||||
for (Object object : children) {
|
||||
|
||||
Element child = (Element) object;
|
||||
String packageName = child.getAttributeValue("NAME");
|
||||
|
||||
// classes excluded by name in the xml
|
||||
Set<String> excludedClasses = new HashSet<>();
|
||||
List<?> grandChildren = child.getChildren("EXCLUDE");
|
||||
for (Object obj : grandChildren) {
|
||||
@@ -185,6 +189,8 @@ public class PluginClassManager {
|
||||
String excludedClassName = grandChild.getAttributeValue("CLASS");
|
||||
excludedClasses.add(excludedClassName);
|
||||
}
|
||||
|
||||
// classes included by name in the xml
|
||||
Set<String> includedClasses = new HashSet<>();
|
||||
grandChildren = child.getChildren("INCLUDE");
|
||||
for (Object obj : grandChildren) {
|
||||
@@ -193,27 +199,34 @@ public class PluginClassManager {
|
||||
includedClasses.add(excludedClassName);
|
||||
}
|
||||
|
||||
String packageName = child.getAttributeValue("NAME");
|
||||
PluginPackage pluginPackage = PluginPackage.getPluginPackage(packageName);
|
||||
List<PluginDescription> pluginDescriptionList = packageMap.get(pluginPackage);
|
||||
if (pluginDescriptionList == null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
for (PluginDescription pluginDescription : pluginDescriptionList) {
|
||||
String pluginClass = pluginDescription.getPluginClass().getName();
|
||||
if (pluginDescription.getStatus() == PluginStatus.RELEASED) {
|
||||
if (!excludedClasses.contains(pluginClass)) {
|
||||
classNames.add(pluginClass);
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (includedClasses.contains(pluginClass)) {
|
||||
classNames.add(pluginClass);
|
||||
}
|
||||
if (shouldAddPlugin(pluginDescription, includedClasses, excludedClasses)) {
|
||||
classNames.add(pluginDescription.getPluginClass().getName());
|
||||
}
|
||||
}
|
||||
}
|
||||
return classNames;
|
||||
|
||||
}
|
||||
|
||||
private boolean shouldAddPlugin(PluginDescription description, Set<String> include,
|
||||
Set<String> exclude) {
|
||||
|
||||
String className = description.getPluginClass().getName();
|
||||
if (include.contains(className)) {
|
||||
return true;
|
||||
}
|
||||
if (exclude.contains(className)) {
|
||||
return false;
|
||||
}
|
||||
return description.getStatus() == PluginStatus.RELEASED;
|
||||
|
||||
}
|
||||
|
||||
public List<PluginPackage> getPluginPackages() {
|
||||
|
||||
@@ -25,7 +25,8 @@ import ghidra.util.classfinder.ClassSearcher;
|
||||
import ghidra.util.classfinder.ExtensionPoint;
|
||||
|
||||
public abstract class PluginPackage implements ExtensionPoint, Comparable<PluginPackage> {
|
||||
public static final int CORE_PRIORITY = 0;
|
||||
public static final int UTILITY_PRIORITY = 0;
|
||||
public static final int CORE_PRIORITY = 1;
|
||||
public static final int FEATURE_PRIORITY = 4;
|
||||
public static final int MISCELLANIOUS_PRIORITY = 6;
|
||||
public static final int DEVELOPER_PRIORITY = 8;
|
||||
|
||||
@@ -28,7 +28,7 @@ import docking.action.MenuData;
|
||||
import docking.tool.ToolConstants;
|
||||
import docking.widgets.OptionDialog;
|
||||
import ghidra.app.util.FileOpenDropHandler;
|
||||
import ghidra.framework.main.FrontEndOnly;
|
||||
import ghidra.framework.main.ApplicationLevelOnlyPlugin;
|
||||
import ghidra.framework.model.Project;
|
||||
import ghidra.framework.model.ToolTemplate;
|
||||
import ghidra.framework.options.PreferenceState;
|
||||
@@ -101,7 +101,7 @@ public class GhidraTool extends PluginTool {
|
||||
@Override
|
||||
public PluginClassManager getPluginClassManager() {
|
||||
if (pluginClassManager == null) {
|
||||
pluginClassManager = new PluginClassManager(Plugin.class, FrontEndOnly.class);
|
||||
pluginClassManager = new PluginClassManager(Plugin.class, ApplicationLevelOnlyPlugin.class);
|
||||
}
|
||||
return pluginClassManager;
|
||||
}
|
||||
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 3.2 KiB |
Reference in New Issue
Block a user