Merge remote-tracking branch 'origin/GP-2386-dragonmacher-plugin-package-refactor--SQUASHED'

This commit is contained in:
Ryan Kurtz
2022-08-05 12:17:49 -04:00
33 changed files with 315 additions and 238 deletions

View File

@@ -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_";

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View 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";

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

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,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
}

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

View File

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

View File

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

View File

@@ -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 &#64;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() {

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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