mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2025-10-05 19:42:36 +02:00
GP-1764 - Plugins - tweaked help
This commit is contained in:
parent
82c42e648c
commit
924bf7656e
30 changed files with 1200 additions and 496 deletions
|
@ -0,0 +1,63 @@
|
|||
/* ###
|
||||
* 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.plugintool;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import ghidra.framework.plugintool.util.*;
|
||||
|
||||
/**
|
||||
* The default plugin package provider that uses the {@link PluginClassManager} to supply packages
|
||||
*/
|
||||
public class DeafultPluginPackagingProvider implements PluginPackagingProvider {
|
||||
|
||||
private PluginClassManager pluginClassManager;
|
||||
|
||||
DeafultPluginPackagingProvider(PluginClassManager pluginClassManager) {
|
||||
this.pluginClassManager = pluginClassManager;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<PluginPackage> getPluginPackages() {
|
||||
return pluginClassManager.getPluginPackages();
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<PluginDescription> getPluginDescriptions() {
|
||||
return pluginClassManager.getManagedPluginDescriptions();
|
||||
}
|
||||
|
||||
@Override
|
||||
public PluginDescription getPluginDescription(String pluginClassName) {
|
||||
return pluginClassManager.getPluginDescription(pluginClassName);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<PluginDescription> getPluginDescriptions(PluginPackage pluginPackage) {
|
||||
return pluginClassManager.getPluginDescriptions(pluginPackage);
|
||||
}
|
||||
|
||||
@Override
|
||||
public PluginPackage getUnstablePluginPackage() {
|
||||
return UNSTABLE_PACKAGE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<PluginDescription> getUnstablePluginDescriptions() {
|
||||
return pluginClassManager.getUnstablePluginDescriptions();
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,47 @@
|
|||
/* ###
|
||||
* 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.plugintool;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import ghidra.framework.plugintool.util.PluginException;
|
||||
|
||||
/**
|
||||
* The default plugin installer that uses a tool to install plugins
|
||||
*/
|
||||
public class DefaultPluginInstaller implements PluginInstaller {
|
||||
|
||||
private PluginTool tool;
|
||||
|
||||
DefaultPluginInstaller(PluginTool tool) {
|
||||
this.tool = tool;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Plugin> getManagedPlugins() {
|
||||
return tool.getManagedPlugins();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addPlugins(List<String> pluginClassNames) throws PluginException {
|
||||
tool.addPlugins(pluginClassNames);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removePlugins(List<Plugin> plugins) {
|
||||
tool.removePlugins(plugins);
|
||||
}
|
||||
}
|
|
@ -17,63 +17,54 @@ package ghidra.framework.plugintool;
|
|||
|
||||
import java.util.*;
|
||||
|
||||
import javax.swing.Icon;
|
||||
import javax.swing.event.ChangeListener;
|
||||
|
||||
import docking.action.DockingActionIf;
|
||||
import docking.actions.KeyBindingUtils;
|
||||
import ghidra.framework.plugintool.util.*;
|
||||
import ghidra.util.Msg;
|
||||
import resources.ResourceManager;
|
||||
import utility.function.Callback;
|
||||
import utility.function.Dummy;
|
||||
|
||||
public class PluginConfigurationModel {
|
||||
private static Icon EXPERIMENTAL_ICON =
|
||||
ResourceManager.loadImage("images/applications-science.png");
|
||||
private final ChangeListener listener;
|
||||
private final PluginTool tool;
|
||||
private PluginClassManager pluginClassManager;
|
||||
|
||||
private final PluginInstaller pluginInstaller;
|
||||
private PluginPackagingProvider pluginPackagingProvider;
|
||||
private Callback listener = Callback.dummy();
|
||||
private Map<PluginDescription, Plugin> loadedPluginMap = new HashMap<>();
|
||||
private Set<PluginDescription> pluginsWithDependenciesSet = new HashSet<>();
|
||||
private List<PluginDescription> unStablePluginDescriptions;
|
||||
private PluginPackage unstablePackage;
|
||||
|
||||
public PluginConfigurationModel(PluginTool tool) {
|
||||
this(tool, e -> {
|
||||
// dummy listener
|
||||
});
|
||||
this(new DefaultPluginInstaller(tool),
|
||||
new DeafultPluginPackagingProvider(tool.getPluginClassManager()));
|
||||
}
|
||||
|
||||
public PluginConfigurationModel(PluginTool tool, ChangeListener listener) {
|
||||
this.tool = tool;
|
||||
this.listener = listener;
|
||||
pluginClassManager = tool.getPluginClassManager();
|
||||
public PluginConfigurationModel(PluginInstaller pluginInstaller,
|
||||
PluginPackagingProvider pluginPackagingProvider) {
|
||||
|
||||
this.pluginInstaller = pluginInstaller;
|
||||
this.pluginPackagingProvider = pluginPackagingProvider;
|
||||
initLoadedPlugins();
|
||||
unStablePluginDescriptions = pluginClassManager.getNonReleasedPluginDescriptions();
|
||||
if (!unStablePluginDescriptions.isEmpty()) {
|
||||
unstablePackage = new PluginPackage("Experimental", EXPERIMENTAL_ICON,
|
||||
"This package contains plugins that are not fully tested and/or documented." +
|
||||
"You must add these plugins individually. Adding these plugins could cause the tool" +
|
||||
" to become unstable.",
|
||||
Integer.MAX_VALUE) {
|
||||
@Override
|
||||
public boolean isfullyAddable() {
|
||||
return false;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
unstablePackage = pluginPackagingProvider.getUnstablePluginPackage();
|
||||
unStablePluginDescriptions = pluginPackagingProvider.getUnstablePluginDescriptions();
|
||||
}
|
||||
|
||||
public void setChangeCallback(Callback listener) {
|
||||
this.listener = Dummy.ifNull(listener);
|
||||
}
|
||||
|
||||
public List<PluginPackage> getPluginPackages() {
|
||||
List<PluginPackage> pluginPackages = pluginClassManager.getPluginPackages();
|
||||
List<PluginPackage> pluginPackages = pluginPackagingProvider.getPluginPackages();
|
||||
List<PluginPackage> packagesWithStablePlugins = new ArrayList<>();
|
||||
for (PluginPackage pluginPackage : pluginPackages) {
|
||||
if (pluginClassManager.getReleasedPluginDescriptions(pluginPackage).size() > 0) {
|
||||
if (pluginPackagingProvider.getPluginDescriptions(pluginPackage).size() > 0) {
|
||||
packagesWithStablePlugins.add(pluginPackage);
|
||||
}
|
||||
}
|
||||
if (unstablePackage != null) {
|
||||
|
||||
if (!unStablePluginDescriptions.isEmpty()) {
|
||||
packagesWithStablePlugins.add(unstablePackage);
|
||||
}
|
||||
|
||||
return packagesWithStablePlugins;
|
||||
}
|
||||
|
||||
|
@ -81,17 +72,17 @@ public class PluginConfigurationModel {
|
|||
if (pluginPackage == unstablePackage) {
|
||||
return unStablePluginDescriptions;
|
||||
}
|
||||
return pluginClassManager.getReleasedPluginDescriptions(pluginPackage);
|
||||
return pluginPackagingProvider.getPluginDescriptions(pluginPackage);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the loaded plugins from the tool and populates the loadedPluginMap and the
|
||||
* pluginsWithDependenciesSet.
|
||||
* Gets the loaded plugins from the tool and populates the loadedPluginMap and the
|
||||
* pluginsWithDependenciesSet.
|
||||
*/
|
||||
private void initLoadedPlugins() {
|
||||
loadedPluginMap.clear();
|
||||
pluginsWithDependenciesSet.clear();
|
||||
List<Plugin> list = tool.getManagedPlugins();
|
||||
List<Plugin> list = pluginInstaller.getManagedPlugins();
|
||||
for (Plugin plugin : list) {
|
||||
loadedPluginMap.put(getPluginDescription(plugin), plugin);
|
||||
findDependencies(plugin, list);
|
||||
|
@ -104,8 +95,7 @@ public class PluginConfigurationModel {
|
|||
* @param plugins the list of all loaded plugins.
|
||||
*/
|
||||
private void findDependencies(Plugin plugin, List<Plugin> plugins) {
|
||||
for (int i = 0; i < plugins.size(); i++) {
|
||||
Plugin p = plugins.get(i);
|
||||
for (Plugin p : plugins) {
|
||||
if (p.dependsUpon(plugin)) {
|
||||
pluginsWithDependenciesSet.add(getPluginDescription(plugin));
|
||||
}
|
||||
|
@ -114,7 +104,7 @@ public class PluginConfigurationModel {
|
|||
|
||||
private PluginDescription getPluginDescription(Plugin plugin) {
|
||||
String className = plugin.getClass().getName();
|
||||
return pluginClassManager.getPluginDescription(className);
|
||||
return pluginPackagingProvider.getPluginDescription(className);
|
||||
}
|
||||
|
||||
public boolean isLoaded(PluginDescription pluginDescription) {
|
||||
|
@ -145,13 +135,14 @@ public class PluginConfigurationModel {
|
|||
|
||||
public void addPlugin(PluginDescription pluginDescription) {
|
||||
try {
|
||||
tool.addPlugin(pluginDescription.getPluginClass().getName());
|
||||
String name = pluginDescription.getPluginClass().getName();
|
||||
pluginInstaller.addPlugins(Arrays.asList(name));
|
||||
}
|
||||
catch (PluginException e) {
|
||||
Msg.showError(this, null, "Error Loading Plugin", e.getMessage(), e);
|
||||
}
|
||||
initLoadedPlugins();
|
||||
listener.stateChanged(null);
|
||||
listener.call();
|
||||
}
|
||||
|
||||
public void removeAllPlugins(PluginPackage pluginPackage) {
|
||||
|
@ -162,37 +153,55 @@ public class PluginConfigurationModel {
|
|||
loadedPlugins.add(loadedPluginMap.get(pluginDescription));
|
||||
}
|
||||
}
|
||||
tool.removePlugins(loadedPlugins.toArray(new Plugin[loadedPlugins.size()]));
|
||||
pluginInstaller.removePlugins(loadedPlugins);
|
||||
initLoadedPlugins();
|
||||
listener.stateChanged(null);
|
||||
listener.call();
|
||||
}
|
||||
|
||||
public void addAllPlugins(PluginPackage pluginPackage) {
|
||||
List<PluginDescription> pluginDescriptions = getPluginDescriptions(pluginPackage);
|
||||
public void addSupportedPlugins(PluginPackage pluginPackage) {
|
||||
|
||||
PluginStatus activationLevel = pluginPackage.getActivationLevel();
|
||||
List<PluginDescription> pluginDescriptions = getPluginDescriptions(pluginPackage);
|
||||
List<String> pluginClasseNames = new ArrayList<>();
|
||||
for (PluginDescription pluginDescription : pluginDescriptions) {
|
||||
|
||||
PluginStatus status = pluginDescription.getStatus();
|
||||
if (status.compareTo(activationLevel) > 0) {
|
||||
continue; // status is not good enough to be activated (e.g., UNSTABLE)
|
||||
}
|
||||
|
||||
if (!isLoaded(pluginDescription)) {
|
||||
pluginClasseNames.add(pluginDescription.getPluginClass().getName());
|
||||
}
|
||||
}
|
||||
try {
|
||||
tool.addPlugins(pluginClasseNames.toArray(new String[pluginClasseNames.size()]));
|
||||
pluginInstaller.addPlugins(pluginClasseNames);
|
||||
}
|
||||
catch (PluginException e) {
|
||||
Msg.showError(this, null, "Error Loading Plugin(s) ", e.getMessage(), e);
|
||||
}
|
||||
initLoadedPlugins();
|
||||
listener.stateChanged(null);
|
||||
listener.call();
|
||||
}
|
||||
|
||||
public boolean hasOnlyUnstablePlugins(PluginPackage pluginPackage) {
|
||||
List<PluginDescription> pluginDescriptions = getPluginDescriptions(pluginPackage);
|
||||
for (PluginDescription pluginDescription : pluginDescriptions) {
|
||||
PluginStatus status = pluginDescription.getStatus();
|
||||
if (status.compareTo(PluginStatus.UNSTABLE) < 0) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public void removePlugin(PluginDescription pluginDescription) {
|
||||
Plugin plugin = loadedPluginMap.get(pluginDescription);
|
||||
if (plugin != null) {
|
||||
tool.removePlugins(new Plugin[] { plugin });
|
||||
pluginInstaller.removePlugins(Arrays.asList(plugin));
|
||||
}
|
||||
initLoadedPlugins();
|
||||
listener.stateChanged(null);
|
||||
listener.call();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -207,28 +216,15 @@ public class PluginConfigurationModel {
|
|||
}
|
||||
|
||||
/**
|
||||
* Returns all of the actions loaded by the Plugin represented by the given PluginDescription.
|
||||
* An empty list will be returned if no actions are loaded or if the plugin has not been
|
||||
* loaded.
|
||||
* @param pluginDescription The description for which to find loaded actions.
|
||||
* @return all of the actions loaded by the Plugin represented by the given PluginDescription.
|
||||
*/
|
||||
public Set<DockingActionIf> getActionsForPlugin(PluginDescription pluginDescription) {
|
||||
if (!isLoaded(pluginDescription)) {
|
||||
return Collections.emptySet();
|
||||
}
|
||||
|
||||
return KeyBindingUtils.getKeyBindingActionsForOwner(tool, pluginDescription.getName());
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the names of the plugins that are dependent on some service
|
||||
* that the plugin corresponding to the given PluginDescription provides.
|
||||
* Return the descriptions of the plugins that are dependent on some service that the plugin
|
||||
* corresponding to the given PluginDescription provides.
|
||||
*
|
||||
* @param pd PluginDescription of the plugin
|
||||
* @return the descriptions
|
||||
*/
|
||||
public List<PluginDescription> getDependencies(PluginDescription pd) {
|
||||
Plugin plugin = loadedPluginMap.get(pd);
|
||||
return (plugin != null) ? getDependencies(plugin, tool.getManagedPlugins())
|
||||
return (plugin != null) ? getDependencies(plugin, pluginInstaller.getManagedPlugins())
|
||||
: Collections.emptyList();
|
||||
}
|
||||
|
||||
|
@ -236,8 +232,7 @@ public class PluginConfigurationModel {
|
|||
HashSet<PluginDescription> set = new HashSet<>();
|
||||
|
||||
// find out all plugins that depend on this plugin
|
||||
for (int i = 0; i < plugins.size(); i++) {
|
||||
Plugin p = plugins.get(i);
|
||||
for (Plugin p : plugins) {
|
||||
if (p.dependsUpon(plugin)) {
|
||||
set.add(p.getPluginDescription());
|
||||
}
|
||||
|
@ -246,7 +241,6 @@ public class PluginConfigurationModel {
|
|||
}
|
||||
|
||||
public List<PluginDescription> getAllPluginDescriptions() {
|
||||
return pluginClassManager.getAllPluginDescriptions();
|
||||
return pluginPackagingProvider.getPluginDescriptions();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -0,0 +1,45 @@
|
|||
/* ###
|
||||
* 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.plugintool;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import ghidra.framework.plugintool.util.PluginException;
|
||||
|
||||
/**
|
||||
* An interface that facilitates the adding and removing of plugins
|
||||
*/
|
||||
public interface PluginInstaller {
|
||||
|
||||
/**
|
||||
* Returns all currently installed plugins
|
||||
* @return the plugins
|
||||
*/
|
||||
public List<Plugin> getManagedPlugins();
|
||||
|
||||
/**
|
||||
* Adds the given plugins to the system
|
||||
* @param pluginClassNames the plugin class names to add
|
||||
* @throws PluginException if there is an issue loading any of the plugins
|
||||
*/
|
||||
public void addPlugins(List<String> pluginClassNames) throws PluginException;
|
||||
|
||||
/**
|
||||
* Removes the given plugins from the system
|
||||
* @param plugins the plugins
|
||||
*/
|
||||
public void removePlugins(List<Plugin> plugins);
|
||||
}
|
|
@ -86,9 +86,9 @@ class PluginManager {
|
|||
addPlugins(new Plugin[] { plugin });
|
||||
}
|
||||
|
||||
void addPlugins(String[] classNames) throws PluginException {
|
||||
void addPlugins(List<String> classNames) throws PluginException {
|
||||
PluginException pe = null;
|
||||
List<Plugin> list = new ArrayList<>(classNames.length);
|
||||
List<Plugin> list = new ArrayList<>(classNames.size());
|
||||
List<String> badList = new ArrayList<>();
|
||||
for (String className : classNames) {
|
||||
try {
|
||||
|
@ -115,8 +115,7 @@ class PluginManager {
|
|||
}
|
||||
if (badList.size() > 0) {
|
||||
//EventManager eventMgr = tool.getEventManager
|
||||
for (int i = 0; i < badList.size(); i++) {
|
||||
String className = badList.get(i);
|
||||
for (String className : badList) {
|
||||
// remove from event manager
|
||||
tool.removeEventListener(className);
|
||||
}
|
||||
|
@ -192,7 +191,7 @@ class PluginManager {
|
|||
if (badList.size() > 0) {
|
||||
Plugin[] badPlugins = new Plugin[badList.size()];
|
||||
try {
|
||||
removePlugins(badList.toArray(badPlugins));
|
||||
removePlugins(badList);
|
||||
}
|
||||
catch (Throwable t) {
|
||||
log.debug("Exception unloading plugin", t);
|
||||
|
@ -229,7 +228,7 @@ class PluginManager {
|
|||
* depending on them.
|
||||
* @param plugins the list of plugins to remove.
|
||||
*/
|
||||
void removePlugins(Plugin[] plugins) {
|
||||
void removePlugins(List<Plugin> plugins) {
|
||||
for (Plugin plugin : plugins) {
|
||||
unregisterPlugin(plugin);
|
||||
}
|
||||
|
@ -268,7 +267,7 @@ class PluginManager {
|
|||
|
||||
PluginException pe = null;
|
||||
try {
|
||||
addPlugins(classNames.toArray(new String[classNames.size()]));
|
||||
addPlugins(classNames);
|
||||
}
|
||||
catch (PluginException e) {
|
||||
pe = e;
|
||||
|
@ -367,8 +366,7 @@ class PluginManager {
|
|||
|
||||
Element saveDataStateToXml(boolean savingProject) {
|
||||
Element root = new Element("DATA_STATE");
|
||||
for (int i = 0; i < pluginList.size(); i++) {
|
||||
Plugin p = pluginList.get(i);
|
||||
for (Plugin p : pluginList) {
|
||||
SaveState ss = new SaveState("PLUGIN");
|
||||
p.writeDataState(ss);
|
||||
if (!ss.isEmpty()) {
|
||||
|
@ -518,10 +516,7 @@ class PluginManager {
|
|||
}
|
||||
catch (Exception e) {
|
||||
errMsg.append("Problem restoring plugin state for: " + p.getName()).append("\n\n");
|
||||
errMsg.append(e.getClass().getName())
|
||||
.append(": ")
|
||||
.append(e.getMessage())
|
||||
.append('\n');
|
||||
errMsg.append(e.getClass().getName()).append(": ").append(e.getMessage()).append('\n');
|
||||
StackTraceElement[] st = e.getStackTrace();
|
||||
int depth = Math.min(5, st.length); // only show the important stuff (magic guess)
|
||||
for (int j = 0; j < depth; j++) {
|
||||
|
|
|
@ -0,0 +1,78 @@
|
|||
/* ###
|
||||
* 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.plugintool;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import javax.swing.Icon;
|
||||
|
||||
import ghidra.framework.plugintool.util.*;
|
||||
import resources.ResourceManager;
|
||||
|
||||
/**
|
||||
* Provides {@link PluginPackage}s and plugin descriptions and to clients
|
||||
*/
|
||||
public interface PluginPackagingProvider {
|
||||
|
||||
public static final Icon EXPERIMENTAL_ICON =
|
||||
ResourceManager.loadImage("images/applications-science.png");
|
||||
public static final PluginPackage UNSTABLE_PACKAGE = new PluginPackage("Experimental",
|
||||
EXPERIMENTAL_ICON,
|
||||
"This package contains plugins that are not fully tested and/or documented." +
|
||||
"You must add these plugins individually. Adding these plugins could cause the tool" +
|
||||
" to become unstable.",
|
||||
Integer.MAX_VALUE) {
|
||||
//
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns all known plugin packages
|
||||
* @return the plugin packages
|
||||
*/
|
||||
public List<PluginPackage> getPluginPackages();
|
||||
|
||||
/**
|
||||
* Returns all loaded plugin descriptions
|
||||
* @return the descriptions
|
||||
*/
|
||||
public List<PluginDescription> getPluginDescriptions();
|
||||
|
||||
/**
|
||||
* Returns the plugin description for the given plugin class name
|
||||
* @param pluginClassName the plugin class name
|
||||
* @return the description
|
||||
*/
|
||||
public PluginDescription getPluginDescription(String pluginClassName);
|
||||
|
||||
/**
|
||||
* Get all plugin descriptions for the given plugin package
|
||||
* @param pluginPackage the package
|
||||
* @return the descriptions
|
||||
*/
|
||||
public List<PluginDescription> getPluginDescriptions(PluginPackage pluginPackage);
|
||||
|
||||
/**
|
||||
* Returns the plugin package used to house all unstable plugin packages
|
||||
* @return the package
|
||||
*/
|
||||
public PluginPackage getUnstablePluginPackage();
|
||||
|
||||
/**
|
||||
* Returns all {@link PluginStatus#UNSTABLE} plugin package descriptions
|
||||
* @return the descriptions
|
||||
*/
|
||||
public List<PluginDescription> getUnstablePluginDescriptions();
|
||||
}
|
|
@ -69,7 +69,7 @@ import ghidra.util.task.*;
|
|||
* an alternate method for getting actions to appear in the popup context menu (see
|
||||
* {@link #addPopupActionProvider(PopupActionProvider)}). The popup listener mechanism is generally not
|
||||
* needed and should only be used in special circumstances (see {@link PopupActionProvider}).
|
||||
*
|
||||
*
|
||||
* <p>The PluginTool also manages tasks that run in the background, and options used by the plugins.
|
||||
*
|
||||
*/
|
||||
|
@ -807,8 +807,26 @@ 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(since = "10.2", forRemoval = true)
|
||||
public void addPlugins(String[] classNames) throws PluginException {
|
||||
try {
|
||||
pluginMgr.addPlugins(Arrays.asList(classNames));
|
||||
}
|
||||
finally {
|
||||
setConfigChanged(true);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Add plugins to the tool.
|
||||
* @param classNames array 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);
|
||||
}
|
||||
|
@ -822,15 +840,28 @@ public abstract class PluginTool extends AbstractDockingTool {
|
|||
setConfigChanged(true);
|
||||
}
|
||||
|
||||
public boolean hasUnsavedData() {
|
||||
return pluginMgr.hasUnsavedData();
|
||||
/**
|
||||
* Remove the array of plugins from the tool.
|
||||
* @param plugins array of plugins to remove
|
||||
* @deprecated use {@link #removePlugins(List)}
|
||||
*/
|
||||
@Deprecated(since = "10.2", forRemoval = true)
|
||||
public void removePlugins(Plugin[] plugins) {
|
||||
SystemUtilities.runSwingNow(() -> {
|
||||
try {
|
||||
pluginMgr.removePlugins(Arrays.asList(plugins));
|
||||
}
|
||||
finally {
|
||||
setConfigChanged(true);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the array of plugins from the tool.
|
||||
* @param plugins array of plugins to remove
|
||||
*/
|
||||
public void removePlugins(Plugin[] plugins) {
|
||||
public void removePlugins(List<Plugin> plugins) {
|
||||
SystemUtilities.runSwingNow(() -> {
|
||||
try {
|
||||
pluginMgr.removePlugins(plugins);
|
||||
|
@ -841,6 +872,10 @@ public abstract class PluginTool extends AbstractDockingTool {
|
|||
});
|
||||
}
|
||||
|
||||
public boolean hasUnsavedData() {
|
||||
return pluginMgr.hasUnsavedData();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a list of plugins in the tool
|
||||
* @return list of plugins in the tool
|
||||
|
@ -960,8 +995,8 @@ public abstract class PluginTool extends AbstractDockingTool {
|
|||
saveAsAction.setMenuBarData(menuData);
|
||||
|
||||
saveAsAction.setEnabled(true);
|
||||
saveAsAction.setHelpLocation(
|
||||
new HelpLocation(ToolConstants.TOOL_HELP_TOPIC, "Tool_Changes"));
|
||||
saveAsAction
|
||||
.setHelpLocation(new HelpLocation(ToolConstants.TOOL_HELP_TOPIC, "Tool_Changes"));
|
||||
|
||||
addAction(saveAction);
|
||||
addAction(saveAsAction);
|
||||
|
@ -986,8 +1021,8 @@ public abstract class PluginTool extends AbstractDockingTool {
|
|||
new String[] { ToolConstants.MENU_FILE, exportPullright, "Export Tool..." });
|
||||
menuData.setMenuSubGroup(Integer.toString(subGroup++));
|
||||
exportToolAction.setMenuBarData(menuData);
|
||||
exportToolAction.setHelpLocation(
|
||||
new HelpLocation(ToolConstants.TOOL_HELP_TOPIC, "Export_Tool"));
|
||||
exportToolAction
|
||||
.setHelpLocation(new HelpLocation(ToolConstants.TOOL_HELP_TOPIC, "Export_Tool"));
|
||||
addAction(exportToolAction);
|
||||
|
||||
DockingAction exportDefautToolAction =
|
||||
|
@ -1135,7 +1170,7 @@ public abstract class PluginTool extends AbstractDockingTool {
|
|||
* <br>Note: This forces plugins to terminate any tasks they have running and
|
||||
* apply any unsaved data to domain objects or files. If they can't do
|
||||
* this or the user cancels then this returns false.
|
||||
*
|
||||
*
|
||||
* @param isExiting whether the tool is exiting
|
||||
* @return false if this tool has tasks in progress or can't be closed
|
||||
* since the user has unfinished/unsaved changes.
|
||||
|
@ -1170,7 +1205,7 @@ public abstract class PluginTool extends AbstractDockingTool {
|
|||
* <br>Note: This forces plugins to terminate any tasks they have running for the
|
||||
* indicated domain object and apply any unsaved data to the domain object. If they can't do
|
||||
* this or the user cancels then this returns false.
|
||||
*
|
||||
*
|
||||
* @param domainObject the domain object to check
|
||||
* @return false any of the plugins reports that the domain object
|
||||
* should not be closed
|
||||
|
@ -1361,7 +1396,7 @@ public abstract class PluginTool extends AbstractDockingTool {
|
|||
* time the dialog is shown.
|
||||
*
|
||||
* @param dialogComponent the DialogComponentProvider object to be shown in a dialog.
|
||||
*
|
||||
*
|
||||
* @deprecated dialogs are now always shown over the active window when possible
|
||||
*/
|
||||
@Deprecated
|
||||
|
|
|
@ -19,8 +19,6 @@ import java.awt.Color;
|
|||
import java.awt.Point;
|
||||
|
||||
import javax.swing.*;
|
||||
import javax.swing.event.ChangeEvent;
|
||||
import javax.swing.event.ChangeListener;
|
||||
|
||||
import docking.ActionContext;
|
||||
import docking.DialogComponentProvider;
|
||||
|
@ -29,27 +27,34 @@ import docking.tool.ToolConstants;
|
|||
import docking.widgets.OptionDialog;
|
||||
import ghidra.app.util.GenericHelpTopics;
|
||||
import ghidra.framework.main.AppInfo;
|
||||
import ghidra.framework.plugintool.PluginConfigurationModel;
|
||||
import ghidra.framework.plugintool.PluginTool;
|
||||
import ghidra.framework.plugintool.util.PluginPackage;
|
||||
import ghidra.util.HelpLocation;
|
||||
import ghidra.util.classfinder.ClassSearcher;
|
||||
import resources.ResourceManager;
|
||||
|
||||
public class ManagePluginsDialog extends DialogComponentProvider implements ChangeListener {
|
||||
public class ManagePluginsDialog extends DialogComponentProvider {
|
||||
|
||||
private PluginTool tool;
|
||||
private boolean isNewTool;
|
||||
private DockingAction saveAction;
|
||||
private DockingAction saveAsAction;
|
||||
private DockingAction configureAllPluginsAction;
|
||||
private PluginManagerComponent comp;
|
||||
private PluginManagerComponent pluginComponent;
|
||||
private PluginConfigurationModel pluginConfigurationModel;
|
||||
|
||||
public ManagePluginsDialog(PluginTool tool, boolean addSaveActions, boolean isNewTool) {
|
||||
this(tool, new PluginConfigurationModel(tool), addSaveActions, isNewTool);
|
||||
}
|
||||
|
||||
public ManagePluginsDialog(PluginTool tool, PluginConfigurationModel pluginConfigurationModel,
|
||||
boolean addSaveActions, boolean isNewTool) {
|
||||
super("Configure Tool", false, true, true, true);
|
||||
this.tool = tool;
|
||||
this.isNewTool = isNewTool;
|
||||
ClassSearcher.addChangeListener(this);
|
||||
comp = new PluginManagerComponent(tool);
|
||||
JScrollPane scrollPane = new JScrollPane(comp);
|
||||
this.pluginConfigurationModel = pluginConfigurationModel;
|
||||
pluginComponent = new PluginManagerComponent(tool, pluginConfigurationModel);
|
||||
JScrollPane scrollPane = new JScrollPane(pluginComponent);
|
||||
scrollPane.getViewport().setBackground(Color.white);
|
||||
scrollPane.getViewport().setViewPosition(new Point(0, 0));
|
||||
addWorkPanel(scrollPane);
|
||||
|
@ -90,7 +95,6 @@ public class ManagePluginsDialog extends DialogComponentProvider implements Chan
|
|||
save();
|
||||
}
|
||||
}
|
||||
ClassSearcher.removeChangeListener(this);
|
||||
close();
|
||||
}
|
||||
|
||||
|
@ -99,14 +103,14 @@ public class ManagePluginsDialog extends DialogComponentProvider implements Chan
|
|||
new DockingAction("Configure All Plugins", ToolConstants.TOOL_OWNER) {
|
||||
@Override
|
||||
public void actionPerformed(ActionContext context) {
|
||||
comp.manageAllPlugins();
|
||||
pluginComponent.manageAllPlugins();
|
||||
}
|
||||
};
|
||||
ImageIcon icon = ResourceManager.loadImage("images/plugin.png");
|
||||
configureAllPluginsAction.setToolBarData(new ToolBarData(icon, "aaa"));
|
||||
configureAllPluginsAction.setDescription("Configure All Plugins");
|
||||
configureAllPluginsAction.setHelpLocation(
|
||||
new HelpLocation(GenericHelpTopics.TOOL, "ConfigureAllPlugins"));
|
||||
configureAllPluginsAction
|
||||
.setHelpLocation(new HelpLocation(GenericHelpTopics.TOOL, "ConfigureAllPlugins"));
|
||||
addAction(configureAllPluginsAction);
|
||||
|
||||
if (addSaveActions) {
|
||||
|
@ -133,8 +137,8 @@ public class ManagePluginsDialog extends DialogComponentProvider implements Chan
|
|||
};
|
||||
saveAsAction.setEnabled(true);
|
||||
icon = ResourceManager.loadImage("images/disk_save_as.png");
|
||||
saveAsAction.setMenuBarData(
|
||||
new MenuData(new String[] { "Save As..." }, icon, saveGroup));
|
||||
saveAsAction
|
||||
.setMenuBarData(new MenuData(new String[] { "Save As..." }, icon, saveGroup));
|
||||
saveAsAction.setToolBarData(new ToolBarData(icon, saveGroup));
|
||||
saveAsAction.setHelpLocation(new HelpLocation(GenericHelpTopics.TOOL, "SaveTool"));
|
||||
saveAsAction.setDescription("Save tool to new name in tool chest");
|
||||
|
@ -142,6 +146,10 @@ public class ManagePluginsDialog extends DialogComponentProvider implements Chan
|
|||
}
|
||||
}
|
||||
|
||||
public PluginConfigurationModel getPluginConfigurationModel() {
|
||||
return pluginConfigurationModel;
|
||||
}
|
||||
|
||||
private void save() {
|
||||
if (isNewTool) {
|
||||
saveAs();
|
||||
|
@ -158,15 +166,21 @@ public class ManagePluginsDialog extends DialogComponentProvider implements Chan
|
|||
isNewTool = false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void stateChanged(ChangeEvent e) {
|
||||
//comp.refresh();
|
||||
}
|
||||
|
||||
public void stateChanged() {
|
||||
if (saveAction != null) {
|
||||
saveAction.setEnabled(tool.hasConfigChanged());
|
||||
}
|
||||
}
|
||||
|
||||
int getPackageCount() {
|
||||
return pluginComponent.getPackageCount();
|
||||
}
|
||||
|
||||
int getPluginCount(PluginPackage pluginPackage) {
|
||||
return pluginComponent.getPluginCount(pluginPackage);
|
||||
}
|
||||
|
||||
PluginManagerComponent getPluginComponent() {
|
||||
return pluginComponent;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -27,6 +27,7 @@ import docking.action.DockingActionIf;
|
|||
import docking.action.MenuData;
|
||||
import docking.actions.KeyBindingUtils;
|
||||
import ghidra.framework.plugintool.PluginConfigurationModel;
|
||||
import ghidra.framework.plugintool.PluginTool;
|
||||
import ghidra.framework.plugintool.util.PluginDescription;
|
||||
import ghidra.framework.plugintool.util.PluginStatus;
|
||||
import ghidra.util.HTMLUtilities;
|
||||
|
@ -47,9 +48,11 @@ class PluginDetailsPanel extends AbstractDetailsPanel {
|
|||
private SimpleAttributeSet noValueAttrSet;
|
||||
|
||||
private final PluginConfigurationModel model;
|
||||
private PluginTool tool;
|
||||
|
||||
PluginDetailsPanel(PluginConfigurationModel model) {
|
||||
PluginDetailsPanel(PluginTool tool, PluginConfigurationModel model) {
|
||||
super();
|
||||
this.tool = tool;
|
||||
this.model = model;
|
||||
createFieldAttributes();
|
||||
createMainPanel();
|
||||
|
@ -158,8 +161,13 @@ class PluginDetailsPanel extends AbstractDetailsPanel {
|
|||
insertHTMLLine(buffer, "Loaded Actions:", titleAttrSet);
|
||||
buffer.append("</TD>");
|
||||
|
||||
Set<DockingActionIf> actions = model.getActionsForPlugin(pluginDescription);
|
||||
if (actions.size() == 0) {
|
||||
Set<DockingActionIf> actions = Collections.emptySet();
|
||||
if (model.isLoaded(pluginDescription)) {
|
||||
actions =
|
||||
KeyBindingUtils.getKeyBindingActionsForOwner(tool, pluginDescription.getName());
|
||||
}
|
||||
|
||||
if (actions.isEmpty()) {
|
||||
buffer.append("<TD VALIGN=\"TOP\">");
|
||||
insertHTMLLine(buffer, "No actions for plugin", noValueAttrSet);
|
||||
buffer.append("</TD>");
|
||||
|
|
|
@ -48,22 +48,19 @@ public class PluginInstallerDialog extends DialogComponentProvider {
|
|||
|
||||
/**
|
||||
* Constructs a new provider.
|
||||
*
|
||||
*
|
||||
* @param title the title of the provider
|
||||
* @param tool the current tool
|
||||
* @param model the plugin configuration model
|
||||
* @param pluginDescriptions the list of plugins to display in the dialog
|
||||
*/
|
||||
public PluginInstallerDialog(String title, PluginTool tool,
|
||||
public PluginInstallerDialog(String title, PluginTool tool, PluginConfigurationModel model,
|
||||
List<PluginDescription> pluginDescriptions) {
|
||||
super(title, true, false, true, false);
|
||||
|
||||
this.tool = tool;
|
||||
|
||||
if (model == null) {
|
||||
model = new PluginConfigurationModel(tool);
|
||||
}
|
||||
|
||||
this.pluginDescriptions = pluginDescriptions;
|
||||
this.model = model;
|
||||
|
||||
addWorkPanel(getWorkPanel());
|
||||
addOKButton();
|
||||
|
@ -90,7 +87,7 @@ public class PluginInstallerDialog extends DialogComponentProvider {
|
|||
* Returns the details panel.
|
||||
* <p>
|
||||
* Note: This is primarily for test access
|
||||
*
|
||||
*
|
||||
* @return the details panel
|
||||
*/
|
||||
PluginDetailsPanel getDetailsPanel() {
|
||||
|
@ -101,20 +98,13 @@ public class PluginInstallerDialog extends DialogComponentProvider {
|
|||
* Returns the filter panel.
|
||||
* <p>
|
||||
* Note: This is primarily for test access
|
||||
*
|
||||
*
|
||||
* @return the filter panel
|
||||
*/
|
||||
GTableFilterPanel<PluginDescription> getFilterPanel() {
|
||||
return tableFilterPanel;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the plugin configuration model.
|
||||
* <p>
|
||||
* Note: This is primarily for test access
|
||||
*
|
||||
* @return the plugin configuration model
|
||||
*/
|
||||
PluginConfigurationModel getModel() {
|
||||
return model;
|
||||
}
|
||||
|
@ -127,7 +117,7 @@ public class PluginInstallerDialog extends DialogComponentProvider {
|
|||
JPanel mainPanel = new JPanel();
|
||||
mainPanel.setLayout(new BorderLayout());
|
||||
|
||||
detailsPanel = new PluginDetailsPanel(model);
|
||||
detailsPanel = new PluginDetailsPanel(tool, model);
|
||||
JPanel pluginTablePanel = createPluginTablePanel(detailsPanel);
|
||||
|
||||
final JSplitPane splitPane =
|
||||
|
@ -174,12 +164,10 @@ public class PluginInstallerDialog extends DialogComponentProvider {
|
|||
|
||||
table.getColumnModel()
|
||||
.getColumn(PluginInstallerTableModel.NAME_COL)
|
||||
.setCellRenderer(
|
||||
new NameCellRenderer());
|
||||
.setCellRenderer(new NameCellRenderer());
|
||||
table.getColumnModel()
|
||||
.getColumn(PluginInstallerTableModel.STATUS_COL)
|
||||
.setCellRenderer(
|
||||
new StatusCellRenderer());
|
||||
.setCellRenderer(new StatusCellRenderer());
|
||||
|
||||
HelpService help = Help.getHelpService();
|
||||
help.registerHelp(table, new HelpLocation(GenericHelpTopics.TOOL, "PluginDialog"));
|
||||
|
@ -237,7 +225,7 @@ public class PluginInstallerDialog extends DialogComponentProvider {
|
|||
}
|
||||
|
||||
/**
|
||||
* Renderer for the plugin name column.
|
||||
* Renderer for the plugin name column.
|
||||
*/
|
||||
private class NameCellRenderer extends GTableCellRenderer {
|
||||
|
||||
|
|
|
@ -20,8 +20,6 @@ import java.util.ArrayList;
|
|||
import java.util.List;
|
||||
|
||||
import javax.swing.*;
|
||||
import javax.swing.event.ChangeEvent;
|
||||
import javax.swing.event.ChangeListener;
|
||||
import javax.swing.event.HyperlinkEvent.EventType;
|
||||
|
||||
import docking.EmptyBorderToggleButton;
|
||||
|
@ -30,24 +28,26 @@ import docking.widgets.checkbox.GCheckBox;
|
|||
import docking.widgets.label.*;
|
||||
import ghidra.framework.plugintool.PluginConfigurationModel;
|
||||
import ghidra.framework.plugintool.PluginTool;
|
||||
import ghidra.framework.plugintool.util.PluginPackage;
|
||||
import ghidra.framework.plugintool.util.PluginPackageState;
|
||||
import ghidra.framework.plugintool.util.*;
|
||||
import ghidra.util.HTMLUtilities;
|
||||
import ghidra.util.exception.AssertException;
|
||||
import ghidra.util.layout.HorizontalLayout;
|
||||
import ghidra.util.layout.VerticalLayout;
|
||||
import resources.ResourceManager;
|
||||
|
||||
public class PluginManagerComponent extends JPanel implements ChangeListener, Scrollable {
|
||||
public class PluginManagerComponent extends JPanel implements Scrollable {
|
||||
private final PluginTool tool;
|
||||
private PluginConfigurationModel model;
|
||||
private List<PluginPackageComponent> packageComponentList = new ArrayList<>();
|
||||
|
||||
PluginManagerComponent(PluginTool tool) {
|
||||
PluginManagerComponent(PluginTool tool, PluginConfigurationModel model) {
|
||||
super(new VerticalLayout(2));
|
||||
setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10));
|
||||
setBackground(Color.WHITE);
|
||||
this.tool = tool;
|
||||
model = new PluginConfigurationModel(tool, this);
|
||||
this.model = model;
|
||||
model.setChangeCallback(this::updateCheckboxes);
|
||||
|
||||
List<PluginPackage> pluginPackages = model.getPluginPackages();
|
||||
for (PluginPackage pluginPackage : pluginPackages) {
|
||||
PluginPackageComponent comp = new PluginPackageComponent(pluginPackage);
|
||||
|
@ -56,31 +56,66 @@ public class PluginManagerComponent extends JPanel implements ChangeListener, Sc
|
|||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void stateChanged(ChangeEvent e) {
|
||||
private void updateCheckboxes() {
|
||||
for (PluginPackageComponent comp : packageComponentList) {
|
||||
comp.updateCheckBoxState();
|
||||
}
|
||||
}
|
||||
|
||||
void managePlugins(PluginPackage pluginPackage) {
|
||||
PluginInstallerDialog pluginInstallerDialog =
|
||||
new PluginInstallerDialog("Configure " + pluginPackage.getName() + " Plugins", tool,
|
||||
model.getPluginDescriptions(pluginPackage));
|
||||
List<PluginDescription> descriptons = model.getPluginDescriptions(pluginPackage);
|
||||
PluginInstallerDialog pluginInstallerDialog = new PluginInstallerDialog(
|
||||
"Configure " + pluginPackage.getName() + " Plugins", tool, model, descriptons);
|
||||
tool.showDialog(pluginInstallerDialog);
|
||||
}
|
||||
|
||||
void manageAllPlugins() {
|
||||
PluginInstallerDialog pluginTableDialog = new PluginInstallerDialog("Configure All Plugins",
|
||||
tool, model.getAllPluginDescriptions());
|
||||
tool, model, model.getAllPluginDescriptions());
|
||||
tool.showDialog(pluginTableDialog);
|
||||
}
|
||||
|
||||
PluginConfigurationModel getModel() {
|
||||
return model;
|
||||
}
|
||||
|
||||
int getPackageCount() {
|
||||
return packageComponentList.size();
|
||||
}
|
||||
|
||||
int getPluginCount(PluginPackage pluginPackage) {
|
||||
return model.getPluginDescriptions(pluginPackage).size();
|
||||
}
|
||||
|
||||
void selectPluginPackage(PluginPackage pluginPackage, boolean selected) {
|
||||
if (selected) {
|
||||
model.addSupportedPlugins(pluginPackage);
|
||||
}
|
||||
else {
|
||||
model.removeAllPlugins(pluginPackage);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
boolean isAddAllCheckBoxEnabled(PluginPackage pluginPackage) {
|
||||
for (PluginPackageComponent ppc : packageComponentList) {
|
||||
if (ppc.pluginPackage.equals(pluginPackage)) {
|
||||
return ppc.checkBox.isEnabled();
|
||||
}
|
||||
}
|
||||
|
||||
throw new AssertException("No checkbox found for " + pluginPackage);
|
||||
}
|
||||
|
||||
//==================================================================================================
|
||||
// Inner Classes
|
||||
//==================================================================================================
|
||||
|
||||
private class PluginPackageComponent extends JPanel {
|
||||
private final Color BG = Color.white;
|
||||
private final PluginPackage pluginPackage;
|
||||
private final GCheckBox checkBox;
|
||||
|
||||
|
||||
PluginPackageComponent(PluginPackage pluginPackage) {
|
||||
super(new BorderLayout());
|
||||
setBackground(BG);
|
||||
|
@ -99,28 +134,29 @@ public class PluginManagerComponent extends JPanel implements ChangeListener, Sc
|
|||
private void initizalizeCheckBoxSection() {
|
||||
final JPanel checkboxPanel = new JPanel(new HorizontalLayout(0));
|
||||
checkboxPanel.setBackground(BG);
|
||||
|
||||
checkBox.addActionListener(e -> checkBoxClicked());
|
||||
if (!pluginPackage.isfullyAddable()) {
|
||||
|
||||
checkBox.addActionListener(
|
||||
e -> selectPluginPackage(pluginPackage, checkBox.isSelected()));
|
||||
if (model.hasOnlyUnstablePlugins(pluginPackage)) {
|
||||
checkBox.setEnabled(false);
|
||||
}
|
||||
checkBox.setBackground(BG);
|
||||
|
||||
|
||||
checkboxPanel.add(Box.createHorizontalStrut(10));
|
||||
checkboxPanel.add(checkBox);
|
||||
checkboxPanel.add(Box.createHorizontalStrut(10));
|
||||
|
||||
|
||||
final JLabel iconLabel =
|
||||
new GIconLabel(ResourceManager.getScaledIcon(pluginPackage.getIcon(), 32, 32, 32));
|
||||
iconLabel.setBackground(BG);
|
||||
|
||||
|
||||
checkboxPanel.add(iconLabel);
|
||||
checkboxPanel.add(Box.createHorizontalStrut(10));
|
||||
checkboxPanel.setPreferredSize(new Dimension(84, 70));
|
||||
|
||||
|
||||
add(checkboxPanel, BorderLayout.WEST);
|
||||
}
|
||||
|
||||
|
||||
private void initializeLabelSection() {
|
||||
final JPanel centerPanel = new JPanel(new GridBagLayout());
|
||||
GridBagConstraints gbc = new GridBagConstraints();
|
||||
|
@ -128,63 +164,52 @@ public class PluginManagerComponent extends JPanel implements ChangeListener, Sc
|
|||
gbc.weightx = 1.0;
|
||||
|
||||
centerPanel.setBackground(BG);
|
||||
|
||||
|
||||
final JPanel labelPanel = new JPanel(new VerticalLayout(3));
|
||||
labelPanel.setBackground(BG);
|
||||
|
||||
|
||||
final GLabel nameLabel = new GLabel(pluginPackage.getName());
|
||||
nameLabel.setFont(nameLabel.getFont().deriveFont(18f));
|
||||
nameLabel.setForeground(Color.BLACK);
|
||||
labelPanel.add(nameLabel);
|
||||
|
||||
|
||||
final HyperlinkComponent configureHyperlink = createConfigureHyperlink();
|
||||
labelPanel.add(configureHyperlink);
|
||||
|
||||
|
||||
labelPanel.setBorder(BorderFactory.createEmptyBorder(0, 25, 0, 40));
|
||||
centerPanel.add(labelPanel, gbc);
|
||||
add(centerPanel);
|
||||
}
|
||||
|
||||
|
||||
private HyperlinkComponent createConfigureHyperlink() {
|
||||
final HyperlinkComponent configureHyperlink =
|
||||
new HyperlinkComponent("<html> <a href=\"Configure\">Configure</a>");
|
||||
configureHyperlink.addHyperlinkListener("Configure", e -> {
|
||||
if (e.getEventType() == EventType.ACTIVATED) {
|
||||
managePlugins(PluginPackageComponent.this.pluginPackage);
|
||||
}
|
||||
});
|
||||
configureHyperlink.setBackground(BG);
|
||||
return configureHyperlink;
|
||||
new HyperlinkComponent("<html> <a href=\"Configure\">Configure</a>");
|
||||
configureHyperlink.addHyperlinkListener("Configure", e -> {
|
||||
if (e.getEventType() == EventType.ACTIVATED) {
|
||||
managePlugins(PluginPackageComponent.this.pluginPackage);
|
||||
}
|
||||
});
|
||||
configureHyperlink.setBackground(BG);
|
||||
return configureHyperlink;
|
||||
}
|
||||
|
||||
|
||||
private String enchanceDescription(final String text) {
|
||||
return String.format("<html><body style='width: 300px'>%s</body></html>", text);
|
||||
}
|
||||
|
||||
|
||||
private void initializeDescriptionSection() {
|
||||
final String htmlDescription = enchanceDescription(pluginPackage.getDescription());
|
||||
|
||||
|
||||
final JLabel descriptionlabel = new GHtmlLabel(htmlDescription);
|
||||
descriptionlabel.setForeground(Color.GRAY);
|
||||
descriptionlabel.setBorder(BorderFactory.createEmptyBorder(5, 0, 0, 0));
|
||||
descriptionlabel.setVerticalAlignment(SwingConstants.TOP);
|
||||
descriptionlabel.setToolTipText(
|
||||
HTMLUtilities.toWrappedHTML(pluginPackage.getDescription(), 80));
|
||||
|
||||
|
||||
add(descriptionlabel, BorderLayout.EAST);
|
||||
}
|
||||
|
||||
protected void checkBoxClicked() {
|
||||
boolean isSelected = checkBox.isSelected();
|
||||
if (isSelected) {
|
||||
model.addAllPlugins(pluginPackage);
|
||||
}
|
||||
else {
|
||||
model.removeAllPlugins(pluginPackage);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void updateCheckBoxState() {
|
||||
checkBox.setSelected(
|
||||
model.getPackageState(pluginPackage) != PluginPackageState.NO_PLUGINS_LOADED);
|
||||
|
@ -227,4 +252,5 @@ public class PluginManagerComponent extends JPanel implements ChangeListener, Sc
|
|||
public int getScrollableUnitIncrement(Rectangle visibleRect, int orientation, int direction) {
|
||||
return 20;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -139,9 +139,9 @@ public class PluginClassManager {
|
|||
|
||||
/**
|
||||
* Used to convert an old style tool XML file by adding in classes in the same packages as
|
||||
* those that were names specifically in the XML file
|
||||
* those that were named specifically in the XML file
|
||||
* @param classNames the list of classNames from from the old XML file
|
||||
* @return
|
||||
* @return the adjusted class names
|
||||
*/
|
||||
public List<String> fillInPackageClasses(List<String> classNames) {
|
||||
Set<PluginPackage> packages = new HashSet<>();
|
||||
|
@ -222,30 +222,30 @@ public class PluginClassManager {
|
|||
return list;
|
||||
}
|
||||
|
||||
public List<PluginDescription> getReleasedPluginDescriptions(PluginPackage pluginPackage) {
|
||||
public List<PluginDescription> getPluginDescriptions(PluginPackage pluginPackage) {
|
||||
List<PluginDescription> list = packageMap.get(pluginPackage);
|
||||
List<PluginDescription> stableList = new ArrayList<>();
|
||||
for (PluginDescription pluginDescription : list) {
|
||||
if (pluginDescription.getStatus() == PluginStatus.RELEASED) {
|
||||
stableList.add(pluginDescription);
|
||||
if (pluginDescription.getStatus() == PluginStatus.UNSTABLE ||
|
||||
pluginDescription.getStatus() == PluginStatus.HIDDEN) {
|
||||
continue;
|
||||
}
|
||||
stableList.add(pluginDescription);
|
||||
}
|
||||
return stableList;
|
||||
}
|
||||
|
||||
public List<PluginDescription> getNonReleasedPluginDescriptions() {
|
||||
public List<PluginDescription> getUnstablePluginDescriptions() {
|
||||
List<PluginDescription> unstablePlugins = new ArrayList<>();
|
||||
for (PluginDescription pluginDescription : pluginClassMap.values()) {
|
||||
if (pluginDescription.getStatus() == PluginStatus.HIDDEN ||
|
||||
pluginDescription.getStatus() == PluginStatus.RELEASED) {
|
||||
continue;
|
||||
if (pluginDescription.getStatus() == PluginStatus.UNSTABLE) {
|
||||
unstablePlugins.add(pluginDescription);
|
||||
}
|
||||
unstablePlugins.add(pluginDescription);
|
||||
}
|
||||
return unstablePlugins;
|
||||
}
|
||||
|
||||
public List<PluginDescription> getAllPluginDescriptions() {
|
||||
public List<PluginDescription> getManagedPluginDescriptions() {
|
||||
ArrayList<PluginDescription> nonHiddenPlugins = new ArrayList<>();
|
||||
for (PluginDescription pluginDescription : pluginClassMap.values()) {
|
||||
if (pluginDescription.getStatus() == PluginStatus.HIDDEN) {
|
||||
|
|
|
@ -67,7 +67,7 @@ public class PluginDescription implements Comparable<PluginDescription> {
|
|||
private final List<Class<? extends PluginEvent>> eventsConsumed;
|
||||
private final List<Class<? extends PluginEvent>> eventsProduced;
|
||||
|
||||
private PluginDescription(Class<? extends Plugin> pluginClass, String pluginPackageName,
|
||||
PluginDescription(Class<? extends Plugin> pluginClass, String pluginPackageName,
|
||||
String category, String shortDescription, String description, PluginStatus status,
|
||||
boolean isSlowInstallation, List<Class<?>> servicesRequired,
|
||||
List<Class<?>> servicesProvided, List<Class<? extends PluginEvent>> eventsConsumed,
|
||||
|
@ -94,7 +94,7 @@ public class PluginDescription implements Comparable<PluginDescription> {
|
|||
|
||||
/**
|
||||
* Returns true if this plugin requires a noticeable amount of time to load when installed.
|
||||
* @return
|
||||
* @return true if this plugin requires a noticeable amount of time to load when installed.
|
||||
*/
|
||||
public boolean isSlowInstallation() {
|
||||
return isSlowInstallation;
|
||||
|
@ -141,6 +141,7 @@ public class PluginDescription implements Comparable<PluginDescription> {
|
|||
|
||||
/**
|
||||
* Return the name of the plugin.
|
||||
* @return the name of the plugin.
|
||||
*/
|
||||
public String getName() {
|
||||
return name;
|
||||
|
@ -186,6 +187,7 @@ public class PluginDescription implements Comparable<PluginDescription> {
|
|||
|
||||
/**
|
||||
* Returns the development status of the plugin.
|
||||
* @return the status.
|
||||
*/
|
||||
public PluginStatus getStatus() {
|
||||
return status;
|
||||
|
@ -253,9 +255,9 @@ public class PluginDescription implements Comparable<PluginDescription> {
|
|||
return name.compareTo(other.name);
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------------------
|
||||
// static methods that we don't care about
|
||||
//-------------------------------------------------------------------------------------
|
||||
//==================================================================================================
|
||||
// static methods that will eventually be removed as old client plugins have been updated
|
||||
//==================================================================================================
|
||||
|
||||
/**
|
||||
* Constructs a new PluginDescription for the given plugin class.
|
||||
|
|
|
@ -103,6 +103,15 @@ public abstract class PluginPackage implements ExtensionPoint, Comparable<Plugin
|
|||
return description;
|
||||
}
|
||||
|
||||
/**
|
||||
* The minimum level required to activate plugins when the entire package is activated by the
|
||||
* user.
|
||||
* @return the minimum level
|
||||
*/
|
||||
public PluginStatus getActivationLevel() {
|
||||
return PluginStatus.RELEASED;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int compareTo(PluginPackage other) {
|
||||
if (priority == other.priority) {
|
||||
|
@ -111,7 +120,8 @@ public abstract class PluginPackage implements ExtensionPoint, Comparable<Plugin
|
|||
return priority - other.priority;
|
||||
}
|
||||
|
||||
public boolean isfullyAddable() {
|
||||
return true;
|
||||
@Override
|
||||
public String toString() {
|
||||
return name;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,9 +5,9 @@
|
|||
* 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.
|
||||
|
|
|
@ -52,20 +52,21 @@ public class PluginUtils {
|
|||
public static List<PluginDescription> getPluginDescriptions(PluginTool tool,
|
||||
List<Class<?>> plugins) {
|
||||
|
||||
// First define the list of plugin descriptions to return.
|
||||
// First define the list of plugin descriptions to return
|
||||
List<PluginDescription> retPlugins = new ArrayList<>();
|
||||
|
||||
// Get all plugins that have been loaded.
|
||||
PluginConfigurationModel model = new PluginConfigurationModel(tool, null);
|
||||
List<PluginDescription> allPluginDescriptions = model.getAllPluginDescriptions();
|
||||
// Get all plugins that have been loaded
|
||||
PluginClassManager pluginClassManager = tool.getPluginClassManager();
|
||||
List<PluginDescription> allPluginDescriptions =
|
||||
pluginClassManager.getManagedPluginDescriptions();
|
||||
|
||||
// For each plugin classes we're searching for, see if an entry exists in the list of all
|
||||
// loaded plugins.
|
||||
// see if an entry exists in the list of all loaded plugins
|
||||
for (Class<?> plugin : plugins) {
|
||||
String pluginName = plugin.getSimpleName();
|
||||
|
||||
Optional<PluginDescription> desc = allPluginDescriptions.stream().filter(
|
||||
d -> (pluginName.equals(d.getName()))).findAny();
|
||||
Optional<PluginDescription> desc = allPluginDescriptions.stream()
|
||||
.filter(d -> (pluginName.equals(d.getName())))
|
||||
.findAny();
|
||||
if (desc.isPresent()) {
|
||||
retPlugins.add(desc.get());
|
||||
}
|
||||
|
|
|
@ -32,8 +32,7 @@ import ghidra.framework.main.FrontEndOnly;
|
|||
import ghidra.framework.model.Project;
|
||||
import ghidra.framework.model.ToolTemplate;
|
||||
import ghidra.framework.options.PreferenceState;
|
||||
import ghidra.framework.plugintool.Plugin;
|
||||
import ghidra.framework.plugintool.PluginTool;
|
||||
import ghidra.framework.plugintool.*;
|
||||
import ghidra.framework.plugintool.dialog.*;
|
||||
import ghidra.framework.plugintool.util.*;
|
||||
import ghidra.util.HelpLocation;
|
||||
|
@ -256,8 +255,8 @@ public class GhidraTool extends PluginTool {
|
|||
if (option == OptionDialog.YES_OPTION) {
|
||||
List<PluginDescription> pluginDescriptions =
|
||||
PluginUtils.getPluginDescriptions(this, newPlugins);
|
||||
PluginInstallerDialog pluginInstaller =
|
||||
new PluginInstallerDialog("New Plugins Found!", this, pluginDescriptions);
|
||||
PluginInstallerDialog pluginInstaller = new PluginInstallerDialog("New Plugins Found!",
|
||||
this, new PluginConfigurationModel(this), pluginDescriptions);
|
||||
showDialog(pluginInstaller);
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,34 @@
|
|||
/* ###
|
||||
* 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.plugintool.util;
|
||||
|
||||
import java.util.Collections;
|
||||
|
||||
import ghidra.framework.plugintool.Plugin;
|
||||
|
||||
/**
|
||||
* A basic stub that allows tests to create plugin descriptions
|
||||
*/
|
||||
public class StubPluginDescription extends PluginDescription {
|
||||
|
||||
public StubPluginDescription(Class<? extends Plugin> pluginClass, PluginPackage pluginPackage,
|
||||
String category, String shortDescription, PluginStatus status) {
|
||||
super(pluginClass, pluginPackage.getName(), category, shortDescription,
|
||||
"Full description for " + pluginClass.getName(), status, false, Collections.emptyList(),
|
||||
Collections.emptyList(), Collections.emptyList(), Collections.emptyList());
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,70 @@
|
|||
/* ###
|
||||
* 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.plugintool.util;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import generic.test.TestUtils;
|
||||
import ghidra.framework.plugintool.Plugin;
|
||||
|
||||
/**
|
||||
* A builder to allow test writers to easily create a {@link StubPluginDescription}.
|
||||
*/
|
||||
public class StubPluginDescriptionBuilder {
|
||||
|
||||
private Class<? extends Plugin> clazz;
|
||||
private PluginPackage pluginPackage;
|
||||
private PluginStatus status = PluginStatus.RELEASED;
|
||||
private String category = "Category";
|
||||
private String shortDescription = "Short description";
|
||||
|
||||
public StubPluginDescriptionBuilder(Class<? extends Plugin> clazz,
|
||||
PluginPackage pluginPackage) {
|
||||
this.clazz = clazz;
|
||||
this.pluginPackage = pluginPackage;
|
||||
}
|
||||
|
||||
public StubPluginDescriptionBuilder status(PluginStatus pluginStatus) {
|
||||
this.status = pluginStatus;
|
||||
return this;
|
||||
}
|
||||
|
||||
public StubPluginDescriptionBuilder category(String pluginCategory) {
|
||||
this.category = pluginCategory;
|
||||
return this;
|
||||
}
|
||||
|
||||
public StubPluginDescriptionBuilder shortDescription(String description) {
|
||||
this.shortDescription = description;
|
||||
return this;
|
||||
}
|
||||
|
||||
public StubPluginDescription build() {
|
||||
|
||||
// as a convenience for test writers, ensure that the given plugin package is registered
|
||||
// with the system
|
||||
@SuppressWarnings("unchecked")
|
||||
Map<String, PluginPackage> map = (Map<String, PluginPackage>) TestUtils
|
||||
.getInstanceField("packageMap", PluginPackage.class);
|
||||
map.put(pluginPackage.getName().toLowerCase(), pluginPackage);
|
||||
|
||||
if (shortDescription == null) {
|
||||
shortDescription = "Short description for " + clazz.getSimpleName();
|
||||
}
|
||||
|
||||
return new StubPluginDescription(clazz, pluginPackage, category, shortDescription, status);
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue