diff --git a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/workflow/ShowInterpreterDebuggerBot.java b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/workflow/ShowInterpreterDebuggerBot.java index ff04d78513..3dcf8978a2 100644 --- a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/workflow/ShowInterpreterDebuggerBot.java +++ b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/workflow/ShowInterpreterDebuggerBot.java @@ -28,11 +28,11 @@ import ghidra.util.Msg; import ghidra.util.Swing; @DebuggerBotInfo( // - description = "Show debugger interpreters", // - details = "Listens for new debuggers supporting the interpreter interface," + - " and when found, displays that interpeter.", // - help = @HelpInfo(anchor = "show_interpreter"), // - enabledByDefault = true // + description = "Show debugger interpreters", // + details = "Listens for new debuggers supporting the interpreter interface," + + " and when found, displays that interpeter.", // + help = @HelpInfo(anchor = "show_interpreter"), // + enabledByDefault = true // ) public class ShowInterpreterDebuggerBot implements DebuggerBot { private DebuggerWorkflowServicePlugin plugin; diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/merge/MergeManager.java b/Ghidra/Features/Base/src/main/java/ghidra/app/merge/MergeManager.java index 2d255499b5..8edab3c4ad 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/merge/MergeManager.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/merge/MergeManager.java @@ -26,8 +26,7 @@ import generic.util.WindowUtilities; import ghidra.framework.data.DomainObjectMergeManager; import ghidra.framework.model.DomainFile; import ghidra.framework.model.UndoableDomainObject; -import ghidra.framework.plugintool.ModalPluginTool; -import ghidra.framework.plugintool.PluginTool; +import ghidra.framework.plugintool.*; import ghidra.framework.plugintool.util.PluginException; import ghidra.program.model.listing.DomainObjectChangeSet; import ghidra.util.*; @@ -502,7 +501,7 @@ public abstract class MergeManager implements DomainObjectMergeManager { if (mergePlugin != null) { mergePlugin.dispose(); } - mergeTool.exit(); // cleanup! + PluginToolAccessUtils.dispose(mergeTool); // cleanup! mergeTool = null; }); } diff --git a/Ghidra/Features/Base/src/main/java/ghidra/test/TestTool.java b/Ghidra/Features/Base/src/main/java/ghidra/test/TestTool.java index 0b5bdbc056..db8e0cf423 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/test/TestTool.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/test/TestTool.java @@ -42,7 +42,7 @@ public class TestTool extends GhidraTool { } Runnable r = () -> { - exit(); + dispose(); if (getProject().getToolServices() != null) { getProject().getToolServices().closeTool(TestTool.this); } diff --git a/Ghidra/Features/VersionTracking/src/main/java/ghidra/feature/vt/gui/plugin/VTSubToolManager.java b/Ghidra/Features/VersionTracking/src/main/java/ghidra/feature/vt/gui/plugin/VTSubToolManager.java index e7e4b1dd14..7b87f176d9 100644 --- a/Ghidra/Features/VersionTracking/src/main/java/ghidra/feature/vt/gui/plugin/VTSubToolManager.java +++ b/Ghidra/Features/VersionTracking/src/main/java/ghidra/feature/vt/gui/plugin/VTSubToolManager.java @@ -336,8 +336,8 @@ public class VTSubToolManager implements VTControllerListener, OptionsChangeList saveSubordinateToolConfig(sourceTool); saveSubordinateToolConfig(destinationTool); pluginList.clear(); - sourceTool.exit(); - destinationTool.exit(); + PluginToolAccessUtils.dispose(sourceTool); + PluginToolAccessUtils.dispose(destinationTool); sourceTool = null; destinationTool = null; } diff --git a/Ghidra/Framework/Project/src/main/java/ghidra/framework/main/AppInfo.java b/Ghidra/Framework/Project/src/main/java/ghidra/framework/main/AppInfo.java index c3fec12cae..17e89cbf9d 100644 --- a/Ghidra/Framework/Project/src/main/java/ghidra/framework/main/AppInfo.java +++ b/Ghidra/Framework/Project/src/main/java/ghidra/framework/main/AppInfo.java @@ -46,7 +46,7 @@ public class AppInfo { public static void exitGhidra() { assertFrontEndRunning(); - tool.exit(); + tool.close(); // closing the front end tool will exit the application } private static void assertFrontEndRunning() { diff --git a/Ghidra/Framework/Project/src/main/java/ghidra/framework/main/FileActionManager.java b/Ghidra/Framework/Project/src/main/java/ghidra/framework/main/FileActionManager.java index 8b2f82f033..04dea7803d 100644 --- a/Ghidra/Framework/Project/src/main/java/ghidra/framework/main/FileActionManager.java +++ b/Ghidra/Framework/Project/src/main/java/ghidra/framework/main/FileActionManager.java @@ -35,6 +35,7 @@ import ghidra.framework.client.RepositoryAdapter; import ghidra.framework.model.*; import ghidra.framework.options.SaveState; import ghidra.framework.plugintool.PluginTool; +import ghidra.framework.plugintool.PluginToolAccessUtils; import ghidra.framework.store.LockException; import ghidra.util.*; import ghidra.util.exception.NotFoundException; @@ -123,7 +124,7 @@ class FileActionManager { closeProjectAction = new DockingAction("Close Project", plugin.getName()) { @Override public void actionPerformed(ActionContext context) { - closeProject(false); //not exiting + closeProject(false); // not exiting } }; closeProjectAction.setEnabled(false); @@ -187,7 +188,7 @@ class FileActionManager { // if all is well and we already have an active project, close it Project activeProject = plugin.getActiveProject(); if (activeProject != null) { - if (!closeProject(false)) { // false -->not exiting + if (!closeProject(false)) { // false --> not exiting return; // user canceled } } @@ -428,7 +429,7 @@ class FileActionManager { // check for any changes since last saved PluginTool[] runningTools = activeProject.getToolManager().getRunningTools(); for (PluginTool runningTool : runningTools) { - if (!runningTool.canClose(isExiting)) { + if (!PluginToolAccessUtils.canClose(runningTool)) { return false; } } diff --git a/Ghidra/Framework/Project/src/main/java/ghidra/framework/main/FrontEndPlugin.java b/Ghidra/Framework/Project/src/main/java/ghidra/framework/main/FrontEndPlugin.java index 9272251a94..a2e6a5c606 100644 --- a/Ghidra/Framework/Project/src/main/java/ghidra/framework/main/FrontEndPlugin.java +++ b/Ghidra/Framework/Project/src/main/java/ghidra/framework/main/FrontEndPlugin.java @@ -445,23 +445,7 @@ public class FrontEndPlugin extends Plugin projectDataPanel.readDataState(saveState); } - /** - * Exit the Ghidra application; the parameter indicates whether - * the user should be prompted to save the project that is about - * to be closed - */ - void exitGhidra() { - boolean okToExit = closeActiveProject(); - if (okToExit) { - System.exit(0); - - } - else if (!tool.isVisible()) { - tool.setVisible(true); - } - } - - private boolean closeActiveProject() { + boolean closeActiveProject() { if (activeProject == null) { return true; } @@ -470,7 +454,7 @@ public class FrontEndPlugin extends Plugin } catch (Exception e) { Msg.error(this, "Unexpected Exception: " + e.getMessage(), e); // Keep this. - int result = OptionDialog.showOptionDialog(tool.getToolFrame(), "Close Project Failed", + int result = OptionDialog.showOptionDialog(null, "Close Project Failed", "Error Description: [ " + e + " ]" + "\n" + "=====> Do you wish to exit Ghidra, possibly losing changes? <=====", "Exit Ghidra (Possibly Lose Changes)", OptionDialog.ERROR_MESSAGE); diff --git a/Ghidra/Framework/Project/src/main/java/ghidra/framework/main/FrontEndTool.java b/Ghidra/Framework/Project/src/main/java/ghidra/framework/main/FrontEndTool.java index 11dd1d1a49..44000e7246 100644 --- a/Ghidra/Framework/Project/src/main/java/ghidra/framework/main/FrontEndTool.java +++ b/Ghidra/Framework/Project/src/main/java/ghidra/framework/main/FrontEndTool.java @@ -166,12 +166,17 @@ public class FrontEndTool extends PluginTool implements OptionsChangeListener { } @Override - protected void dispose() { + public void dispose() { super.dispose(); if (logProvider != null) { logProvider.dispose(); } + shutdown(); + } + + protected void shutdown() { + System.exit(0); } private void ensureSize() { @@ -392,13 +397,8 @@ public class FrontEndTool extends PluginTool implements OptionsChangeListener { } @Override - public void exit() { - plugin.exitGhidra(); - } - - @Override - public void close() { - close(true); + public boolean canClose() { + return super.canClose() && plugin.closeActiveProject(); } /** diff --git a/Ghidra/Framework/Project/src/main/java/ghidra/framework/main/ProjectInfoDialog.java b/Ghidra/Framework/Project/src/main/java/ghidra/framework/main/ProjectInfoDialog.java index feacb4ff20..2f1bb07961 100644 --- a/Ghidra/Framework/Project/src/main/java/ghidra/framework/main/ProjectInfoDialog.java +++ b/Ghidra/Framework/Project/src/main/java/ghidra/framework/main/ProjectInfoDialog.java @@ -38,6 +38,7 @@ import ghidra.framework.data.ConvertFileSystem; import ghidra.framework.data.TransientDataManager; import ghidra.framework.model.*; import ghidra.framework.plugintool.PluginTool; +import ghidra.framework.plugintool.PluginToolAccessUtils; import ghidra.framework.remote.User; import ghidra.framework.store.local.*; import ghidra.util.*; @@ -95,9 +96,9 @@ public class ProjectInfoDialog extends DialogComponentProvider { connectionButton.setContentAreaFilled(false); connectionButton.setSelected(isConnected); - connectionButton.setBorder( - isConnected ? BorderFactory.createBevelBorder(BevelBorder.LOWERED) - : BorderFactory.createBevelBorder(BevelBorder.RAISED)); + connectionButton + .setBorder(isConnected ? BorderFactory.createBevelBorder(BevelBorder.LOWERED) + : BorderFactory.createBevelBorder(BevelBorder.RAISED)); updateConnectButtonToolTip(); if (isConnected) { try { @@ -181,8 +182,8 @@ public class ProjectInfoDialog extends DialogComponentProvider { String toolTipForChange = "Change server information or specify another repository."; String toolTipForConvert = "Convert project to be a shared project."; - changeConvertButton.setToolTipText( - repository != null ? toolTipForChange : toolTipForConvert); + changeConvertButton + .setToolTipText(repository != null ? toolTipForChange : toolTipForConvert); Class fsClass = project.getProjectData().getLocalStorageClass(); String convertStorageButtonLabel = null; @@ -198,8 +199,8 @@ public class ProjectInfoDialog extends DialogComponentProvider { convertStorageButton.addActionListener(e -> convertToIndexedFilesystem()); help.registerHelp(changeConvertButton, new HelpLocation(GenericHelpTopics.FRONT_END, "Convert_Project_Storage")); - convertStorageButton.setToolTipText( - "Convert/Upgrade project storage to latest Indexed Filesystem"); + convertStorageButton + .setToolTipText("Convert/Upgrade project storage to latest Indexed Filesystem"); } JPanel p = new JPanel(new FlowLayout()); @@ -260,9 +261,9 @@ public class ProjectInfoDialog extends DialogComponentProvider { connectionButton.setName("Connect Button"); connectionButton.setContentAreaFilled(false); connectionButton.setSelected(isConnected); - connectionButton.setBorder( - isConnected ? BorderFactory.createBevelBorder(BevelBorder.LOWERED) - : BorderFactory.createBevelBorder(BevelBorder.RAISED)); + connectionButton + .setBorder(isConnected ? BorderFactory.createBevelBorder(BevelBorder.LOWERED) + : BorderFactory.createBevelBorder(BevelBorder.RAISED)); updateConnectButtonToolTip(); HelpService help = Help.getHelpService(); help.registerHelp(connectionButton, @@ -343,8 +344,7 @@ public class ProjectInfoDialog extends DialogComponentProvider { private void updateSharedProjectInfo() { int openCount = getOpenFileCount(); if (openCount != 0) { - Msg.showInfo(getClass(), getComponent(), - "Cannot Change Project Info with Open Files", + Msg.showInfo(getClass(), getComponent(), "Cannot Change Project Info with Open Files", "Found " + openCount + " open project file(s).\n" + "Before your project info can be updated, you must\n" + "close all open project files and tools."); @@ -392,7 +392,7 @@ public class ProjectInfoDialog extends DialogComponentProvider { private boolean checkToolsClose() { PluginTool[] runningTools = project.getToolManager().getRunningTools(); for (PluginTool runningTool : runningTools) { - if (!runningTool.canClose(false)) { + if (!PluginToolAccessUtils.canClose(runningTool)) { return false; } runningTool.close(); @@ -448,8 +448,7 @@ public class ProjectInfoDialog extends DialogComponentProvider { int openCount = getOpenFileCount(); if (openCount != 0) { - Msg.showInfo(getClass(), getComponent(), - "Cannot Convert Project with Open Files", + Msg.showInfo(getClass(), getComponent(), "Cannot Convert Project with Open Files", "Found " + openCount + " open project file(s).\n" + "Before your project can be converted, you must close\n" + "all open project files and tools."); diff --git a/Ghidra/Framework/Project/src/main/java/ghidra/framework/main/SaveDataDialog.java b/Ghidra/Framework/Project/src/main/java/ghidra/framework/main/SaveDataDialog.java index 213b92c76c..29952b28f1 100644 --- a/Ghidra/Framework/Project/src/main/java/ghidra/framework/main/SaveDataDialog.java +++ b/Ghidra/Framework/Project/src/main/java/ghidra/framework/main/SaveDataDialog.java @@ -126,8 +126,8 @@ public class SaveDataDialog extends DialogComponentProvider { } } if (list.size() > 0) { - DomainFile[] deleteFiles = new DomainFile[list.size()]; - SaveTask task = new SaveTask(list.toArray(deleteFiles)); + DomainFile[] saveFiles = new DomainFile[list.size()]; + SaveTask task = new SaveTask(list.toArray(saveFiles)); new TaskLauncher(task, getComponent()); } else { diff --git a/Ghidra/Framework/Project/src/main/java/ghidra/framework/main/TestFrontEndTool.java b/Ghidra/Framework/Project/src/main/java/ghidra/framework/main/TestFrontEndTool.java index 921ed9437a..ab324df7e6 100644 --- a/Ghidra/Framework/Project/src/main/java/ghidra/framework/main/TestFrontEndTool.java +++ b/Ghidra/Framework/Project/src/main/java/ghidra/framework/main/TestFrontEndTool.java @@ -28,6 +28,12 @@ public class TestFrontEndTool extends FrontEndTool { @Override public void close() { - setVisible(false); + // overridden to not ask to save + dispose(); + } + + @Override + protected void shutdown() { + // let test environment bring the system down } } diff --git a/Ghidra/Framework/Project/src/main/java/ghidra/framework/plugintool/PluginTool.java b/Ghidra/Framework/Project/src/main/java/ghidra/framework/plugintool/PluginTool.java index 67a7db337b..303eac34cc 100644 --- a/Ghidra/Framework/Project/src/main/java/ghidra/framework/plugintool/PluginTool.java +++ b/Ghidra/Framework/Project/src/main/java/ghidra/framework/plugintool/PluginTool.java @@ -492,10 +492,6 @@ public abstract class PluginTool extends AbstractDockingTool { return eventMgr.hasToolListeners(); } - public void exit() { - dispose(); - } - protected void dispose() { isDisposed = true; @@ -525,6 +521,7 @@ public abstract class PluginTool extends AbstractDockingTool { disposeManagers(); winMgr.dispose(); + toolServices.closeTool(this); } private void disposeManagers() { @@ -1148,46 +1145,80 @@ public abstract class PluginTool extends AbstractDockingTool { } /** - * Close this tool: + * Closes this tool, possibly with input from the user. The following conditions are checked + * and can prompt the user for more info and allow them to cancel the close. *
    - *
  1. if there are no tasks running. - *
  2. resolve the state of any plugins so they can be closed. - *
  3. Prompt the user to save any changes. - *
  4. close all associated plugins (this closes the domain object if one is open). - *
  5. pop up dialog to save the configuration if it has changed. - *
  6. notify the project tool services that this tool is going away. + *
  7. Running tasks. Closing with running tasks could lead to data loss. + *
  8. Plugins get asked if they can be closed. They may prompt the user to resolve + * some plugin specific state. + *
  9. The user is prompted to save any data changes. + *
  10. Tools are saved, possibly asking the user to resolve any conflicts caused by + * changing multiple instances of the same tool in different ways. + *
  11. If all the above conditions passed, the tool is closed and disposed. *
*/ @Override public void close() { - close(false); + if (canClose()) { + dispose(); + } } - protected void close(boolean isExiting) { - if (canClose(isExiting) && pluginMgr.saveData()) { - doClose(); + protected boolean canClose() { + if (isBusy()) { + return false; } + if (!canClosePlugins()) { + return false; + } + if (!pluginMgr.saveData()) { + return false; + } + return doSaveTool(); } /** - * Close this tool: - *
    - *
  1. if there are no tasks running. - *
  2. close all associated plugins (this closes the domain object if one is open). - *
  3. pop up dialog to save the configuration if it has changed; - *
  4. notify the project tool services that this tool is going away. - *
+ * Normally, tools are not allowed to close while tasks are running in that tool as it + * could leave the application in an unstable state. Tools that exit the application + * (such as the FrontEndTool) can override this so that the user can terminate running tasks + * and not have that prevent exiting the application. + * @return whether the user is allowed to terminate tasks so that the tool can be closed. */ - private void doClose() { - - if (!doSaveTool()) { - return; // if cancelled, don't close - } - - exit(); - toolServices.closeTool(this); + protected boolean allowTerminatingTasksWhenClosing() { + return false; } + /** + * Checks if this tool's plugins are in a state to be closed. + * @return true if all the plugins in the tool can be closed without further user input. + */ + protected boolean canClosePlugins() { + return pluginMgr.canClose(); + } + + /** + * Checks if this tool has running tasks, with optionally giving the user an + * opportunity to cancel them. + * + * @return true if this tool has running tasks + */ + protected boolean isBusy() { + if (taskMgr.isBusy()) { + int result = OptionDialog.showYesNoDialog(getToolFrame(), "Tool Busy Executing Task", + "The tool is busy performing a background task.\n If you continue the" + + " task may be terminated and some work may be lost!\n\nContinue anyway?"); + if (result != OptionDialog.YES_OPTION) { + return true; + } + taskMgr.stop(false); + } + return false; + } + + /** + * Returns true if this tool needs saving + * @return true if this tool needs saving + */ public boolean shouldSave() { return hasConfigChanged(); // ignore the window layout changes } @@ -1224,41 +1255,6 @@ public abstract class PluginTool extends AbstractDockingTool { return true; } - /** - * Can this tool be closed? - *
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. - */ - public boolean canClose(boolean isExiting) { - if (taskMgr.isBusy()) { - if (isExiting) { - int result = OptionDialog.showYesNoDialog(getToolFrame(), - "Tool Busy Executing Task", - "The tool is busy performing a background task.\n If you continue the" + - " task may be terminated and some work may be lost!\n\nContinue anyway?"); - if (result == OptionDialog.NO_OPTION) { - return false; - } - taskMgr.stop(false); - } - else { - beep(); - Msg.showInfo(getClass(), getToolFrame(), "Tool Busy", - "You must stop all background tasks before tool may close."); - return false; - } - } - if (!pluginMgr.canClose()) { - return false; - } - return true; - } - /** * Can the domain object be closed? *
Note: This forces plugins to terminate any tasks they have running for the diff --git a/Ghidra/Framework/Project/src/main/java/ghidra/framework/plugintool/PluginToolAccessUtils.java b/Ghidra/Framework/Project/src/main/java/ghidra/framework/plugintool/PluginToolAccessUtils.java new file mode 100644 index 0000000000..011a2ceac3 --- /dev/null +++ b/Ghidra/Framework/Project/src/main/java/ghidra/framework/plugintool/PluginToolAccessUtils.java @@ -0,0 +1,48 @@ +/* ### + * 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; + +/** + * Utility class to provide access to non-public methods on PluginTool. There are a number of + * methods that internal classes need access to but we don't want on the public interface of + * PluginTool.This is a stopgap approach until we clean up the package structure for tool related + * classes and interfaces. This class should only be used by internal tool manager classes. + */ +public class PluginToolAccessUtils { + + private PluginToolAccessUtils() { + // Can't be constructed + } + + /** + * Disposes the tool. + * @param tool the tool to dispose + */ + public static void dispose(PluginTool tool) { + tool.dispose(); + } + + /** + * Returns true if the tool can be closed. Note this does not handle any data saving. It only + * checks that there are no tasks running and the plugins can be closed. + * @param tool the tool to close + * @return true if the tool can be closed + */ + public static boolean canClose(PluginTool tool) { + return !tool.isBusy() && tool.canClosePlugins(); + } + +} diff --git a/Ghidra/Framework/Project/src/main/java/ghidra/framework/project/DefaultProject.java b/Ghidra/Framework/Project/src/main/java/ghidra/framework/project/DefaultProject.java index 71b72a1790..77e2c3d51f 100644 --- a/Ghidra/Framework/Project/src/main/java/ghidra/framework/project/DefaultProject.java +++ b/Ghidra/Framework/Project/src/main/java/ghidra/framework/project/DefaultProject.java @@ -303,8 +303,7 @@ public class DefaultProject implements Project { ProjectFileManager projectData = (ProjectFileManager) c.getProjectData(); if (projectData == null) { throw new IOException( - "Failed to view specified project/repository: " + - GhidraURL.getDisplayString(url)); + "Failed to view specified project/repository: " + GhidraURL.getDisplayString(url)); } url = projectData.getProjectLocator().getURL(); // transform to repository root URL @@ -423,7 +422,6 @@ public class DefaultProject implements Project { try { if (toolManager != null) { - toolManager.close(); toolManager.dispose(); } if (projectManager != null) { diff --git a/Ghidra/Framework/Project/src/main/java/ghidra/framework/project/tool/GhidraTool.java b/Ghidra/Framework/Project/src/main/java/ghidra/framework/project/tool/GhidraTool.java index 4c289b57a9..2a4584ed73 100644 --- a/Ghidra/Framework/Project/src/main/java/ghidra/framework/project/tool/GhidraTool.java +++ b/Ghidra/Framework/Project/src/main/java/ghidra/framework/project/tool/GhidraTool.java @@ -167,12 +167,12 @@ public class GhidraTool extends PluginTool { } @Override - public void exit() { + public void dispose() { if (fileOpenDropHandler != null) { fileOpenDropHandler.dispose(); fileOpenDropHandler = null; } - super.exit(); + super.dispose(); } private void addCloseAction() { diff --git a/Ghidra/Framework/Project/src/main/java/ghidra/framework/project/tool/ToolManagerImpl.java b/Ghidra/Framework/Project/src/main/java/ghidra/framework/project/tool/ToolManagerImpl.java index 22943a5e60..cebca6420a 100644 --- a/Ghidra/Framework/Project/src/main/java/ghidra/framework/project/tool/ToolManagerImpl.java +++ b/Ghidra/Framework/Project/src/main/java/ghidra/framework/project/tool/ToolManagerImpl.java @@ -375,16 +375,6 @@ public class ToolManagerImpl implements ToolManager, PropertyChangeListener { return ((changedWorkspaces.size() > 0) || activeWorkspaceChanged); } - /** - * Close all running tools in the project. - */ - public void close() { - for (Workspace element : workspaces) { - WorkspaceImpl w = (WorkspaceImpl) element; - w.close(); - } - } - /** * Save the tools that are opened and changed, that will be brought back up when the project * is reopened @@ -445,6 +435,10 @@ public class ToolManagerImpl implements ToolManager, PropertyChangeListener { } public void dispose() { + for (Workspace element : workspaces) { + WorkspaceImpl w = (WorkspaceImpl) element; + w.dispose(); + } toolServices.dispose(); } diff --git a/Ghidra/Framework/Project/src/main/java/ghidra/framework/project/tool/WorkspaceImpl.java b/Ghidra/Framework/Project/src/main/java/ghidra/framework/project/tool/WorkspaceImpl.java index 3068502134..7f4a63fcda 100644 --- a/Ghidra/Framework/Project/src/main/java/ghidra/framework/project/tool/WorkspaceImpl.java +++ b/Ghidra/Framework/Project/src/main/java/ghidra/framework/project/tool/WorkspaceImpl.java @@ -15,13 +15,16 @@ */ package ghidra.framework.project.tool; -import java.util.*; +import java.util.Iterator; +import java.util.Set; +import java.util.concurrent.CopyOnWriteArraySet; import org.jdom.Element; import ghidra.framework.model.ToolTemplate; import ghidra.framework.model.Workspace; import ghidra.framework.plugintool.PluginTool; +import ghidra.framework.plugintool.PluginToolAccessUtils; import ghidra.util.exception.DuplicateNameException; /** @@ -31,11 +34,10 @@ import ghidra.util.exception.DuplicateNameException; * */ class WorkspaceImpl implements Workspace { - private final static int TYPICAL_NUM_RUNNING_TOOLS = 5; private String name; private ToolManagerImpl toolManager; - private Set runningTools = new HashSet(TYPICAL_NUM_RUNNING_TOOLS); + private Set runningTools = new CopyOnWriteArraySet<>(); private boolean isActive; WorkspaceImpl(String name, ToolManagerImpl toolManager) { @@ -223,14 +225,9 @@ class WorkspaceImpl implements Workspace { * Close all running tools; called from the close() method in * ToolManagerImpl which is called from the Project's close() */ - void close() { + void dispose() { for (PluginTool tool : runningTools) { - try { - tool.exit(); - } - finally { - toolManager.toolRemoved(this, tool); - } + PluginToolAccessUtils.dispose(tool); } runningTools.clear(); } diff --git a/Ghidra/Framework/SoftwareModeling/src/test/java/ghidra/test/DummyTool.java b/Ghidra/Framework/SoftwareModeling/src/test/java/ghidra/test/DummyTool.java index 1b0931a9dc..f722afcd1c 100644 --- a/Ghidra/Framework/SoftwareModeling/src/test/java/ghidra/test/DummyTool.java +++ b/Ghidra/Framework/SoftwareModeling/src/test/java/ghidra/test/DummyTool.java @@ -64,17 +64,11 @@ public class DummyTool extends PluginTool { name = typeName; } - @Override - public void exit() { - //do nothing - } - @Override public void close() { if (project != null) { project.getToolServices().closeTool(this); } - } @Override @@ -266,7 +260,7 @@ public class DummyTool extends PluginTool { } @Override - public boolean canClose(boolean isExiting) { + public boolean canClose() { return true; }