mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2025-02-07 19:20:14 +00:00
GP-1764 - Plugins - tweaked help
This commit is contained in:
parent
82c42e648c
commit
924bf7656e
@ -1,111 +0,0 @@
|
||||
/* ###
|
||||
* 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.
|
||||
*/
|
||||
import java.util.*;
|
||||
|
||||
import generic.jar.ResourceFile;
|
||||
import ghidra.app.script.GhidraScript;
|
||||
import ghidra.app.services.Analyzer;
|
||||
import ghidra.framework.Application;
|
||||
import ghidra.framework.plugintool.PluginConfigurationModel;
|
||||
import ghidra.framework.plugintool.util.PluginDescription;
|
||||
import ghidra.util.classfinder.ClassSearcher;
|
||||
|
||||
public class DumpGhidraCapabilitiesScript extends GhidraScript {
|
||||
|
||||
private Map<String, List<PluginDescription>> pluginMap = new HashMap<>();
|
||||
private Map<String, List<Analyzer>> analyzerMap = new HashMap<>();
|
||||
|
||||
@Override
|
||||
public void run() throws Exception {
|
||||
PluginConfigurationModel model = new PluginConfigurationModel(state.getTool());
|
||||
List<PluginDescription> descriptions = model.getAllPluginDescriptions();
|
||||
for (PluginDescription pluginDescription : descriptions) {
|
||||
String moduleName = pluginDescription.getModuleName();
|
||||
|
||||
if (moduleName == null) {
|
||||
moduleName = "[ No Module ]";
|
||||
}
|
||||
|
||||
addPlugin(moduleName, pluginDescription);
|
||||
}
|
||||
|
||||
List<Analyzer> instances = ClassSearcher.getInstances(Analyzer.class);
|
||||
for (Analyzer analyzer : instances) {
|
||||
Class<? extends Analyzer> clazz = analyzer.getClass();
|
||||
|
||||
ResourceFile module = Application.getModuleContainingClass(clazz.getName());
|
||||
|
||||
String moduleName;
|
||||
if (module == null) {
|
||||
moduleName = "[ No Module ]";
|
||||
}
|
||||
else {
|
||||
moduleName = module.getName();
|
||||
}
|
||||
|
||||
addAnalyzer(moduleName, analyzer);
|
||||
}
|
||||
|
||||
Set<String> set = new HashSet<>(pluginMap.keySet());
|
||||
set.addAll(analyzerMap.keySet());
|
||||
List<String> list = new ArrayList<>(set);
|
||||
Collections.sort(list);
|
||||
System.out.println("Modules:");
|
||||
for (String module : list) {
|
||||
System.out.println("\t" + module);
|
||||
List<PluginDescription> plugins = pluginMap.get(module);
|
||||
if (plugins != null && !plugins.isEmpty()) {
|
||||
System.out.println("\t\tPlugins: ");
|
||||
Collections.sort(plugins);
|
||||
for (PluginDescription pd : plugins) {
|
||||
System.out.println("\t\t\t" + pd.getName());
|
||||
System.out.println("\t\t\t\t" + pd.getShortDescription());
|
||||
System.out.println("\t\t\t\t" + pd.getDescription());
|
||||
}
|
||||
}
|
||||
|
||||
List<Analyzer> analyzers = analyzerMap.get(module);
|
||||
if (analyzers != null && !analyzers.isEmpty()) {
|
||||
System.out.println("\t\tAnalyzers: ");
|
||||
Collections.sort(analyzers,
|
||||
(arg0, arg1) -> arg0.getName().compareTo(arg1.getName()));
|
||||
for (Analyzer analyzer : analyzers) {
|
||||
System.out.println("\t\t\t" + analyzer.getName());
|
||||
System.out.println("\t\t\t\t" + analyzer.getDescription());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void addAnalyzer(String moduleName, Analyzer analyzer) {
|
||||
List<Analyzer> list = analyzerMap.get(moduleName);
|
||||
if (list == null) {
|
||||
list = new ArrayList<>();
|
||||
analyzerMap.put(moduleName, list);
|
||||
}
|
||||
list.add(analyzer);
|
||||
|
||||
}
|
||||
|
||||
private void addPlugin(String moduleName, PluginDescription pluginDescription) {
|
||||
List<PluginDescription> list = pluginMap.get(moduleName);
|
||||
if (list == null) {
|
||||
list = new ArrayList<>();
|
||||
pluginMap.put(moduleName, list);
|
||||
}
|
||||
list.add(pluginDescription);
|
||||
}
|
||||
}
|
@ -28,8 +28,12 @@
|
||||
<BLOCKQUOTE>
|
||||
<BLOCKQUOTE>
|
||||
<P>The <I>Configure Tool</I> dialog shows a list of plugin packages that can be added to
|
||||
the tool. Clicking the checkbox will add (or remove) all the plugins in the package to the
|
||||
tool. Clicking on the <B>Configure</B> link will bring up a dialog for adding individual
|
||||
the tool. Clicking the unchecked checkbox will add all the plugins in the package that are
|
||||
at the supported level (typically the RELEASED level) for that package. Any plugins in the
|
||||
package not at the supported level or higher will not be automatically added. Clicking
|
||||
the checked checkbox will remove all plugins from the tool that belong to that package.
|
||||
|
||||
<P>Clicking on the <B>Configure</B> link will bring up a dialog for adding individual
|
||||
plugins.</P>
|
||||
|
||||
<BLOCKQUOTE>
|
||||
|
@ -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,14 +16,20 @@
|
||||
package ghidra.app;
|
||||
|
||||
import ghidra.framework.plugintool.util.PluginPackage;
|
||||
import ghidra.framework.plugintool.util.PluginStatus;
|
||||
import resources.ResourceManager;
|
||||
|
||||
public class DeveloperPluginPackage extends PluginPackage {
|
||||
public static final String NAME = "Developer";
|
||||
|
||||
|
||||
public DeveloperPluginPackage() {
|
||||
super(NAME, ResourceManager.loadImage("images/applications-engineering.png"),
|
||||
"These plugins provide features useful for developing and debugging plugins.",
|
||||
DEVELOPER_PRIORITY);
|
||||
"These plugins provide features useful for developing and debugging plugins.",
|
||||
DEVELOPER_PRIORITY);
|
||||
}
|
||||
|
||||
@Override
|
||||
public PluginStatus getActivationLevel() {
|
||||
return PluginStatus.STABLE;
|
||||
}
|
||||
}
|
||||
|
@ -1,29 +0,0 @@
|
||||
/* ###
|
||||
* 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.app;
|
||||
|
||||
import ghidra.framework.plugintool.util.PluginPackage;
|
||||
import resources.ResourceManager;
|
||||
|
||||
public class GraphPluginPackage extends PluginPackage {
|
||||
|
||||
public static final String NAME = "Graph";
|
||||
|
||||
public GraphPluginPackage() {
|
||||
super(NAME, ResourceManager.loadImage("images/katomic.png"),
|
||||
"Provides plugins that display information in graph form.", FEATURE_PRIORITY);
|
||||
}
|
||||
}
|
@ -32,28 +32,15 @@ import ghidra.test.TestEnv;
|
||||
import ghidra.util.classfinder.ClassSearcher;
|
||||
|
||||
/**
|
||||
*
|
||||
* Test configure the Front End tool.
|
||||
*
|
||||
*
|
||||
* Test configure the Front End tool
|
||||
*/
|
||||
public class ManageFrontEndToolTest extends AbstractGhidraHeadedIntegrationTest {
|
||||
|
||||
private TestEnv env;
|
||||
private FrontEndTool tool;
|
||||
private FrontEndPlugin plugin;
|
||||
private ManagePluginsDialog provider;
|
||||
|
||||
private ManagePluginsDialog managePluginsDialog;
|
||||
private PluginConfigurationModel pluginModel;
|
||||
private PluginManagerComponent pluginManagerComponent;
|
||||
|
||||
/**
|
||||
* Constructor for ManageFrontEndToolTest.
|
||||
* @param arg0
|
||||
*/
|
||||
public ManageFrontEndToolTest() {
|
||||
super();
|
||||
}
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
@ -65,15 +52,12 @@ public class ManageFrontEndToolTest extends AbstractGhidraHeadedIntegrationTest
|
||||
showProvider();
|
||||
}
|
||||
|
||||
/*
|
||||
* @see TestCase#tearDown()
|
||||
*/
|
||||
@After
|
||||
public void tearDown() throws Exception {
|
||||
|
||||
runSwing(() -> {
|
||||
tool.setConfigChanged(false);
|
||||
provider.close();
|
||||
managePluginsDialog.close();
|
||||
});
|
||||
env.dispose();
|
||||
}
|
||||
@ -97,7 +81,7 @@ public class ManageFrontEndToolTest extends AbstractGhidraHeadedIntegrationTest
|
||||
final Plugin p = getPlugin(tool, ArchivePlugin.class);
|
||||
assertNotNull(p);
|
||||
runSwing(() -> {
|
||||
provider.close();
|
||||
managePluginsDialog.close();
|
||||
tool.removePlugins(new Plugin[] { p });
|
||||
});
|
||||
|
||||
@ -108,7 +92,7 @@ public class ManageFrontEndToolTest extends AbstractGhidraHeadedIntegrationTest
|
||||
|
||||
action = getAction(tool, plugin.getName(), "Close Project");
|
||||
performAction(action, true);
|
||||
assertTrue(!provider.isVisible());
|
||||
assertFalse(managePluginsDialog.isVisible());
|
||||
}
|
||||
|
||||
private void showProvider() throws Exception {
|
||||
@ -118,9 +102,7 @@ public class ManageFrontEndToolTest extends AbstractGhidraHeadedIntegrationTest
|
||||
waitForPostedSwingRunnables();
|
||||
runSwing(() -> tool.showConfig(false, false));
|
||||
|
||||
provider = tool.getManagePluginsDialog();
|
||||
pluginManagerComponent = (PluginManagerComponent) getInstanceField("comp", provider);
|
||||
pluginModel = (PluginConfigurationModel) getInstanceField("model", pluginManagerComponent);
|
||||
|
||||
managePluginsDialog = tool.getManagePluginsDialog();
|
||||
pluginModel = managePluginsDialog.getPluginConfigurationModel();
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,480 @@
|
||||
/* ###
|
||||
* 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.dialog;
|
||||
|
||||
import static org.hamcrest.collection.IsEmptyCollection.*;
|
||||
import static org.hamcrest.core.IsNot.*;
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.junit.*;
|
||||
|
||||
import ghidra.app.plugin.core.help.AboutProgramPlugin;
|
||||
import ghidra.app.plugin.core.totd.TipOfTheDayPlugin;
|
||||
import ghidra.app.plugin.debug.JavaHelpPlugin;
|
||||
import ghidra.framework.plugintool.*;
|
||||
import ghidra.framework.plugintool.util.*;
|
||||
import ghidra.test.AbstractGhidraHeadedIntegrationTest;
|
||||
import ghidra.test.TestEnv;
|
||||
import resources.ResourceManager;
|
||||
|
||||
/**
|
||||
* Tests for the configuring a tool.
|
||||
*
|
||||
*
|
||||
*/
|
||||
public class ManagePlugins2Test extends AbstractGhidraHeadedIntegrationTest {
|
||||
|
||||
private TestEnv env;
|
||||
private PluginTool tool;
|
||||
private ManagePluginsDialog dialog;
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
env = new TestEnv();
|
||||
tool = env.getTool();
|
||||
}
|
||||
|
||||
@After
|
||||
public void tearDown() throws Exception {
|
||||
close(dialog);
|
||||
env.dispose();
|
||||
|
||||
sleep(1000);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPluginPackage_ReleasedPackage_ReleasedPlugins() throws Exception {
|
||||
|
||||
PluginPackage testPackage = new PluginPackage("TEST",
|
||||
ResourceManager.loadImage("images/Data_32.png"), "Test plugin pacakge") {
|
||||
//
|
||||
};
|
||||
|
||||
StubPluginDescription pd1 =
|
||||
new StubPluginDescriptionBuilder(AboutProgramPlugin.class, testPackage).build();
|
||||
StubPluginDescription pd2 =
|
||||
new StubPluginDescriptionBuilder(JavaHelpPlugin.class, testPackage).build();
|
||||
|
||||
StubPluginPackagingProvider stubProvider = new StubPluginPackagingProvider();
|
||||
stubProvider.addPackage(testPackage);
|
||||
stubProvider.addDescription(pd1);
|
||||
stubProvider.addDescription(pd2);
|
||||
|
||||
StubPluginInstaller stubInstaller = new StubPluginInstaller();
|
||||
PluginConfigurationModel model = new PluginConfigurationModel(stubInstaller, stubProvider);
|
||||
|
||||
dialog = new ManagePluginsDialog(tool, model, false, false);
|
||||
runSwing(() -> tool.showDialog(dialog), false);
|
||||
|
||||
waitForDialogComponent(ManagePluginsDialog.class);
|
||||
|
||||
// test the checkbox to add/remove all plugins in the package
|
||||
assertPackageCount(1);
|
||||
assertPluginCount(testPackage, 2);
|
||||
|
||||
selectAddAll(testPackage, true);
|
||||
assertLoadedPlugins(stubInstaller, pd1, pd2);
|
||||
|
||||
selectAddAll(testPackage, false);
|
||||
assertNoPluginsLoaded(stubInstaller);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPluginPackage_ReleasedPackage_ReleasedAndStablePlugins() throws Exception {
|
||||
|
||||
PluginPackage testPackage = new PluginPackage("TEST",
|
||||
ResourceManager.loadImage("images/Data_32.png"), "Test plugin pacakge") {
|
||||
//
|
||||
};
|
||||
|
||||
StubPluginDescription pd1 =
|
||||
new StubPluginDescriptionBuilder(AboutProgramPlugin.class, testPackage)
|
||||
.status(PluginStatus.RELEASED)
|
||||
.build();
|
||||
StubPluginDescription pd2 =
|
||||
new StubPluginDescriptionBuilder(JavaHelpPlugin.class, testPackage)
|
||||
.status(PluginStatus.STABLE)
|
||||
.build();
|
||||
|
||||
StubPluginPackagingProvider stubProvider = new StubPluginPackagingProvider();
|
||||
stubProvider.addPackage(testPackage);
|
||||
stubProvider.addDescription(pd1);
|
||||
stubProvider.addDescription(pd2);
|
||||
|
||||
StubPluginInstaller stubInstaller = new StubPluginInstaller();
|
||||
PluginConfigurationModel model = new PluginConfigurationModel(stubInstaller, stubProvider);
|
||||
|
||||
dialog = new ManagePluginsDialog(tool, model, false, false);
|
||||
runSwing(() -> tool.showDialog(dialog), false);
|
||||
|
||||
waitForDialogComponent(ManagePluginsDialog.class);
|
||||
|
||||
// test the checkbox to add/remove all plugins in the package
|
||||
assertPackageCount(1);
|
||||
assertPluginCount(testPackage, 2);
|
||||
|
||||
selectAddAll(testPackage, true);
|
||||
assertLoadedPlugins(stubInstaller, pd1); // only 1 'released' plugin loaded
|
||||
|
||||
selectAddAll(testPackage, false);
|
||||
assertNoPluginsLoaded(stubInstaller);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPluginPackage_StablePackage_ReleasedAndStablePlugins() throws Exception {
|
||||
|
||||
PluginPackage testPackage = new PluginPackage("TEST",
|
||||
ResourceManager.loadImage("images/Data_32.png"), "Test plugin pacakge") {
|
||||
@Override
|
||||
public PluginStatus getActivationLevel() {
|
||||
return PluginStatus.STABLE;
|
||||
}
|
||||
};
|
||||
|
||||
StubPluginDescription pd1 =
|
||||
new StubPluginDescriptionBuilder(AboutProgramPlugin.class, testPackage)
|
||||
.status(PluginStatus.RELEASED)
|
||||
.build();
|
||||
StubPluginDescription pd2 =
|
||||
new StubPluginDescriptionBuilder(JavaHelpPlugin.class, testPackage)
|
||||
.status(PluginStatus.STABLE)
|
||||
.build();
|
||||
|
||||
StubPluginPackagingProvider stubProvider = new StubPluginPackagingProvider();
|
||||
stubProvider.addPackage(testPackage);
|
||||
stubProvider.addDescription(pd1);
|
||||
stubProvider.addDescription(pd2);
|
||||
|
||||
StubPluginInstaller stubInstaller = new StubPluginInstaller();
|
||||
PluginConfigurationModel model = new PluginConfigurationModel(stubInstaller, stubProvider);
|
||||
|
||||
dialog = new ManagePluginsDialog(tool, model, false, false);
|
||||
runSwing(() -> tool.showDialog(dialog), false);
|
||||
|
||||
waitForDialogComponent(ManagePluginsDialog.class);
|
||||
|
||||
// test the checkbox to add/remove all plugins in the package
|
||||
assertPackageCount(1);
|
||||
assertPluginCount(testPackage, 2);
|
||||
|
||||
selectAddAll(testPackage, true);
|
||||
assertLoadedPlugins(stubInstaller, pd1, pd2); // 'released' and 'stable' plugins loaded
|
||||
|
||||
selectAddAll(testPackage, false);
|
||||
assertNoPluginsLoaded(stubInstaller);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPluginPackage_StablePackage_ReleasedAndStableAndUnstablePlugins()
|
||||
throws Exception {
|
||||
|
||||
PluginPackage testPackage = new PluginPackage("TEST",
|
||||
ResourceManager.loadImage("images/Data_32.png"), "Test plugin pacakge") {
|
||||
@Override
|
||||
public PluginStatus getActivationLevel() {
|
||||
return PluginStatus.STABLE;
|
||||
}
|
||||
};
|
||||
|
||||
StubPluginDescription pd1 =
|
||||
new StubPluginDescriptionBuilder(AboutProgramPlugin.class, testPackage)
|
||||
.status(PluginStatus.RELEASED)
|
||||
.build();
|
||||
StubPluginDescription pd2 =
|
||||
new StubPluginDescriptionBuilder(JavaHelpPlugin.class, testPackage)
|
||||
.status(PluginStatus.STABLE)
|
||||
.build();
|
||||
|
||||
StubPluginDescription pd3 =
|
||||
new StubPluginDescriptionBuilder(TipOfTheDayPlugin.class, testPackage)
|
||||
.status(PluginStatus.UNSTABLE)
|
||||
.build();
|
||||
|
||||
StubPluginPackagingProvider stubProvider = new StubPluginPackagingProvider();
|
||||
stubProvider.addPackage(testPackage);
|
||||
stubProvider.addDescription(pd1);
|
||||
stubProvider.addDescription(pd2);
|
||||
stubProvider.addDescription(pd3);
|
||||
|
||||
StubPluginInstaller stubInstaller = new StubPluginInstaller();
|
||||
PluginConfigurationModel model = new PluginConfigurationModel(stubInstaller, stubProvider);
|
||||
|
||||
dialog = new ManagePluginsDialog(tool, model, false, false);
|
||||
runSwing(() -> tool.showDialog(dialog), false);
|
||||
|
||||
waitForDialogComponent(ManagePluginsDialog.class);
|
||||
|
||||
// test the checkbox to add/remove all plugins in the package
|
||||
assertPackageCount(1);
|
||||
assertPluginCount(testPackage, 3);
|
||||
|
||||
selectAddAll(testPackage, true);
|
||||
assertLoadedPlugins(stubInstaller, pd1, pd2); // 'released' and 'stable' plugins loaded
|
||||
|
||||
selectAddAll(testPackage, false);
|
||||
assertNoPluginsLoaded(stubInstaller);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPluginPackage_ReleasedPackage_StablePlugins() throws Exception {
|
||||
|
||||
PluginPackage testPackage = new PluginPackage("TEST",
|
||||
ResourceManager.loadImage("images/Data_32.png"), "Test plugin pacakge") {
|
||||
//
|
||||
};
|
||||
|
||||
StubPluginDescription pd1 =
|
||||
new StubPluginDescriptionBuilder(AboutProgramPlugin.class, testPackage)
|
||||
.status(PluginStatus.STABLE)
|
||||
.build();
|
||||
StubPluginDescription pd2 =
|
||||
new StubPluginDescriptionBuilder(JavaHelpPlugin.class, testPackage)
|
||||
.status(PluginStatus.STABLE)
|
||||
.build();
|
||||
|
||||
StubPluginPackagingProvider stubProvider = new StubPluginPackagingProvider();
|
||||
stubProvider.addPackage(testPackage);
|
||||
stubProvider.addDescription(pd1);
|
||||
stubProvider.addDescription(pd2);
|
||||
|
||||
StubPluginInstaller stubInstaller = new StubPluginInstaller();
|
||||
PluginConfigurationModel model = new PluginConfigurationModel(stubInstaller, stubProvider);
|
||||
|
||||
dialog = new ManagePluginsDialog(tool, model, false, false);
|
||||
runSwing(() -> tool.showDialog(dialog), false);
|
||||
|
||||
waitForDialogComponent(ManagePluginsDialog.class);
|
||||
|
||||
// test the checkbox to add/remove all plugins in the package
|
||||
assertPackageCount(1);
|
||||
assertPluginCount(testPackage, 2);
|
||||
|
||||
// the checkbox is disabled since there are no plugins that meet the activation level
|
||||
assertAddAllCheckBoxDisabled(testPackage);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPluginPackageConfigure_ReleasedPackage_ReleasedAndStablePlugins()
|
||||
throws Exception {
|
||||
|
||||
PluginPackage testPackage = new PluginPackage("TEST",
|
||||
ResourceManager.loadImage("images/Data_32.png"), "Test plugin pacakge") {
|
||||
//
|
||||
};
|
||||
|
||||
StubPluginDescription pd1 =
|
||||
new StubPluginDescriptionBuilder(AboutProgramPlugin.class, testPackage)
|
||||
.status(PluginStatus.RELEASED)
|
||||
.build();
|
||||
StubPluginDescription pd2 =
|
||||
new StubPluginDescriptionBuilder(JavaHelpPlugin.class, testPackage)
|
||||
.status(PluginStatus.STABLE)
|
||||
.build();
|
||||
|
||||
StubPluginPackagingProvider stubProvider = new StubPluginPackagingProvider();
|
||||
stubProvider.addPackage(testPackage);
|
||||
stubProvider.addDescription(pd1);
|
||||
stubProvider.addDescription(pd2);
|
||||
|
||||
StubPluginInstaller stubInstaller = new StubPluginInstaller();
|
||||
PluginConfigurationModel model = new PluginConfigurationModel(stubInstaller, stubProvider);
|
||||
|
||||
dialog = new ManagePluginsDialog(tool, model, false, false);
|
||||
runSwing(() -> tool.showDialog(dialog), false);
|
||||
|
||||
waitForDialogComponent(ManagePluginsDialog.class);
|
||||
|
||||
PluginInstallerDialog installerDialog = pressConfigure(testPackage);
|
||||
assertPluginCount(installerDialog, 2);
|
||||
close(installerDialog);
|
||||
}
|
||||
|
||||
//==================================================================================================
|
||||
// Private Methods
|
||||
//==================================================================================================
|
||||
|
||||
private void selectAddAll(PluginPackage pluginPackage, boolean select) {
|
||||
PluginManagerComponent component = dialog.getPluginComponent();
|
||||
component.selectPluginPackage(pluginPackage, select);
|
||||
}
|
||||
|
||||
private void assertPackageCount(int expected) {
|
||||
int actual = dialog.getPackageCount();
|
||||
assertEquals(expected, actual);
|
||||
}
|
||||
|
||||
private void assertPluginCount(PluginPackage pluginPackage, int expected) {
|
||||
int actual = dialog.getPluginCount(pluginPackage);
|
||||
assertEquals(expected, actual);
|
||||
}
|
||||
|
||||
private void assertLoadedPlugins(StubPluginInstaller stubInstaller,
|
||||
StubPluginDescription... descriptions) {
|
||||
|
||||
Set<String> addedPlugins = stubInstaller.getAddedPlugins();
|
||||
assertEquals(descriptions.length, addedPlugins.size());
|
||||
for (PluginDescription pd : descriptions) {
|
||||
assertTrue(addedPlugins.contains(pd.getPluginClass().getName()));
|
||||
}
|
||||
}
|
||||
|
||||
private void assertNoPluginsLoaded(StubPluginInstaller installer) {
|
||||
assertTrue(installer.getManagedPlugins().isEmpty());
|
||||
}
|
||||
|
||||
private void assertAddAllCheckBoxDisabled(PluginPackage pluginPackage) {
|
||||
PluginManagerComponent component = dialog.getPluginComponent();
|
||||
assertTrue(runSwing(() -> component.isAddAllCheckBoxEnabled(pluginPackage)));
|
||||
}
|
||||
|
||||
private PluginInstallerDialog pressConfigure(PluginPackage pluginPackage) {
|
||||
PluginManagerComponent component = dialog.getPluginComponent();
|
||||
runSwing(() -> component.managePlugins(pluginPackage), false);
|
||||
return waitForDialogComponent(PluginInstallerDialog.class);
|
||||
}
|
||||
|
||||
private void assertPluginCount(PluginInstallerDialog installerDialog, int expected) {
|
||||
PluginConfigurationModel model = installerDialog.getModel();
|
||||
assertEquals(expected, model.getAllPluginDescriptions().size());
|
||||
}
|
||||
|
||||
//==================================================================================================
|
||||
// Inner Classes
|
||||
//==================================================================================================
|
||||
|
||||
private class StubPluginInstaller implements PluginInstaller {
|
||||
|
||||
private List<Plugin> loadedPlugins = new ArrayList<>();
|
||||
private Set<String> addedPlugins = new HashSet<>();
|
||||
private Set<String> removedPlugins = new HashSet<>();
|
||||
|
||||
@Override
|
||||
public void addPlugins(List<String> pluginClassNames) throws PluginException {
|
||||
for (String name : pluginClassNames) {
|
||||
addedPlugins.add(name);
|
||||
runSwing(() -> loadPlugin(name));
|
||||
}
|
||||
}
|
||||
|
||||
private void loadPlugin(String name) {
|
||||
try {
|
||||
Class<?> clazz = Class.forName(name);
|
||||
Plugin plugin =
|
||||
(Plugin) clazz.getDeclaredConstructor(PluginTool.class).newInstance(tool);
|
||||
loadedPlugins.add(plugin);
|
||||
}
|
||||
catch (Exception e) {
|
||||
failWithException("Unable to load plugin: " + name, e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removePlugins(List<Plugin> array) {
|
||||
for (Plugin plugin : array) {
|
||||
loadedPlugins.remove(plugin);
|
||||
removedPlugins.remove(plugin.getClass().getSimpleName());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Plugin> getManagedPlugins() {
|
||||
return loadedPlugins;
|
||||
}
|
||||
|
||||
Set<String> getAddedPlugins() {
|
||||
return addedPlugins;
|
||||
}
|
||||
}
|
||||
|
||||
private class StubPluginPackagingProvider implements PluginPackagingProvider {
|
||||
|
||||
private List<PluginPackage> packages = new ArrayList<>();
|
||||
private List<PluginDescription> descriptions = new ArrayList<>();
|
||||
private List<PluginDescription> unstableDescriptions = new ArrayList<>();
|
||||
|
||||
@Override
|
||||
public List<PluginPackage> getPluginPackages() {
|
||||
return packages;
|
||||
}
|
||||
|
||||
void addPackage(PluginPackage p) {
|
||||
packages.add(p);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<PluginDescription> getPluginDescriptions() {
|
||||
return descriptions;
|
||||
}
|
||||
|
||||
void addDescription(PluginDescription pd) {
|
||||
descriptions.add(pd);
|
||||
}
|
||||
|
||||
@Override
|
||||
public PluginDescription getPluginDescription(String pluginClassName) {
|
||||
List<PluginDescription> results = descriptions.stream()
|
||||
.filter(pd -> pd.getPluginClass().getName().equals(pluginClassName))
|
||||
.collect(Collectors.toList());
|
||||
assertEquals(1, results.size());
|
||||
return results.get(0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<PluginDescription> getPluginDescriptions(PluginPackage pluginPackage) {
|
||||
List<PluginDescription> results = descriptions.stream()
|
||||
.filter(pd -> pd.getPluginPackage().equals(pluginPackage))
|
||||
.collect(Collectors.toList());
|
||||
assertThat(results, not(empty()));
|
||||
return results;
|
||||
}
|
||||
|
||||
@Override
|
||||
public PluginPackage getUnstablePluginPackage() {
|
||||
return UNSTABLE_PACKAGE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<PluginDescription> getUnstablePluginDescriptions() {
|
||||
return unstableDescriptions;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
testPluginPackage_Released() {
|
||||
|
||||
Click to add all
|
||||
|
||||
Click to remove All
|
||||
|
||||
}
|
||||
|
||||
|
||||
testPluginPackage_Stable_ReleasedPlugins()
|
||||
|
||||
testPluginPackage_Stable_ReleasedAndStablePlugins()
|
||||
|
||||
testPluginPackage_Stable_ReleasedAndStableAndUnstablePlugins()
|
||||
-unstable goes to 'experimental'
|
||||
|
||||
testPluginPackage
|
||||
|
||||
*/
|
||||
|
||||
}
|
@ -43,7 +43,6 @@ import ghidra.app.plugin.core.programtree.ProgramTreePlugin;
|
||||
import ghidra.app.plugin.debug.DbViewerPlugin;
|
||||
import ghidra.app.plugin.debug.EventDisplayPlugin;
|
||||
import ghidra.app.plugin.prototype.debug.ScreenshotPlugin;
|
||||
import ghidra.framework.model.ToolChest;
|
||||
import ghidra.framework.plugintool.PluginConfigurationModel;
|
||||
import ghidra.framework.plugintool.PluginTool;
|
||||
import ghidra.framework.plugintool.util.PluginDescription;
|
||||
@ -60,7 +59,7 @@ public class ManagePluginsTest extends AbstractGhidraHeadedIntegrationTest {
|
||||
|
||||
private TestEnv env;
|
||||
private PluginTool tool;
|
||||
private ManagePluginsDialog provider;
|
||||
private ManagePluginsDialog managePluginsDialog;
|
||||
private PluginConfigurationModel pluginModel;
|
||||
private String descrText;
|
||||
private PluginManagerComponent pluginManagerComponent;
|
||||
@ -89,19 +88,17 @@ public class ManagePluginsTest extends AbstractGhidraHeadedIntegrationTest {
|
||||
@After
|
||||
public void tearDown() throws Exception {
|
||||
tool.setConfigChanged(false);
|
||||
ToolChest tc = tool.getProject().getLocalToolChest();
|
||||
tc.remove("MyTestTool");
|
||||
runSwing(() -> provider.close());
|
||||
closeAllWindowsAndFrames();
|
||||
runSwing(() -> managePluginsDialog.close());
|
||||
closeAllWindows();
|
||||
env.dispose();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testActionEnablement() {
|
||||
performAction(provider.getSaveAction(), true);
|
||||
performAction(managePluginsDialog.getSaveAction(), true);
|
||||
|
||||
assertTrue(!provider.getSaveAction().isEnabled());
|
||||
assertTrue(provider.getSaveAsAction().isEnabled());
|
||||
assertFalse(managePluginsDialog.getSaveAction().isEnabled());
|
||||
assertTrue(managePluginsDialog.getSaveAsAction().isEnabled());
|
||||
}
|
||||
|
||||
@Test
|
||||
@ -114,11 +111,11 @@ public class ManagePluginsTest extends AbstractGhidraHeadedIntegrationTest {
|
||||
PluginDescription eventDisplay =
|
||||
PluginDescription.getPluginDescription(EventDisplayPlugin.class);
|
||||
|
||||
assertTrue(!pluginModel.isLoaded(dBViewer));
|
||||
assertTrue(!pluginModel.isLoaded(screenshot));
|
||||
assertTrue(!pluginModel.isLoaded(eventDisplay));
|
||||
assertFalse(pluginModel.isLoaded(dBViewer));
|
||||
assertFalse(pluginModel.isLoaded(screenshot));
|
||||
assertFalse(pluginModel.isLoaded(eventDisplay));
|
||||
|
||||
executeOnSwingWithoutBlocking(() -> pluginModel.addAllPlugins(pluginPackage));
|
||||
executeOnSwingWithoutBlocking(() -> pluginModel.addSupportedPlugins(pluginPackage));
|
||||
|
||||
assertTrue(pluginModel.isLoaded(dBViewer));
|
||||
assertTrue(pluginModel.isLoaded(screenshot));
|
||||
@ -126,9 +123,9 @@ public class ManagePluginsTest extends AbstractGhidraHeadedIntegrationTest {
|
||||
|
||||
executeOnSwingWithoutBlocking(() -> pluginModel.removeAllPlugins(pluginPackage));
|
||||
|
||||
assertTrue(!pluginModel.isLoaded(dBViewer));
|
||||
assertTrue(!pluginModel.isLoaded(screenshot));
|
||||
assertTrue(!pluginModel.isLoaded(eventDisplay));
|
||||
assertFalse(pluginModel.isLoaded(dBViewer));
|
||||
assertFalse(pluginModel.isLoaded(screenshot));
|
||||
assertFalse(pluginModel.isLoaded(eventDisplay));
|
||||
|
||||
}
|
||||
|
||||
@ -147,7 +144,7 @@ public class ManagePluginsTest extends AbstractGhidraHeadedIntegrationTest {
|
||||
waitForTasks();
|
||||
|
||||
assertTrue(tool.hasConfigChanged());
|
||||
assertTrue(provider.getSaveAction().isEnabled());
|
||||
assertTrue(managePluginsDialog.getSaveAction().isEnabled());
|
||||
assertTrue(
|
||||
pluginModel.isLoaded(PluginDescription.getPluginDescription(AboutProgramPlugin.class)));
|
||||
}
|
||||
@ -158,9 +155,9 @@ public class ManagePluginsTest extends AbstractGhidraHeadedIntegrationTest {
|
||||
SwingUtilities.invokeLater(() -> pluginManagerComponent.manageAllPlugins());
|
||||
pluginModel.removePlugin(PluginDescription.getPluginDescription(EquateTablePlugin.class));
|
||||
assertTrue(tool.hasConfigChanged());
|
||||
assertTrue(provider.getSaveAction().isEnabled());
|
||||
assertTrue(!pluginModel.isLoaded(
|
||||
PluginDescription.getPluginDescription(AboutProgramPlugin.class)));
|
||||
assertTrue(managePluginsDialog.getSaveAction().isEnabled());
|
||||
assertFalse(
|
||||
pluginModel.isLoaded(PluginDescription.getPluginDescription(AboutProgramPlugin.class)));
|
||||
|
||||
}
|
||||
|
||||
@ -238,14 +235,14 @@ public class ManagePluginsTest extends AbstractGhidraHeadedIntegrationTest {
|
||||
public void testSaveChanges() throws Exception {
|
||||
tool.setConfigChanged(true);
|
||||
assertTrue(tool.hasConfigChanged());
|
||||
performAction(provider.getSaveAction(), true);
|
||||
assertTrue(!tool.hasConfigChanged());
|
||||
performAction(managePluginsDialog.getSaveAction(), true);
|
||||
assertFalse(tool.hasConfigChanged());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSaveAs() throws Exception {
|
||||
// verify the Save tool config dialog is displayed.
|
||||
performAction(provider.getSaveAsAction(), false);
|
||||
performAction(managePluginsDialog.getSaveAsAction(), false);
|
||||
waitForSwing();
|
||||
SaveToolConfigDialog d = waitForDialogComponent(SaveToolConfigDialog.class);
|
||||
assertNotNull(d);
|
||||
@ -259,12 +256,13 @@ public class ManagePluginsTest extends AbstractGhidraHeadedIntegrationTest {
|
||||
DockingActionIf action = getAction(tool, ToolConstants.TOOL_OWNER, "Configure Tool");
|
||||
performAction(action, true);
|
||||
waitForSwing();
|
||||
provider = tool.getManagePluginsDialog();
|
||||
pluginManagerComponent = (PluginManagerComponent) getInstanceField("comp", provider);
|
||||
managePluginsDialog = tool.getManagePluginsDialog();
|
||||
pluginManagerComponent =
|
||||
(PluginManagerComponent) getInstanceField("pluginComponent", managePluginsDialog);
|
||||
|
||||
executeOnSwingWithoutBlocking(() -> pluginManagerComponent.manageAllPlugins());
|
||||
installerProvider = waitForDialogComponent(PluginInstallerDialog.class);
|
||||
|
||||
pluginModel = installerProvider.getModel();
|
||||
pluginModel = managePluginsDialog.getPluginConfigurationModel();
|
||||
}
|
||||
}
|
||||
|
@ -70,7 +70,7 @@ import ghidra.util.task.TaskMonitor;
|
||||
//@formatter:on
|
||||
public class FidDebugPlugin extends ProgramPlugin implements ChangeListener {
|
||||
|
||||
private static final String FUNCTION_ID_DEBUG_NAME = "Function ID Debug";
|
||||
static final String FUNCTION_ID_NAME = "Function ID";
|
||||
private static final String MENU_GROUP_2 = "group2";
|
||||
|
||||
private FidService service;
|
||||
@ -132,21 +132,19 @@ public class FidDebugPlugin extends ProgramPlugin implements ChangeListener {
|
||||
}
|
||||
};
|
||||
action.setMenuBarData(new MenuData(
|
||||
new String[] { ToolConstants.MENU_TOOLS, FidPluginPackage.NAME, "Debug Search Window" },
|
||||
new String[] { ToolConstants.MENU_TOOLS, FUNCTION_ID_NAME, "Debug Search Window" },
|
||||
null, MENU_GROUP_2, MenuData.NO_MNEMONIC, "7"));
|
||||
action.setDescription("Open a window to search the FID DBs in debug mode");
|
||||
action.setHelpLocation(
|
||||
new HelpLocation(FidPlugin.FID_HELP, "FunctionIDDebug"));
|
||||
action.setHelpLocation(new HelpLocation(FidPlugin.FID_HELP, "FunctionIDDebug"));
|
||||
tool.addAction(action);
|
||||
|
||||
action = new HashAction(this);
|
||||
action.setMenuBarData(new MenuData(
|
||||
new String[] { ToolConstants.MENU_TOOLS, FidPluginPackage.NAME,
|
||||
new String[] { ToolConstants.MENU_TOOLS, FUNCTION_ID_NAME,
|
||||
"Debug Search Window (Current Function)" },
|
||||
null, MENU_GROUP_2, MenuData.NO_MNEMONIC, "1"));
|
||||
action.setDescription("FidHashes the current function for debug purposes");
|
||||
action.setHelpLocation(
|
||||
new HelpLocation(FidPlugin.FID_HELP, "FunctionIDDebug"));
|
||||
action.setHelpLocation(new HelpLocation(FidPlugin.FID_HELP, "FunctionIDDebug"));
|
||||
tool.addAction(action);
|
||||
|
||||
createRawFileAction = new DockingAction("raw file", getName()) {
|
||||
@ -155,13 +153,15 @@ public class FidDebugPlugin extends ProgramPlugin implements ChangeListener {
|
||||
createRawFile();
|
||||
}
|
||||
};
|
||||
createRawFileAction.setMenuBarData(
|
||||
new MenuData(new String[] { ToolConstants.MENU_TOOLS, FidPluginPackage.NAME,
|
||||
"Create Read-only Database" }, null, MENU_GROUP_2, MenuData.NO_MNEMONIC, "1"));
|
||||
createRawFileAction
|
||||
.setMenuBarData(new MenuData(
|
||||
new String[] { ToolConstants.MENU_TOOLS, FUNCTION_ID_NAME,
|
||||
"Create Read-only Database" },
|
||||
null, MENU_GROUP_2, MenuData.NO_MNEMONIC, "1"));
|
||||
createRawFileAction.setDescription(
|
||||
"Creates a raw read-only database suitable for distribution in the installation directory");
|
||||
createRawFileAction.setHelpLocation(
|
||||
new HelpLocation(FidPlugin.FID_HELP, "FunctionIDDebug"));
|
||||
createRawFileAction
|
||||
.setHelpLocation(new HelpLocation(FidPlugin.FID_HELP, "FunctionIDDebug"));
|
||||
|
||||
tool.addAction(createRawFileAction);
|
||||
}
|
||||
@ -222,8 +222,8 @@ public class FidDebugPlugin extends ProgramPlugin implements ChangeListener {
|
||||
List<FidDbViewerProvider> componentProviders =
|
||||
tool.getWindowManager().getComponentProviders(FidDbViewerProvider.class);
|
||||
for (ComponentProvider comp : componentProviders) {
|
||||
if (((FidDbViewerProvider) comp).fidDB.getPath().equals(
|
||||
fidFile.getPath())) {
|
||||
if (((FidDbViewerProvider) comp).fidDB.getPath()
|
||||
.equals(fidFile.getPath())) {
|
||||
tool.getWindowManager().showComponent(comp, true);
|
||||
return;
|
||||
}
|
||||
@ -239,12 +239,11 @@ public class FidDebugPlugin extends ProgramPlugin implements ChangeListener {
|
||||
}
|
||||
};
|
||||
action.setMenuBarData(new MenuData(new String[] { ToolConstants.MENU_TOOLS,
|
||||
FidPluginPackage.NAME, "Table Viewer", fidFile.getName() }, null, MENU_GROUP_2,
|
||||
FUNCTION_ID_NAME, "Table Viewer", fidFile.getName() }, null, MENU_GROUP_2,
|
||||
MenuData.NO_MNEMONIC, "6"));
|
||||
action.setDescription(
|
||||
"Opens new DB Table Viewer to browse the database in " + fidFile.getName());
|
||||
action.setHelpLocation(
|
||||
new HelpLocation(FidPlugin.FID_HELP, "FunctionIDPlugin"));
|
||||
action.setHelpLocation(new HelpLocation(FidPlugin.FID_HELP, "FunctionIDPlugin"));
|
||||
action.setEnabled(true);
|
||||
if (tool != null) {
|
||||
tool.addAction(action);
|
||||
@ -253,8 +252,7 @@ public class FidDebugPlugin extends ProgramPlugin implements ChangeListener {
|
||||
}
|
||||
// make these appear at the bottom of the Fid Menu.
|
||||
tool.setMenuGroup(
|
||||
new String[] { ToolConstants.MENU_TOOLS, FidPluginPackage.NAME, "Table Viewer" },
|
||||
"zzz");
|
||||
new String[] { ToolConstants.MENU_TOOLS, FUNCTION_ID_NAME, "Table Viewer" }, "zzz");
|
||||
|
||||
}
|
||||
|
||||
|
@ -28,6 +28,8 @@ import docking.action.DockingAction;
|
||||
import docking.action.MenuData;
|
||||
import docking.tool.ToolConstants;
|
||||
import docking.widgets.filechooser.GhidraFileChooser;
|
||||
import docking.widgets.filechooser.GhidraFileChooserMode;
|
||||
import ghidra.app.CorePluginPackage;
|
||||
import ghidra.app.plugin.PluginCategoryNames;
|
||||
import ghidra.app.plugin.ProgramPlugin;
|
||||
import ghidra.app.script.AskDialog;
|
||||
@ -39,7 +41,6 @@ import ghidra.framework.plugintool.PluginTool;
|
||||
import ghidra.framework.plugintool.util.PluginStatus;
|
||||
import ghidra.util.HelpLocation;
|
||||
import ghidra.util.Msg;
|
||||
import ghidra.util.exception.CancelledException;
|
||||
import ghidra.util.exception.DuplicateFileException;
|
||||
|
||||
/**
|
||||
@ -51,17 +52,16 @@ import ghidra.util.exception.DuplicateFileException;
|
||||
//@formatter:off
|
||||
@PluginInfo(
|
||||
status = PluginStatus.RELEASED,
|
||||
packageName = FidPluginPackage.NAME,
|
||||
packageName = CorePluginPackage.NAME,
|
||||
category = PluginCategoryNames.SEARCH,
|
||||
shortDescription = FidPlugin.FUNCTION_ID_NAME,
|
||||
description = "This plugin is for creating and maintaining function identification libraries."
|
||||
)
|
||||
//@formatter:on
|
||||
public class FidPlugin extends ProgramPlugin implements ChangeListener {
|
||||
|
||||
private static final String MENU_GROUP_1 = "group1";
|
||||
|
||||
static final String FUNCTION_ID_NAME = "Function ID";
|
||||
|
||||
public static final String FID_HELP = "FunctionID";
|
||||
|
||||
private FidService service;
|
||||
@ -115,9 +115,9 @@ public class FidPlugin extends ProgramPlugin implements ChangeListener {
|
||||
chooseActiveFidDbs();
|
||||
}
|
||||
};
|
||||
action.setMenuBarData(
|
||||
new MenuData(new String[] { ToolConstants.MENU_TOOLS, FidPluginPackage.NAME,
|
||||
"Choose active FidDbs..." }, null, MENU_GROUP_1, MenuData.NO_MNEMONIC, "1"));
|
||||
action.setMenuBarData(new MenuData(
|
||||
new String[] { ToolConstants.MENU_TOOLS, FUNCTION_ID_NAME, "Choose active FidDbs..." },
|
||||
null, MENU_GROUP_1, MenuData.NO_MNEMONIC, "1"));
|
||||
action.setDescription("Select which FidDbs are used during Fid Search");
|
||||
action.setHelpLocation(new HelpLocation(FID_HELP, "chooseactivemenu"));
|
||||
tool.addAction(action);
|
||||
@ -130,7 +130,7 @@ public class FidPlugin extends ProgramPlugin implements ChangeListener {
|
||||
}
|
||||
};
|
||||
action.setMenuBarData(
|
||||
new MenuData(new String[] { ToolConstants.MENU_TOOLS, FidPluginPackage.NAME,
|
||||
new MenuData(new String[] { ToolConstants.MENU_TOOLS, FUNCTION_ID_NAME,
|
||||
"Create new empty FidDb..." }, null, MENU_GROUP_1, MenuData.NO_MNEMONIC, "2"));
|
||||
action.setDescription("Create a new, empty FidDb file in your file system");
|
||||
action.setHelpLocation(new HelpLocation(FID_HELP, "createemptyfid"));
|
||||
@ -143,9 +143,9 @@ public class FidPlugin extends ProgramPlugin implements ChangeListener {
|
||||
attachFidDb();
|
||||
}
|
||||
};
|
||||
action.setMenuBarData(
|
||||
new MenuData(new String[] { ToolConstants.MENU_TOOLS, FidPluginPackage.NAME,
|
||||
"Attach existing FidDb..." }, null, MENU_GROUP_1, MenuData.NO_MNEMONIC, "3"));
|
||||
action.setMenuBarData(new MenuData(
|
||||
new String[] { ToolConstants.MENU_TOOLS, FUNCTION_ID_NAME, "Attach existing FidDb..." },
|
||||
null, MENU_GROUP_1, MenuData.NO_MNEMONIC, "3"));
|
||||
action.setDescription("Attach an existing FidDb file from your file system");
|
||||
action.setHelpLocation(new HelpLocation(FID_HELP, "attachfid"));
|
||||
tool.addAction(action);
|
||||
@ -157,9 +157,9 @@ public class FidPlugin extends ProgramPlugin implements ChangeListener {
|
||||
removeFidFile();
|
||||
}
|
||||
};
|
||||
action.setMenuBarData(
|
||||
new MenuData(new String[] { ToolConstants.MENU_TOOLS, FidPluginPackage.NAME,
|
||||
"Detach attached FidDb..." }, null, MENU_GROUP_1, MenuData.NO_MNEMONIC, "4"));
|
||||
action.setMenuBarData(new MenuData(
|
||||
new String[] { ToolConstants.MENU_TOOLS, FUNCTION_ID_NAME, "Detach attached FidDb..." },
|
||||
null, MENU_GROUP_1, MenuData.NO_MNEMONIC, "4"));
|
||||
action.setDescription("Detach an already attached FidDb");
|
||||
action.setHelpLocation(new HelpLocation(FID_HELP, "detachfid"));
|
||||
tool.addAction(action);
|
||||
@ -173,7 +173,7 @@ public class FidPlugin extends ProgramPlugin implements ChangeListener {
|
||||
}
|
||||
};
|
||||
action.setMenuBarData(new MenuData(
|
||||
new String[] { ToolConstants.MENU_TOOLS, FidPluginPackage.NAME,
|
||||
new String[] { ToolConstants.MENU_TOOLS, FUNCTION_ID_NAME,
|
||||
"Populate FidDb from programs..." },
|
||||
null, MENU_GROUP_1, MenuData.NO_MNEMONIC, "5"));
|
||||
action.setDescription("Populate an existing FidDb with all programs under a domain folder");
|
||||
@ -266,7 +266,7 @@ public class FidPlugin extends ProgramPlugin implements ChangeListener {
|
||||
final GhidraFileChooser chooser = new GhidraFileChooser(tool.getActiveWindow());
|
||||
chooser.setApproveButtonText(approveButtonText);
|
||||
chooser.setTitle(title);
|
||||
chooser.setFileSelectionMode(GhidraFileChooser.FILES_ONLY);
|
||||
chooser.setFileSelectionMode(GhidraFileChooserMode.FILES_ONLY);
|
||||
return chooser.getSelectedFile();
|
||||
}
|
||||
|
||||
@ -277,7 +277,6 @@ public class FidPlugin extends ProgramPlugin implements ChangeListener {
|
||||
* @param choices array of choices for the users
|
||||
* @param defaultValue the default value to select
|
||||
* @return the user's choice, or null
|
||||
* @throws CancelledException if the user cancels
|
||||
*/
|
||||
private <T> T askChoice(String title, String message, List<T> choices, T defaultValue) {
|
||||
AskDialog<T> dialog =
|
||||
|
@ -1,31 +0,0 @@
|
||||
/* ###
|
||||
* 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.feature.fid.plugin;
|
||||
|
||||
import ghidra.framework.plugintool.util.PluginPackage;
|
||||
import resources.ResourceManager;
|
||||
|
||||
/**
|
||||
* Plugin package for the FID plugin.
|
||||
*/
|
||||
public class FidPluginPackage extends PluginPackage {
|
||||
public static final String NAME = "Function ID";
|
||||
|
||||
public FidPluginPackage() {
|
||||
super(NAME, ResourceManager.loadImage("images/vcard.png"),
|
||||
"These plugins are for creating, maintaining, and debugging function identification libraries.");
|
||||
}
|
||||
}
|
@ -55,13 +55,13 @@ public class DockingDialog extends JDialog implements HelpDescriptor {
|
||||
|
||||
/**
|
||||
* Creates a default parent frame that will appear in the OS's task bar. Having this frame
|
||||
* gives the user something to click when their dialog is lost. We attempt to hide this
|
||||
* gives the user something to click when their dialog is lost. We attempt to hide this
|
||||
* frame offscreen.
|
||||
*
|
||||
*
|
||||
* Note: we expect to only get here when there is no parent window found. This usually
|
||||
* only happens during tests and one-off main methods that are not part of a
|
||||
* only happens during tests and one-off main methods that are not part of a
|
||||
* running tool.
|
||||
*
|
||||
*
|
||||
* @param componentProvider the dialog content for this dialog
|
||||
* @return the hidden frame
|
||||
*/
|
||||
@ -69,7 +69,7 @@ public class DockingDialog extends JDialog implements HelpDescriptor {
|
||||
|
||||
//
|
||||
// Note: we expect to only get here when there is no parent window found. This usually
|
||||
// only happens during tests and one-off main methods that are not part of a
|
||||
// only happens during tests and one-off main methods that are not part of a
|
||||
// running tool
|
||||
//
|
||||
HiddenDockingFrame hiddenFrame = new HiddenDockingFrame(Application.getName());
|
||||
@ -132,8 +132,8 @@ public class DockingDialog extends JDialog implements HelpDescriptor {
|
||||
|
||||
Point initialLocation = component.getIntialLocation();
|
||||
if (initialLocation != null) {
|
||||
// NOTE: have to call setLocation() twice because the first time the native peer
|
||||
// component's location is not actually changed; calling setLocation() again
|
||||
// NOTE: have to call setLocation() twice because the first time the native peer
|
||||
// component's location is not actually changed; calling setLocation() again
|
||||
// does cause the location to change.
|
||||
setLocation(initialLocation);
|
||||
setLocation(initialLocation);
|
||||
@ -286,7 +286,7 @@ public class DockingDialog extends JDialog implements HelpDescriptor {
|
||||
JFrame f = (JFrame) myParent;
|
||||
Window[] ownedWindows = f.getOwnedWindows();
|
||||
for (Window window : ownedWindows) {
|
||||
if (window != this) {
|
||||
if (window != this && window.isVisible()) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
@ -382,7 +382,7 @@ public class DockingDialog extends JDialog implements HelpDescriptor {
|
||||
|
||||
void setEndBounds(Rectangle bounds) {
|
||||
if (Objects.equals(startBounds, bounds)) {
|
||||
// keep the end bounds unchanged, which helps us later determine if the
|
||||
// keep the end bounds unchanged, which helps us later determine if the
|
||||
// dialog was moved
|
||||
return;
|
||||
}
|
||||
|
@ -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…
Reference in New Issue
Block a user