diff --git a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/AbstractDebuggerMapProposalDialog.java b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/AbstractDebuggerMapProposalDialog.java index 4eadc04aba..9eeaf700b6 100644 --- a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/AbstractDebuggerMapProposalDialog.java +++ b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/AbstractDebuggerMapProposalDialog.java @@ -20,13 +20,13 @@ import java.util.Collection; import javax.swing.*; -import docking.DialogComponentProvider; +import docking.ReusableDialogComponentProvider; import docking.widgets.table.EnumeratedColumnTableModel; import docking.widgets.table.GTable; import ghidra.framework.plugintool.PluginTool; import ghidra.util.table.GhidraTableFilterPanel; -public abstract class AbstractDebuggerMapProposalDialog extends DialogComponentProvider { +public abstract class AbstractDebuggerMapProposalDialog extends ReusableDialogComponentProvider { protected final EnumeratedColumnTableModel tableModel; protected GTable table; diff --git a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/DebuggerBlockChooserDialog.java b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/DebuggerBlockChooserDialog.java index b1b5923df9..f16cce9eac 100644 --- a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/DebuggerBlockChooserDialog.java +++ b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/DebuggerBlockChooserDialog.java @@ -24,7 +24,7 @@ import javax.swing.*; import javax.swing.table.TableColumn; import javax.swing.table.TableColumnModel; -import docking.DialogComponentProvider; +import docking.ReusableDialogComponentProvider; import docking.widgets.table.*; import docking.widgets.table.ColumnSortState.SortDirection; import docking.widgets.table.DefaultEnumeratedColumnTableModel.EnumeratedTableColumn; @@ -38,7 +38,7 @@ import ghidra.trace.model.memory.TraceMemoryRegion; import ghidra.trace.model.modules.TraceSection; import ghidra.util.table.GhidraTableFilterPanel; -public class DebuggerBlockChooserDialog extends DialogComponentProvider { +public class DebuggerBlockChooserDialog extends ReusableDialogComponentProvider { public static class MemoryBlockRow { private final Program program; private final MemoryBlock block; diff --git a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/action/DebuggerGoToTrait.java b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/action/DebuggerGoToTrait.java index b10c0fba4f..4cdea1eed0 100644 --- a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/action/DebuggerGoToTrait.java +++ b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/action/DebuggerGoToTrait.java @@ -42,14 +42,10 @@ public abstract class DebuggerGoToTrait { protected DebuggerCoordinates current = DebuggerCoordinates.NOWHERE; - protected final DebuggerGoToDialog goToDialog; - public DebuggerGoToTrait(PluginTool tool, Plugin plugin, ComponentProvider provider) { this.tool = tool; this.plugin = plugin; this.provider = provider; - - goToDialog = new DebuggerGoToDialog(this); } protected abstract boolean goToAddress(Address address); @@ -68,6 +64,7 @@ public abstract class DebuggerGoToTrait { } private void activatedGoTo(ActionContext context) { + DebuggerGoToDialog goToDialog = new DebuggerGoToDialog(this); TracePlatform platform = current.getPlatform(); goToDialog.show((SleighLanguage) platform.getLanguage()); } diff --git a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/copying/DebuggerCopyActionsPlugin.java b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/copying/DebuggerCopyActionsPlugin.java index 13b408c549..3a920f6c63 100644 --- a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/copying/DebuggerCopyActionsPlugin.java +++ b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/copying/DebuggerCopyActionsPlugin.java @@ -32,6 +32,7 @@ import ghidra.program.util.ProgramSelection; import ghidra.trace.model.program.TraceProgramView; import ghidra.trace.model.program.TraceVariableSnapProgramView; +//@formatter:off @PluginInfo( shortDescription = "Copy and export trace data", description = "Provides tool actions for moving data from traces to various destinations.", @@ -45,6 +46,7 @@ import ghidra.trace.model.program.TraceVariableSnapProgramView; ProgramManager.class, }, servicesProvided = {}) +//@formatter:on public class DebuggerCopyActionsPlugin extends AbstractDebuggerPlugin { protected static ProgramSelection getSelectionFromContext(ActionContext context) { @@ -75,6 +77,13 @@ public class DebuggerCopyActionsPlugin extends AbstractDebuggerPlugin { createActions(); } + @Override + protected void dispose() { + super.dispose(); + + copyDialog.dispose(); + } + protected void createActions() { actionExportView = ExportTraceViewAction.builder(this) .enabled(false) diff --git a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/copying/DebuggerCopyIntoProgramDialog.java b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/copying/DebuggerCopyIntoProgramDialog.java index b7eb817b9c..576d032064 100644 --- a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/copying/DebuggerCopyIntoProgramDialog.java +++ b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/copying/DebuggerCopyIntoProgramDialog.java @@ -27,7 +27,7 @@ import javax.swing.*; import javax.swing.table.TableColumn; import javax.swing.table.TableColumnModel; -import docking.DialogComponentProvider; +import docking.ReusableDialogComponentProvider; import docking.widgets.table.*; import docking.widgets.table.DefaultEnumeratedColumnTableModel.EnumeratedTableColumn; import ghidra.app.plugin.core.debug.DebuggerCoordinates; @@ -52,7 +52,7 @@ import ghidra.util.exception.CancelledException; import ghidra.util.table.GhidraTableFilterPanel; import ghidra.util.task.*; -public class DebuggerCopyIntoProgramDialog extends DialogComponentProvider { +public class DebuggerCopyIntoProgramDialog extends ReusableDialogComponentProvider { static final int GAP = 5; static final int BUTTON_SIZE = 32; diff --git a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/memory/DebuggerRegionsPlugin.java b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/memory/DebuggerRegionsPlugin.java index 65330bf4b7..f67605e963 100644 --- a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/memory/DebuggerRegionsPlugin.java +++ b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/memory/DebuggerRegionsPlugin.java @@ -24,6 +24,7 @@ import ghidra.app.services.*; import ghidra.framework.plugintool.*; import ghidra.framework.plugintool.util.PluginStatus; +//@formatter:off @PluginInfo( shortDescription = "Debugger regions manager", description = "GUI to manage memory regions", @@ -42,6 +43,7 @@ import ghidra.framework.plugintool.util.PluginStatus; DebuggerTraceManagerService.class, ProgramManager.class, }) +//@formatter:on public class DebuggerRegionsPlugin extends AbstractDebuggerPlugin { protected DebuggerRegionsProvider provider; @@ -58,6 +60,7 @@ public class DebuggerRegionsPlugin extends AbstractDebuggerPlugin { @Override protected void dispose() { tool.removeComponentProvider(provider); + provider.dispose(); super.dispose(); } diff --git a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/memory/DebuggerRegionsProvider.java b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/memory/DebuggerRegionsProvider.java index 3c65bf5065..d11c6e6c5c 100644 --- a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/memory/DebuggerRegionsProvider.java +++ b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/memory/DebuggerRegionsProvider.java @@ -204,6 +204,11 @@ public class DebuggerRegionsProvider extends ComponentProviderAdapter { createActions(); } + void dispose() { + blockChooserDialog.dispose(); + regionProposalDialog.dispose(); + } + protected void buildMainPanel() { panel = new DebuggerRegionsPanel(this); mainPanel.add(panel); diff --git a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/modules/DebuggerAddMappingDialog.java b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/modules/DebuggerAddMappingDialog.java index ebfa9a57dd..b7da3b86e4 100644 --- a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/modules/DebuggerAddMappingDialog.java +++ b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/modules/DebuggerAddMappingDialog.java @@ -23,7 +23,7 @@ import java.math.BigInteger; import javax.swing.*; import javax.swing.border.EmptyBorder; -import docking.DialogComponentProvider; +import docking.ReusableDialogComponentProvider; import docking.widgets.model.GAddressRangeField; import docking.widgets.model.GSpanField; import ghidra.app.services.DebuggerStaticMappingService; @@ -36,7 +36,7 @@ import ghidra.trace.model.modules.TraceConflictedMappingException; import ghidra.util.MathUtilities; import ghidra.util.layout.PairLayout; -public class DebuggerAddMappingDialog extends DialogComponentProvider { +public class DebuggerAddMappingDialog extends ReusableDialogComponentProvider { private static final String HEX_BIT64 = "0x" + BigInteger.ONE.shiftLeft(64).toString(16); private DebuggerStaticMappingService mappingService; diff --git a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/modules/DebuggerModulesProvider.java b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/modules/DebuggerModulesProvider.java index ab2c663686..d05e1cfdc9 100644 --- a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/modules/DebuggerModulesProvider.java +++ b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/modules/DebuggerModulesProvider.java @@ -418,7 +418,6 @@ public class DebuggerModulesProvider extends ComponentProviderAdapter { private final DebuggerBlockChooserDialog blockChooserDialog; private final DebuggerModuleMapProposalDialog moduleProposalDialog; private final DebuggerSectionMapProposalDialog sectionProposalDialog; - private DataTreeDialog programChooserDialog; // Already lazy private DebuggerCoordinates current = DebuggerCoordinates.NOWHERE; private Program currentProgram; @@ -470,6 +469,7 @@ public class DebuggerModulesProvider extends ComponentProviderAdapter { GhidraFileChooser chooser = new GhidraFileChooser(getComponent()); chooser.setSelectedFile(new File(module.getName())); File file = chooser.getSelectedFile(); + chooser.dispose(); if (file == null) { // Perhaps cancelled return; } @@ -511,6 +511,10 @@ public class DebuggerModulesProvider extends ComponentProviderAdapter { consoleService.removeResolutionAction(actionMapMissingModule); } } + + blockChooserDialog.dispose(); + moduleProposalDialog.dispose(); + sectionProposalDialog.dispose(); } @Override @@ -1071,27 +1075,24 @@ public class DebuggerModulesProvider extends ComponentProviderAdapter { } private DataTreeDialog getProgramChooserDialog() { - if (programChooserDialog != null) { - return programChooserDialog; - } + DomainFileFilter filter = df -> Program.class.isAssignableFrom(df.getDomainObjectClass()); // TODO regarding the hack note below, I believe it's fixed, but not sure how to test - return programChooserDialog = - new DataTreeDialog(null, "Map Module to Program", DataTreeDialog.OPEN, filter) { - { // TODO/HACK: I get an NPE setting the default selection if I don't fake this. - dialogShown(); - } - }; + return new DataTreeDialog(null, "Map Module to Program", DataTreeDialog.OPEN, filter) { + { // TODO/HACK: I get an NPE setting the default selection if I don't fake this. + dialogShown(); + } + }; } public DomainFile askProgram(Program program) { - getProgramChooserDialog(); + DataTreeDialog dialog = getProgramChooserDialog(); if (program != null) { - programChooserDialog.selectDomainFile(program.getDomainFile()); + dialog.selectDomainFile(program.getDomainFile()); } - tool.showDialog(programChooserDialog); - return programChooserDialog.getDomainFile(); + tool.showDialog(dialog); + return dialog.getDomainFile(); } public Entry askBlock(TraceSection section, Program program, diff --git a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/modules/DebuggerStaticMappingPlugin.java b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/modules/DebuggerStaticMappingPlugin.java index aa1b1ae218..ac892eaefc 100644 --- a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/modules/DebuggerStaticMappingPlugin.java +++ b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/modules/DebuggerStaticMappingPlugin.java @@ -25,6 +25,7 @@ import ghidra.app.services.DebuggerTraceManagerService; import ghidra.framework.plugintool.*; import ghidra.framework.plugintool.util.PluginStatus; +//@formatter:off @PluginInfo( shortDescription = "Debugger static mapping manager", description = "GUI to manage static mappings", @@ -39,6 +40,7 @@ import ghidra.framework.plugintool.util.PluginStatus; DebuggerStaticMappingService.class, DebuggerTraceManagerService.class, }) +//@formatter:on public class DebuggerStaticMappingPlugin extends AbstractDebuggerPlugin { protected DebuggerStaticMappingProvider provider; @@ -55,6 +57,7 @@ public class DebuggerStaticMappingPlugin extends AbstractDebuggerPlugin { @Override protected void dispose() { tool.removeComponentProvider(provider); + provider.dispose(); super.dispose(); } diff --git a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/modules/DebuggerStaticMappingProvider.java b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/modules/DebuggerStaticMappingProvider.java index 22839ce755..119c9692f1 100644 --- a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/modules/DebuggerStaticMappingProvider.java +++ b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/modules/DebuggerStaticMappingProvider.java @@ -176,6 +176,10 @@ public class DebuggerStaticMappingProvider extends ComponentProviderAdapter createActions(); } + void dispose() { + addMappingDialog.dispose(); + } + @AutoServiceConsumed private void setMappingService(DebuggerStaticMappingService mappingService) { addMappingDialog.setMappingService(mappingService); diff --git a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/objects/DebuggerObjectsProvider.java b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/objects/DebuggerObjectsProvider.java index ceb22fca0f..4265314674 100644 --- a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/objects/DebuggerObjectsProvider.java +++ b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/objects/DebuggerObjectsProvider.java @@ -132,9 +132,7 @@ public class DebuggerObjectsProvider extends ComponentProviderAdapter @SuppressWarnings("unused") private final AutoService.Wiring autoServiceWiring; - @AutoOptionDefined( - name = "Default Extended Step", - description = "The default string for the extended step command") + @AutoOptionDefined(name = "Default Extended Step", description = "The default string for the extended step command") String extendedStep = ""; @SuppressWarnings("unused") @@ -248,6 +246,16 @@ public class DebuggerObjectsProvider extends ComponentProviderAdapter repeatLastSet.run(); } + void dispose() { + // TODO This is not currently called, since the clients of this provider to not hold onto + // the provider after creation. Ideally, these providers should either be tracked and + // disposed, or this provider should perform cleanup on itself when it is no longer used. + configDialog.dispose(); + methodDialog.dispose(); + attachDialog.dispose(); + breakpointDialog.dispose(); + } + @Override public void addLocalAction(DockingActionIf action) { super.addLocalAction(action); diff --git a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/objects/actions/ImportExportAsAction.java b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/objects/actions/ImportExportAsAction.java index f1e34aec38..d96604bb6d 100644 --- a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/objects/actions/ImportExportAsAction.java +++ b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/objects/actions/ImportExportAsAction.java @@ -78,6 +78,7 @@ public abstract class ImportExportAsAction extends DockingAction { chooser.setCurrentDirectory(Application.getUserSettingsDirectory()); File f = chooser.getSelectedFile(); + chooser.dispose(); if (chooser.wasCancelled() || f == null) { // Redundant? Meh, it's cheap. return; } diff --git a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/objects/components/DebuggerAttachDialog.java b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/objects/components/DebuggerAttachDialog.java index 13642638c5..30e44746be 100644 --- a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/objects/components/DebuggerAttachDialog.java +++ b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/objects/components/DebuggerAttachDialog.java @@ -15,8 +15,7 @@ */ package ghidra.app.plugin.core.debug.gui.objects.components; -import static ghidra.app.plugin.core.debug.gui.DebuggerResources.GROUP_GENERAL; -import static ghidra.app.plugin.core.debug.gui.DebuggerResources.tableRowActivationAction; +import static ghidra.app.plugin.core.debug.gui.DebuggerResources.*; import java.awt.BorderLayout; import java.util.List; @@ -26,7 +25,7 @@ import java.util.concurrent.atomic.AtomicReference; import javax.swing.*; import docking.ActionContext; -import docking.DialogComponentProvider; +import docking.ReusableDialogComponentProvider; import docking.action.ToolBarData; import docking.widgets.table.*; import ghidra.app.plugin.core.debug.gui.DebuggerResources.AbstractAttachAction; @@ -40,7 +39,7 @@ import ghidra.util.MessageType; import ghidra.util.Msg; import ghidra.util.table.GhidraTableFilterPanel; -public class DebuggerAttachDialog extends DialogComponentProvider { +public class DebuggerAttachDialog extends ReusableDialogComponentProvider { protected class RefreshAction extends AbstractRefreshAction { public static final String GROUP = GROUP_GENERAL; diff --git a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/register/DebuggerAvailableRegistersDialog.java b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/register/DebuggerAvailableRegistersDialog.java index fea51a28e9..7e67ae3307 100644 --- a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/register/DebuggerAvailableRegistersDialog.java +++ b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/register/DebuggerAvailableRegistersDialog.java @@ -26,7 +26,7 @@ import javax.swing.table.TableColumn; import javax.swing.table.TableColumnModel; import docking.ActionContext; -import docking.DialogComponentProvider; +import docking.ReusableDialogComponentProvider; import docking.action.DockingAction; import docking.widgets.table.DefaultEnumeratedColumnTableModel; import docking.widgets.table.DefaultEnumeratedColumnTableModel.EnumeratedTableColumn; @@ -37,7 +37,7 @@ import ghidra.program.model.lang.Language; import ghidra.program.model.lang.Register; import ghidra.util.table.GhidraTableFilterPanel; -public class DebuggerAvailableRegistersDialog extends DialogComponentProvider { +public class DebuggerAvailableRegistersDialog extends ReusableDialogComponentProvider { protected enum AvailableRegisterTableColumns implements EnumeratedTableColumn { diff --git a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/register/DebuggerRegistersProvider.java b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/register/DebuggerRegistersProvider.java index b9bf8f9fcf..6c64729259 100644 --- a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/register/DebuggerRegistersProvider.java +++ b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/register/DebuggerRegistersProvider.java @@ -553,6 +553,8 @@ public class DebuggerRegistersProvider extends ComponentProviderAdapter @Override public void removeFromTool() { + availableRegsDialog.dispose(); + plugin.providerRemoved(this); plugin.getTool().removePopupActionProvider(this); super.removeFromTool(); diff --git a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/service/model/DebuggerConnectDialog.java b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/service/model/DebuggerConnectDialog.java index f03b345218..6ecaf399e1 100644 --- a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/service/model/DebuggerConnectDialog.java +++ b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/service/model/DebuggerConnectDialog.java @@ -31,7 +31,7 @@ import javax.swing.text.View; import org.apache.commons.collections4.BidiMap; import org.apache.commons.collections4.bidimap.DualLinkedHashBidiMap; -import docking.DialogComponentProvider; +import docking.ReusableDialogComponentProvider; import ghidra.app.plugin.core.debug.gui.DebuggerResources.AbstractConnectAction; import ghidra.app.plugin.core.debug.utils.MiscellaneousUtils; import ghidra.app.services.DebuggerModelService; @@ -45,7 +45,7 @@ import ghidra.program.model.listing.Program; import ghidra.util.*; import ghidra.util.datastruct.CollectionChangeListener; -public class DebuggerConnectDialog extends DialogComponentProvider +public class DebuggerConnectDialog extends ReusableDialogComponentProvider implements PropertyChangeListener { private static final String KEY_CURRENT_FACTORY_CLASSNAME = "currentFactoryCls"; private static final String KEY_SUCCESS_FACTORY_CLASSNAME = "successFactoryCls"; diff --git a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/service/model/DebuggerModelServicePlugin.java b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/service/model/DebuggerModelServicePlugin.java index 0b3e89f598..4ceb3aaa21 100644 --- a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/service/model/DebuggerModelServicePlugin.java +++ b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/service/model/DebuggerModelServicePlugin.java @@ -62,6 +62,7 @@ import ghidra.util.classfinder.ClassSearcher; import ghidra.util.datastruct.CollectionChangeListener; import ghidra.util.datastruct.ListenerSet; +//@formatter:off @PluginInfo( shortDescription = "Debugger models manager service", description = "Manage debug sessions, connections, and trace recording", @@ -70,7 +71,9 @@ import ghidra.util.datastruct.ListenerSet; status = PluginStatus.HIDDEN, servicesRequired = {}, servicesProvided = { - DebuggerModelService.class, }) + DebuggerModelService.class + }) +//@formatter:on public class DebuggerModelServicePlugin extends Plugin implements DebuggerModelServiceInternal, ApplicationLevelOnlyPlugin { @@ -184,6 +187,14 @@ public class DebuggerModelServicePlugin extends Plugin createActions(); } + @Override + protected void dispose() { + super.dispose(); + + connectDialog.dispose(); + offerDialog.dispose(); + } + protected void createActions() { actionDisconnectAll = DisconnectAllAction.builder(this, this) .menuPath("Debugger", DisconnectAllAction.NAME) diff --git a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/service/model/DebuggerSelectMappingOfferDialog.java b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/service/model/DebuggerSelectMappingOfferDialog.java index 25657d81c0..3f5f66278a 100644 --- a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/service/model/DebuggerSelectMappingOfferDialog.java +++ b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/service/model/DebuggerSelectMappingOfferDialog.java @@ -23,7 +23,7 @@ import java.util.function.Function; import javax.swing.*; -import docking.DialogComponentProvider; +import docking.ReusableDialogComponentProvider; import docking.widgets.table.*; import docking.widgets.table.ColumnSortState.SortDirection; import docking.widgets.table.DefaultEnumeratedColumnTableModel.EnumeratedTableColumn; @@ -35,7 +35,7 @@ import ghidra.program.util.DefaultLanguageService; import ghidra.util.table.GhidraTable; import ghidra.util.table.GhidraTableFilterPanel; -public class DebuggerSelectMappingOfferDialog extends DialogComponentProvider { +public class DebuggerSelectMappingOfferDialog extends ReusableDialogComponentProvider { protected enum OfferTableColumns implements EnumeratedTableColumn { diff --git a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/service/tracemgr/DebuggerTraceManagerServicePlugin.java b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/service/tracemgr/DebuggerTraceManagerServicePlugin.java index 8c3aed3e33..afe6991016 100644 --- a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/service/tracemgr/DebuggerTraceManagerServicePlugin.java +++ b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/service/tracemgr/DebuggerTraceManagerServicePlugin.java @@ -66,6 +66,7 @@ import ghidra.util.datastruct.CollectionChangeListener; import ghidra.util.exception.*; import ghidra.util.task.*; +//@formatter:off @PluginInfo( shortDescription = "Debugger Trace Management Plugin", description = "Manages the set of open traces, current views, etc.", @@ -86,6 +87,7 @@ import ghidra.util.task.*; servicesProvided = { DebuggerTraceManagerService.class, }) +//@formatter:on public class DebuggerTraceManagerServicePlugin extends Plugin implements DebuggerTraceManagerService { @@ -282,8 +284,6 @@ public class DebuggerTraceManagerServicePlugin extends Plugin @SuppressWarnings("unused") private final AutoService.Wiring autoServiceWiring; - private DataTreeDialog traceChooserDialog; - DockingAction actionCloseTrace; DockingAction actionCloseAllTraces; DockingAction actionCloseOtherTraces; @@ -393,9 +393,7 @@ public class DebuggerTraceManagerServicePlugin extends Plugin } protected DataTreeDialog getTraceChooserDialog() { - if (traceChooserDialog != null) { - return traceChooserDialog; - } + DomainFileFilter filter = new DomainFileFilter() { @Override @@ -410,21 +408,20 @@ public class DebuggerTraceManagerServicePlugin extends Plugin }; // TODO regarding the hack note below, I believe this issue ahs been fixed, but not sure how to test - return traceChooserDialog = - new DataTreeDialog(null, OpenTraceAction.NAME, DataTreeDialog.OPEN, filter) { - { // TODO/HACK: Why the NPE if I don't do this? - dialogShown(); - } - }; + return new DataTreeDialog(null, OpenTraceAction.NAME, DataTreeDialog.OPEN, filter) { + { // TODO/HACK: Why the NPE if I don't do this? + dialogShown(); + } + }; } public DomainFile askTrace(Trace trace) { - getTraceChooserDialog(); + DataTreeDialog dialog = getTraceChooserDialog(); if (trace != null) { - traceChooserDialog.selectDomainFile(trace.getDomainFile()); + dialog.selectDomainFile(trace.getDomainFile()); } - tool.showDialog(traceChooserDialog); - return traceChooserDialog.getDomainFile(); + tool.showDialog(dialog); + return dialog.getDomainFile(); } @Override diff --git a/Ghidra/Extensions/MachineLearning/src/main/java/ghidra/machinelearning/functionfinding/FunctionStartRFParamsDialog.java b/Ghidra/Extensions/MachineLearning/src/main/java/ghidra/machinelearning/functionfinding/FunctionStartRFParamsDialog.java index a5cf021edf..e8536b5882 100644 --- a/Ghidra/Extensions/MachineLearning/src/main/java/ghidra/machinelearning/functionfinding/FunctionStartRFParamsDialog.java +++ b/Ghidra/Extensions/MachineLearning/src/main/java/ghidra/machinelearning/functionfinding/FunctionStartRFParamsDialog.java @@ -24,7 +24,7 @@ import javax.swing.*; import org.apache.commons.lang3.StringUtils; -import docking.DialogComponentProvider; +import docking.ReusableDialogComponentProvider; import docking.action.DockingAction; import docking.action.builder.ActionBuilder; import docking.widgets.combobox.GComboBox; @@ -50,7 +50,7 @@ import ghidra.util.task.*; * for learning function starts, train models, see performance statistics, and * apply the models. */ -public class FunctionStartRFParamsDialog extends DialogComponentProvider { +public class FunctionStartRFParamsDialog extends ReusableDialogComponentProvider { private static final String INITIAL_BYTES_TEXT = "Number of Initial Bytes (CSV)"; private static final String INITIAL_BYTES_TIP = diff --git a/Ghidra/Extensions/MachineLearning/src/main/java/ghidra/machinelearning/functionfinding/RandomForestFunctionFinderPlugin.java b/Ghidra/Extensions/MachineLearning/src/main/java/ghidra/machinelearning/functionfinding/RandomForestFunctionFinderPlugin.java index d38f90c08b..e0a1753467 100644 --- a/Ghidra/Extensions/MachineLearning/src/main/java/ghidra/machinelearning/functionfinding/RandomForestFunctionFinderPlugin.java +++ b/Ghidra/Extensions/MachineLearning/src/main/java/ghidra/machinelearning/functionfinding/RandomForestFunctionFinderPlugin.java @@ -96,6 +96,15 @@ public class RandomForestFunctionFinderPlugin extends ProgramPlugin initOptions(getTool().getOptions("Random Forest Function Finder")); } + @Override + protected void dispose() { + super.dispose(); + + if (paramsDialog != null) { + paramsDialog.dispose(); + } + } + @Override public void optionsChanged(ToolOptions options, String optionName, Object oldValue, Object newValue) throws OptionsVetoException { diff --git a/Ghidra/Extensions/SampleTablePlugin/src/main/java/ghidra/examples/SampleTableProvider.java b/Ghidra/Extensions/SampleTablePlugin/src/main/java/ghidra/examples/SampleTableProvider.java index 6aaa3c25f6..a8f71f720a 100644 --- a/Ghidra/Extensions/SampleTablePlugin/src/main/java/ghidra/examples/SampleTableProvider.java +++ b/Ghidra/Extensions/SampleTablePlugin/src/main/java/ghidra/examples/SampleTableProvider.java @@ -69,6 +69,7 @@ public class SampleTableProvider extends ComponentProviderAdapter implements Opt void dispose() { filterTable.dispose(); + fileChooserPanel.dispose(); removeFromTool(); } diff --git a/Ghidra/Features/Base/certification.manifest b/Ghidra/Features/Base/certification.manifest index c1f70ee0b7..ce192cb3ef 100644 --- a/Ghidra/Features/Base/certification.manifest +++ b/Ghidra/Features/Base/certification.manifest @@ -192,7 +192,6 @@ src/main/help/help/topics/DataTypeManagerPlugin/data_type_manager_archives.html| src/main/help/help/topics/DataTypeManagerPlugin/data_type_manager_description.htm||GHIDRA||||END| src/main/help/help/topics/DataTypeManagerPlugin/data_type_manager_window.html||GHIDRA||||END| src/main/help/help/topics/DataTypeManagerPlugin/images/CommitDialog.png||GHIDRA||||END| -src/main/help/help/topics/DataTypeManagerPlugin/images/DataTypeConflict.png||GHIDRA||||END| src/main/help/help/topics/DataTypeManagerPlugin/images/DataTypeManager.png||GHIDRA||||END| src/main/help/help/topics/DataTypeManagerPlugin/images/DisassociateDialog.png||GHIDRA||||END| src/main/help/help/topics/DataTypeManagerPlugin/images/EditPaths.png||GHIDRA||||END| diff --git a/Ghidra/Features/Base/src/main/help/help/topics/DataTypeManagerPlugin/data_type_manager_description.htm b/Ghidra/Features/Base/src/main/help/help/topics/DataTypeManagerPlugin/data_type_manager_description.htm index c571ebe828..fb37bdc85c 100644 --- a/Ghidra/Features/Base/src/main/help/help/topics/DataTypeManagerPlugin/data_type_manager_description.htm +++ b/Ghidra/Features/Base/src/main/help/help/topics/DataTypeManagerPlugin/data_type_manager_description.htm @@ -991,35 +991,6 @@ -

Handling Data Type Conflicts

- -
-

When you move or copy a data type to a category that has a data type with the same - name, a conflict occurs. If the data types are not the same, then a dialog is displayed - in order to resolve the conflict, as shown below:

-
- -

- -
-

In this example, you dragged (or pasted) the data type "SIZE_T" from one category to - the /basetsd.h category; the one being dragged is different from the one that already - exists in the /basetsd.h category. The choices to resolve the conflict are:

- -
    -
  1. Rename the data type that you are dragging to have ".conflict" appended to - it to make a unique name.
  2. - -
  3. Replace the existing data type with the new one; - this means any use of the existing data types is replaced with the new - data type; the existing data type is deleted.
  4. - -
  5. Use the existing data type; if you did a cut/paste or drag/move operation, the - "cut" or "dragged" data type is removed from its original category; the destination - category is unaffected.
  6. -
-
-

Replacing a Data Type

diff --git a/Ghidra/Features/Base/src/main/help/help/topics/DataTypeManagerPlugin/images/DataTypeConflict.png b/Ghidra/Features/Base/src/main/help/help/topics/DataTypeManagerPlugin/images/DataTypeConflict.png deleted file mode 100644 index a55764c06c..0000000000 Binary files a/Ghidra/Features/Base/src/main/help/help/topics/DataTypeManagerPlugin/images/DataTypeConflict.png and /dev/null differ diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/archive/ArchiveDialog.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/archive/ArchiveDialog.java index 16468e6176..49b439a233 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/archive/ArchiveDialog.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/archive/ArchiveDialog.java @@ -20,9 +20,10 @@ import java.io.File; import javax.swing.*; -import docking.DialogComponentProvider; +import docking.ReusableDialogComponentProvider; import docking.widgets.OptionDialog; import docking.widgets.filechooser.GhidraFileChooser; +import docking.widgets.filechooser.GhidraFileChooserMode; import docking.widgets.label.GDLabel; import ghidra.framework.GenericRunInfo; import ghidra.framework.model.ProjectLocator; @@ -32,10 +33,9 @@ import ghidra.util.filechooser.GhidraFileChooserModel; import ghidra.util.filechooser.GhidraFileFilter; /** - * Dialog to prompt the user for the project to archive and the file to archive - * it to. + * Dialog to prompt the user for the project to archive and the file to archive it to. */ -public class ArchiveDialog extends DialogComponentProvider { +public class ArchiveDialog extends ReusableDialogComponentProvider { private static final int NUM_TEXT_COLUMNS = 40; private boolean actionComplete; @@ -43,14 +43,12 @@ public class ArchiveDialog extends DialogComponentProvider { private JTextField archiveField; private JButton archiveBrowse; - private GhidraFileChooser jarFileChooser; private ProjectLocator projectLocator; private String archivePathName; /** * Constructor * - * @param parent the parent frame of the NumberInputDialog. * @param plugin the archive plugin using this dialog. */ ArchiveDialog(ArchivePlugin plugin) { @@ -179,6 +177,7 @@ public class ArchiveDialog extends DialogComponentProvider { * Display this dialog. * @param pProjectLocator the project URL to display when the dialog pops up. * @param pArchivePathName the archive file name to display when the dialog pops up. + * @param tool the tool * * @return true if the user submitted valid values for the project and * archive file, false if user cancelled. @@ -237,7 +236,7 @@ public class ArchiveDialog extends DialogComponentProvider { File file = new File(pathname); String name = file.getName(); - if (!isValidName(name)) { + if (!NamingUtilities.isValidProjectName(name)) { setStatusText("Archive name contains invalid characters."); return false; } @@ -256,8 +255,7 @@ public class ArchiveDialog extends DialogComponentProvider { String filePathName) { GhidraFileChooser fileChooser = new GhidraFileChooser(getComponent()); - - fileChooser.setFileSelectionMode(GhidraFileChooser.FILES_ONLY); + fileChooser.setFileSelectionMode(GhidraFileChooserMode.FILES_ONLY); fileChooser.setFileFilter(new GhidraFileFilter() { @Override public boolean accept(File file, GhidraFileChooserModel model) { @@ -310,12 +308,12 @@ public class ArchiveDialog extends DialogComponentProvider { * @param approveToolTip The tool tip for the "Open" button on the file chooser * @return the archive file path. */ - String chooseArchiveFile(String approveButtonText, String approveToolTip) { - if (jarFileChooser == null) { - jarFileChooser = createFileChooser(ArchivePlugin.ARCHIVE_EXTENSION, "Ghidra Archives", + private String chooseArchiveFile(String approveButtonText, String approveToolTip) { + + GhidraFileChooser jarFileChooser = + createFileChooser(ArchivePlugin.ARCHIVE_EXTENSION, "Ghidra Archives", archivePathName); - jarFileChooser.setTitle("Archive a Ghidra Project"); - } + jarFileChooser.setTitle("Archive a Ghidra Project"); File jarFile = null; if (archivePathName != null && archivePathName.length() != 0) { jarFile = new File(archivePathName); @@ -338,7 +336,7 @@ public class ArchiveDialog extends DialogComponentProvider { File file = selectedFile; String chosenPathname = file.getAbsolutePath(); String name = file.getName(); - if (!NamingUtilities.isValidName(name)) { + if (!NamingUtilities.isValidProjectName(name)) { Msg.showError(getClass(), null, "Invalid Archive Name", name + " is not a valid archive name"); continue; @@ -354,32 +352,7 @@ public class ArchiveDialog extends DialogComponentProvider { pathname = chosenPathname; } - + jarFileChooser.dispose(); return pathname; } - - /** - * tests whether the given string is a valid name. - * @param name name to validate - */ - public boolean isValidName(String name) { - if (name == null) { - return false; - } - - if ((name.length() < 1)) { - return false; - } - - for (int i = 0; i < name.length(); i++) { - char c = name.charAt(i); - if (!Character.isLetterOrDigit(c) && c != '.' && c != '-' && c != ' ' && c != '_' && - c != '\\' && c != '~' && c != '/' && c != ':') { - return false; - } - } - - return true; - } - } diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/archive/ArchivePlugin.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/archive/ArchivePlugin.java index 84d0faf741..cf066d3d2c 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/archive/ArchivePlugin.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/archive/ArchivePlugin.java @@ -96,8 +96,6 @@ public class ArchivePlugin extends Plugin implements ApplicationLevelOnlyPlugin, private TaskListener archivingListener; private TaskListener restoringListener; - ////////////////////////////////////////////////////////////////// - /** * The archive plugin provides menu action from the front end allowing the * user to archive a project or restore an archived project. @@ -112,36 +110,34 @@ public class ArchivePlugin extends Plugin implements ApplicationLevelOnlyPlugin, @Override public void dispose() { super.dispose(); + if (archiveDialog != null) { + archiveDialog.dispose(); + } + if (restoreDialog != null) { + restoreDialog.dispose(); + } } - ///////////////////////////////////////////////////////////////////// - - /** - * @see ghidra.framework.model.ProjectListener#projectClosed(Project) - */ @Override public void projectClosed(Project project) { archiveAction.setEnabled(false); restoreAction.setEnabled(true); } - /** - * @see ghidra.framework.model.ProjectListener#projectOpened(Project) - */ @Override public void projectOpened(Project project) { archiveAction.setEnabled(true); restoreAction.setEnabled(false); } - /** + /* * for JUnits... */ boolean isArchiving() { return isArchiving; } - /** + /* * for JUnits... */ boolean isRestoring() { @@ -300,12 +296,6 @@ public class ArchivePlugin extends Plugin implements ApplicationLevelOnlyPlugin, new TaskLauncher(task, tool.getToolFrame()); } - /** - * Return true if the jar file contains the JAR_FORMAT tag to indicate - * the new jar file format. - * @param jarFile - * @throws IOException - */ private boolean isJarFormat(File jarFile) throws IOException { JarInputStream jarIn = new JarInputStream(new FileInputStream(jarFile)); JarEntry entry = jarIn.getNextJarEntry(); diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/archive/RestoreDialog.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/archive/RestoreDialog.java index 30dc9cfebd..5677881798 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/archive/RestoreDialog.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/archive/RestoreDialog.java @@ -22,8 +22,9 @@ import java.io.File; import javax.swing.*; -import docking.DialogComponentProvider; +import docking.ReusableDialogComponentProvider; import docking.widgets.filechooser.GhidraFileChooser; +import docking.widgets.filechooser.GhidraFileChooserMode; import docking.widgets.label.GDLabel; import ghidra.framework.GenericRunInfo; import ghidra.framework.model.ProjectLocator; @@ -35,7 +36,7 @@ import ghidra.util.filechooser.ExtensionFileFilter; * Dialog to prompt the user for the archive file to restore * and where to restore it to. */ -public class RestoreDialog extends DialogComponentProvider { +public class RestoreDialog extends ReusableDialogComponentProvider { /** * Preference name for directory last selected to choose a jar file * to restore. @@ -54,14 +55,12 @@ public class RestoreDialog extends DialogComponentProvider { private JButton restoreBrowse; private JLabel projectNameLabel; private JTextField projectNameField; - private GhidraFileChooser jarFileChooser; - private GhidraFileChooser dirChooser; private String archivePathName; private ProjectLocator restoreURL; public RestoreDialog(ArchivePlugin plugin) { - super("Restore Project Archive", true); + super("Restore Project Archive"); this.plugin = plugin; initialize(); @@ -374,10 +373,9 @@ public class RestoreDialog extends DialogComponentProvider { GhidraFileChooser fileChooser = new GhidraFileChooser(null); // start the browsing in the user's preferred project directory File projectDirectory = new File(GenericRunInfo.getProjectsDirPath()); - fileChooser.setFileSelectionMode(GhidraFileChooser.DIRECTORIES_ONLY); + fileChooser.setFileSelectionMode(GhidraFileChooserMode.DIRECTORIES_ONLY); fileChooser.setCurrentDirectory(projectDirectory); fileChooser.setSelectedFile(projectDirectory); - return fileChooser; } @@ -386,19 +384,19 @@ public class RestoreDialog extends DialogComponentProvider { * filename that are used for the Project location and name * @param approveButtonText The label for the "Open" button on the file chooser * @param approveToolTip The tool tip for the "Open" button on the file chooser - * @return the archive filepath. + * @return the archive file path. */ String chooseArchiveFile(String approveButtonText, String approveToolTip) { - if (jarFileChooser == null) { - jarFileChooser = createFileChooser(ArchivePlugin.ARCHIVE_EXTENSION, "Ghidra Archives", + + GhidraFileChooser jarFileChooser = + createFileChooser(ArchivePlugin.ARCHIVE_EXTENSION, "Ghidra Archives", archivePathName); - jarFileChooser.setTitle("Restore a Ghidra Project - Archive"); - String lastDirSelected = Preferences.getProperty(ArchivePlugin.LAST_ARCHIVE_DIR); - if (lastDirSelected != null) { - File file = new File(lastDirSelected); - if (file.exists()) { - jarFileChooser.setCurrentDirectory(file); - } + jarFileChooser.setTitle("Restore a Ghidra Project - Archive"); + String lastDirSelected = Preferences.getProperty(ArchivePlugin.LAST_ARCHIVE_DIR); + if (lastDirSelected != null) { + File file = new File(lastDirSelected); + if (file.exists()) { + jarFileChooser.setCurrentDirectory(file); } } File jarFile = null; @@ -419,7 +417,7 @@ public class RestoreDialog extends DialogComponentProvider { File file = selectedFile; String chosenName = file.getName(); - if (!NamingUtilities.isValidName(chosenName)) { + if (!NamingUtilities.isValidProjectName(chosenName)) { Msg.showError(getClass(), null, "Invalid Archive Name", chosenName + " is not a valid archive name"); continue; @@ -428,6 +426,9 @@ public class RestoreDialog extends DialogComponentProvider { Preferences.setProperty(ArchivePlugin.LAST_ARCHIVE_DIR, file.getParent()); pathname = file.getAbsolutePath(); } + + jarFileChooser.dispose(); + return pathname; } @@ -436,13 +437,11 @@ public class RestoreDialog extends DialogComponentProvider { * project archive will be restored. * @param approveButtonText The label for the "Open" button on the file chooser * @param approveToolTip The tool tip for the "Open" button on the file chooser - * @return the restore directory filepath. + * @return the restore directory file path. */ String chooseDirectory(String approveButtonText, String approveToolTip) { - if (dirChooser == null) { - dirChooser = createDirectoryChooser(); - dirChooser.setTitle("Restore a Ghidra Project - Directory"); - } + GhidraFileChooser dirChooser = createDirectoryChooser(); + dirChooser.setTitle("Restore a Ghidra Project - Directory"); if (restoreURL != null) { dirChooser.setSelectedFile(new File(restoreURL.getLocation())); } @@ -450,6 +449,7 @@ public class RestoreDialog extends DialogComponentProvider { dirChooser.setApproveButtonToolTipText(approveToolTip); File selectedFile = dirChooser.getSelectedFile(true); + dirChooser.dispose(); if (selectedFile != null) { return selectedFile.getAbsolutePath(); } diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/bookmark/BookmarkPlugin.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/bookmark/BookmarkPlugin.java index 0fa54915d9..3190a2a8be 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/bookmark/BookmarkPlugin.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/bookmark/BookmarkPlugin.java @@ -77,7 +77,6 @@ public class BookmarkPlugin extends ProgramPlugin private BookmarkProvider provider; private DockingAction addAction; private DockingAction deleteAction; - private CreateBookmarkDialog createDialog; private GoToService goToService; private MarkerService markerService; private BookmarkManager bookmarkMgr; @@ -206,10 +205,6 @@ public class BookmarkPlugin extends ProgramPlugin provider.dispose(); provider = null; } - if (createDialog != null) { - createDialog.dispose(); - createDialog = null; - } goToService = null; disposeAllBookmarkers(); @@ -444,7 +439,7 @@ public class BookmarkPlugin extends ProgramPlugin return; } boolean hasSelection = currentSelection != null && !currentSelection.isEmpty(); - createDialog = new CreateBookmarkDialog(this, currCU, hasSelection); + CreateBookmarkDialog createDialog = new CreateBookmarkDialog(this, currCU, hasSelection); tool.showDialog(createDialog); } diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/clear/ClearPlugin.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/clear/ClearPlugin.java index 97fba29664..84dac7d9c3 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/clear/ClearPlugin.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/clear/ClearPlugin.java @@ -46,22 +46,11 @@ public class ClearPlugin extends Plugin { private static final String CLEAR_CODE_BYTES_NAME = "Clear Code Bytes"; private static final String CLEAR_FLOW_AND_REPAIR = "Clear Flow and Repair"; - private ClearDialog clearDialog; - private ClearFlowDialog clearFlowDialog; - - /** - * Constructor - */ public ClearPlugin(PluginTool tool) { super(tool); createActions(); } - // ///////////////////////////////////////////////////////////////////// - - /** - * Clear the flow and repair disassembly at the current location - */ void clearFlowAndRepair(ListingActionContext context, boolean clearSymbols, boolean clearData, boolean repair) { ClearFlowAndRepairCmd cmd; @@ -76,10 +65,6 @@ public class ClearPlugin extends Plugin { tool.executeBackgroundCommand(cmd, context.getProgram()); } - /** - * Use the options to determine what must be cleared. Starts a new thread if - * necessary to do the work. Called by the actions and by the dialog. - */ void clear(ClearOptions options, ListingActionContext context) { if (!options.clearAny()) { return; @@ -258,13 +243,12 @@ public class ClearPlugin extends Plugin { clear(opts, context); } + /** * Pop up the clear with options dialog. */ private void showClearAllDialog(ListingActionContext programActionContext) { - if (clearDialog == null) { - clearDialog = new ClearDialog(this); - } + ClearDialog clearDialog = new ClearDialog(this); clearDialog.setProgramActionContext(programActionContext); tool.showDialog(clearDialog); } @@ -273,9 +257,7 @@ public class ClearPlugin extends Plugin { * Pop up the clear flows dialog */ private void showClearFlowDialog(ListingActionContext context) { - if (clearFlowDialog == null) { - clearFlowDialog = new ClearFlowDialog(this); - } + ClearFlowDialog clearFlowDialog = new ClearFlowDialog(this); clearFlowDialog.setProgramActionContext(context); tool.showDialog(clearFlowDialog); } diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/comments/CommentsDialog.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/comments/CommentsDialog.java index 2c335a7a52..f8abf9aad6 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/comments/CommentsDialog.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/comments/CommentsDialog.java @@ -38,7 +38,7 @@ import ghidra.util.HelpLocation; /** * Dialog for setting the comments for a CodeUnit. */ -public class CommentsDialog extends DialogComponentProvider implements KeyListener { +public class CommentsDialog extends ReusableDialogComponentProvider implements KeyListener { private JTextArea eolField; private JTextArea preField; diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/comments/CommentsPlugin.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/comments/CommentsPlugin.java index f87956e424..298160ca00 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/comments/CommentsPlugin.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/comments/CommentsPlugin.java @@ -58,7 +58,6 @@ public class CommentsPlugin extends Plugin implements OptionsChangeListener { private DockingAction deleteAction; private DockingAction historyAction; private CommentsDialog dialog; - private CommentHistoryDialog historyDialog; private DockingAction preCommentEditAction; private DockingAction postCommentEditAction; @@ -76,6 +75,12 @@ public class CommentsPlugin extends Plugin implements OptionsChangeListener { initializeOptions(tool.getOptions("Comments")); } + @Override + protected void dispose() { + super.dispose(); + dialog.dispose(); + } + @Override public void optionsChanged(ToolOptions options, String optionName, Object oldValue, Object newValue) { @@ -223,9 +228,7 @@ public class CommentsPlugin extends Plugin implements OptionsChangeListener { private void showCommentHistory(ListingActionContext context) { CodeUnit cu = context.getCodeUnit(); ProgramLocation loc = context.getLocation(); - if (historyDialog == null) { - historyDialog = new CommentHistoryDialog(); - } + CommentHistoryDialog historyDialog = new CommentHistoryDialog(); historyDialog.showDialog(cu, CommentType.getCommentType(null, loc, CodeUnit.EOL_COMMENT), tool, context); } @@ -238,14 +241,17 @@ public class CommentsPlugin extends Plugin implements OptionsChangeListener { } if (loc instanceof FunctionRepeatableCommentFieldLocation) { - action.getPopupMenuData().setMenuPath( - new String[] { "Comments", actionString + " Repeatable Comment" + endString }); + action.getPopupMenuData() + .setMenuPath( + new String[] { "Comments", + actionString + " Repeatable Comment" + endString }); return; } if (loc instanceof PlateFieldLocation) { - action.getPopupMenuData().setMenuPath( - new String[] { "Comments", actionString + " Plate Comment" + endString }); + action.getPopupMenuData() + .setMenuPath( + new String[] { "Comments", actionString + " Plate Comment" + endString }); return; } @@ -253,23 +259,29 @@ public class CommentsPlugin extends Plugin implements OptionsChangeListener { int type = cfLoc.getCommentType(); switch (type) { case CodeUnit.PRE_COMMENT: - action.getPopupMenuData().setMenuPath( - new String[] { "Comments", actionString + " Pre-Comment" + endString }); + action.getPopupMenuData() + .setMenuPath( + new String[] { "Comments", actionString + " Pre-Comment" + endString }); break; case CodeUnit.POST_COMMENT: - action.getPopupMenuData().setMenuPath( - new String[] { "Comments", actionString + " Post-Comment" + endString }); + action.getPopupMenuData() + .setMenuPath( + new String[] { "Comments", + actionString + " Post-Comment" + endString }); break; case CodeUnit.EOL_COMMENT: - action.getPopupMenuData().setMenuPath( - new String[] { "Comments", actionString + " EOL Comment" + endString }); + action.getPopupMenuData() + .setMenuPath( + new String[] { "Comments", actionString + " EOL Comment" + endString }); break; case CodeUnit.REPEATABLE_COMMENT: - action.getPopupMenuData().setMenuPath( - new String[] { "Comments", actionString + " Repeatable Comment" + endString }); + action.getPopupMenuData() + .setMenuPath( + new String[] { "Comments", + actionString + " Repeatable Comment" + endString }); break; } } diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/compositeeditor/CompositeEditorProvider.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/compositeeditor/CompositeEditorProvider.java index 9fe4c4e392..6ac350c2b4 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/compositeeditor/CompositeEditorProvider.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/compositeeditor/CompositeEditorProvider.java @@ -150,6 +150,7 @@ public abstract class CompositeEditorProvider extends ComponentProviderAdapter editorModel.endFieldEditing(); } if (saveChanges(true) != 0) { + super.closeComponent(); dispose(); } } diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/cparser/ParseDialog.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/cparser/ParseDialog.java index 3aad90b9ee..70d64ef2fc 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/cparser/ParseDialog.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/cparser/ParseDialog.java @@ -59,7 +59,7 @@ import resources.Icons; * * */ -class ParseDialog extends DialogComponentProvider { +class ParseDialog extends ReusableDialogComponentProvider { final static String PROFILE_DIR = "parserprofiles"; private static String FILE_EXTENSION = ".prf"; @@ -89,11 +89,10 @@ class ParseDialog extends DialogComponentProvider { private ArrayList itemList; private ComboBoxItemComparator comparator; private ResourceFile parentUserFile; - private GhidraFileChooser fileChooser; private boolean saveAsInProgress; ParseDialog(CParserPlugin plugin) { - super("Parse C Source", false); + super("Parse C Source", false, true, true, false); this.plugin = plugin; itemList = new ArrayList<>(); @@ -157,7 +156,7 @@ class ParseDialog extends DialogComponentProvider { pathPanel.setBorder(BorderFactory.createTitledBorder("Source files to parse")); String importDir = Preferences.getProperty(LAST_IMPORT_C_DIRECTORY); if (importDir == null) { - importDir = Preferences.getProperty(Preferences.LAST_IMPORT_DIRECTORY); + importDir = Preferences.getProperty(Preferences.LAST_PATH_DIRECTORY); if (importDir != null) { Preferences.setProperty(LAST_IMPORT_C_DIRECTORY, importDir); } @@ -625,19 +624,15 @@ class ParseDialog extends DialogComponentProvider { } private File getSaveFile() { - if (fileChooser == null) { - fileChooser = new GhidraFileChooser(rootPanel); - String dir = Preferences.getProperty(Preferences.LAST_EXPORT_DIRECTORY); - if (dir != null) { - File file = new File(dir); - fileChooser.setCurrentDirectory(file); - fileChooser.setTitle("Choose Save Archive File"); - fileChooser.setApproveButtonText("Choose Save Archive File"); - fileChooser.setApproveButtonToolTipText("Choose filename for archive"); - } - } - fileChooser.rescanCurrentDirectory(); + + GhidraFileChooser fileChooser = new GhidraFileChooser(rootPanel); + fileChooser.setTitle("Choose Save Archive File"); + fileChooser.setApproveButtonText("Choose Save Archive File"); + fileChooser.setApproveButtonToolTipText("Choose filename for archive"); + fileChooser.setLastDirectoryPreference(Preferences.LAST_EXPORT_DIRECTORY); + File file = fileChooser.getSelectedFile(); + fileChooser.dispose(); if (file != null) { File parent = file.getParentFile(); if (parent != null) { diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/data/CreateStructureAction.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/data/CreateStructureAction.java index cf2044da17..ebb9da5250 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/data/CreateStructureAction.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/data/CreateStructureAction.java @@ -42,14 +42,9 @@ class CreateStructureAction extends ListingContextAction { private DataPlugin plugin; private CreateStructureDialog createStructureDialog; - /** - * Constructor - * @param name action name - * @param owner owner of this action (the plugin name) - */ public CreateStructureAction(DataPlugin plugin) { super("Create Structure", plugin.getName()); -// ACTIONS - auto generated + setPopupMenuData(new MenuData(CREATE_STRUCTURE_POPUP_MENU, null, "BasicData")); setKeyBindingData(new KeyBindingData(KeyEvent.VK_OPEN_BRACKET, InputEvent.SHIFT_DOWN_MASK)); diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/data/CreateStructureDialog.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/data/CreateStructureDialog.java index 5d3d6c9eda..c5fbd55f24 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/data/CreateStructureDialog.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/data/CreateStructureDialog.java @@ -28,7 +28,7 @@ import javax.swing.table.*; import javax.swing.text.BadLocationException; import javax.swing.text.Document; -import docking.DialogComponentProvider; +import docking.ReusableDialogComponentProvider; import docking.widgets.button.GRadioButton; import docking.widgets.table.*; import generic.theme.GThemeDefaults.Colors; @@ -48,7 +48,7 @@ import ghidra.util.table.GhidraTableFilterPanel; * * */ -public class CreateStructureDialog extends DialogComponentProvider { +public class CreateStructureDialog extends ReusableDialogComponentProvider { private static final String NEW_STRUCTURE_STATUS_PREFIX = "Creating new structure: "; private static final String EXISITING_STRUCTURE_STATUS_PREFIX = "Using existing structure: "; diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/data/RenameDataFieldAction.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/data/RenameDataFieldAction.java index 0729a06c2f..1e6da527b3 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/data/RenameDataFieldAction.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/data/RenameDataFieldAction.java @@ -28,33 +28,32 @@ import ghidra.program.model.listing.Data; import ghidra.program.model.listing.Program; import ghidra.program.util.FieldNameFieldLocation; import ghidra.program.util.ProgramLocation; - + /** * Base class for comment actions to edit and delete comments. */ class RenameDataFieldAction extends ListingContextAction { private DataPlugin plugin; - private RenameDataFieldDialog dialog; - - public RenameDataFieldAction(DataPlugin plugin) { - super("Rename Data Field", plugin.getName()); - dialog = new RenameDataFieldDialog(plugin); - setPopupMenuData( - new MenuData( - new String[] {"Data", "Rename Field"},null,"BasicData" ) ); + public RenameDataFieldAction(DataPlugin plugin) { + super("Rename Data Field", plugin.getName()); - setKeyBindingData( new KeyBindingData( - KeyEvent.VK_N, 0 ) ); + setPopupMenuData( + new MenuData( + new String[] { "Data", "Rename Field" }, null, "BasicData")); - this.plugin = plugin; - setEnabled(true); - } + setKeyBindingData(new KeyBindingData( + KeyEvent.VK_N, 0)); - @Override + this.plugin = plugin; + setEnabled(true); + } + + @Override protected void actionPerformed(ListingActionContext context) { - ListingActionContext programActionContext = (ListingActionContext) context.getContextObject(); + ListingActionContext programActionContext = + (ListingActionContext) context.getContextObject(); PluginTool tool = plugin.getTool(); Program program = programActionContext.getProgram(); ProgramLocation loc = programActionContext.getLocation(); @@ -62,19 +61,22 @@ class RenameDataFieldAction extends ListingContextAction { DataType type = data.getDataType(); if (type instanceof Composite) { - Composite comp = (Composite)type; + Composite comp = (Composite) type; int[] compPath = loc.getComponentPath(); - for (int i=0; i openDialog; private Map recentlyOpenedArchiveMap; private Map installArchiveMap; @@ -366,19 +364,10 @@ public class DataTypeManagerPlugin extends ProgramPlugin newProvider.setIncludeDataTypeMembersInFilter(provider.includeDataMembersInSearch()); newProvider.setFilteringArrays(provider.isFilteringArrays()); newProvider.setFilteringPointers(provider.isFilteringPointers()); + newProvider.setTransient(); return newProvider; } - public void closeProvider(DataTypesProvider providerToClose) { - if (providerToClose != provider) { - providerToClose.removeFromTool(); // remove any transient providers when closed - providerToClose.dispose(); - } - else { - provider.setVisible(false); - } - } - public Program getProgram() { return currentProgram; } @@ -574,25 +563,24 @@ public class DataTypeManagerPlugin extends ProgramPlugin } public void openProjectDataTypeArchive() { - if (openDialog == null) { - ActionListener listener = ev -> { - DomainFile domainFile = openDialog.getDomainFile(); - int version = openDialog.getVersion(); - if (domainFile == null) { - openDialog.setStatusText("Please choose a Project Data Type Archive"); - } - else { - openDialog.close(); - openArchive(domainFile, version); - } - }; - openDialog = - new OpenVersionedFileDialog<>(tool, "Open Project Data Type Archive", - DataTypeArchive.class); - openDialog.setHelpLocation(new HelpLocation(HelpTopics.PROGRAM, "Open_File_Dialog")); - openDialog.addOkActionListener(listener); - } - tool.showDialog(openDialog); + + OpenVersionedFileDialog dialog = + new OpenVersionedFileDialog<>(tool, "Open Project Data Type Archive", + DataTypeArchive.class); + dialog.setHelpLocation(new HelpLocation(HelpTopics.PROGRAM, "Open_File_Dialog")); + dialog.addOkActionListener(ev -> { + DomainFile domainFile = dialog.getDomainFile(); + int version = dialog.getVersion(); + if (domainFile == null) { + dialog.setStatusText("Please choose a Project Data Type Archive"); + } + else { + dialog.close(); + openArchive(domainFile, version); + } + }); + + tool.showDialog(dialog); } @Override diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/DataTypeSyncDialog.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/DataTypeSyncDialog.java index a50ccd75b8..8250c0b56c 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/DataTypeSyncDialog.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/DataTypeSyncDialog.java @@ -42,7 +42,6 @@ public class DataTypeSyncDialog extends DialogComponentProvider implements DataT private DataTypeComparePanel comparePanel; private final String operationName; - private boolean cancelled; private List selectedInfos = Collections.emptyList(); public DataTypeSyncDialog(DataTypeManagerPlugin plugin, String clientName, String sourceName, @@ -118,7 +117,6 @@ public class DataTypeSyncDialog extends DialogComponentProvider implements DataT @Override protected void cancelCallback() { - cancelled = true; close(); } diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/DataTypesProvider.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/DataTypesProvider.java index 807b5fb0eb..4c65b8c08e 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/DataTypesProvider.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/DataTypesProvider.java @@ -114,6 +114,11 @@ public class DataTypesProvider extends ComponentProviderAdapter { createLocalActions(); } + @Override // overridden to open access + protected void setTransient() { + super.setTransient(); + } + /** * This creates all the actions for opening/creating data type archives. * It also creates the action for refreshing the built-in data types @@ -358,7 +363,10 @@ public class DataTypesProvider extends ComponentProviderAdapter { @Override // overridden to handle special logic in plugin public void closeComponent() { - plugin.closeProvider(this); + super.closeComponent(); + if (isTransient()) { + dispose(); + } } private void buildComponent() { diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/actions/CreateArchiveAction.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/actions/CreateArchiveAction.java index 3329bef6f6..f72b57d0ef 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/actions/CreateArchiveAction.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/actions/CreateArchiveAction.java @@ -51,6 +51,7 @@ public class CreateArchiveAction extends DockingAction { Msg.trace(this, "Showing filechooser to get new archive name..."); File file = fileChooser.promptUserForFile("New_Archive"); + fileChooser.dispose(); if (file == null) { Msg.trace(this, "No new archive filename chosen by user - not performing action"); return; diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/actions/ExportToHeaderAction.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/actions/ExportToHeaderAction.java index 487d595651..fd345dcac5 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/actions/ExportToHeaderAction.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/actions/ExportToHeaderAction.java @@ -176,6 +176,8 @@ public class ExportToHeaderAction extends DockingAction { new DataTypeWriterTask(gTree, programDataTypeMgr, dataTypeList, handler, file), gTree); } + + fileChooser.dispose(); } private class DataTypeWriterTask extends Task { @@ -209,8 +211,9 @@ public class ExportToHeaderAction extends DockingAction { finally { writer.close(); } - plugin.getTool().setStatusInfo( - "Successfully exported data type(s) to " + file.getAbsolutePath()); + plugin.getTool() + .setStatusInfo( + "Successfully exported data type(s) to " + file.getAbsolutePath()); } catch (CancelledException e) { // user cancelled; ignore diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/actions/OpenArchiveAction.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/actions/OpenArchiveAction.java index 35876cf5d5..ff7067b22a 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/actions/OpenArchiveAction.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/actions/OpenArchiveAction.java @@ -67,6 +67,7 @@ public class OpenArchiveAction extends DockingAction { DataTypeManagerHandler manager = plugin.getDataTypeManagerHandler(); File file = fileChooser.getSelectedFile(); + fileChooser.dispose(); if (file == null) { return; } diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/archive/ArchiveUtils.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/archive/ArchiveUtils.java index 9666fdc316..b45d8b0031 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/archive/ArchiveUtils.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/archive/ArchiveUtils.java @@ -119,7 +119,7 @@ public class ArchiveUtils { ArchiveFileChooser fileChooser = new ArchiveFileChooser(component); String archiveName = archive.getName(); File file = fileChooser.promptUserForFile(archiveName); - + fileChooser.dispose(); if (file == null) { return null; } diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/archive/DataTypeManagerHandler.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/archive/DataTypeManagerHandler.java index ba12a297cf..244808a79f 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/archive/DataTypeManagerHandler.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/archive/DataTypeManagerHandler.java @@ -73,8 +73,6 @@ public class DataTypeManagerHandler { private Set knownOpenFileArchiveNames = new HashSet<>(); private Map invalidArchives = new HashMap<>(); - private DataTreeDialog dataTreeSaveDialog; - private CreateDataTypeArchiveDataTreeDialog dataTreeCreateDialog; private boolean treeDialogCancelled = false; private DomainFileFilter createArchiveFileFilter; @@ -1409,77 +1407,74 @@ public class DataTypeManagerHandler { } private DataTreeDialog getSaveDialog() { - if (dataTreeSaveDialog == null) { + DataTreeDialog dialog = + new DataTreeDialog(null, "Save As", DataTreeDialog.SAVE, createArchiveFileFilter); - ActionListener listener = event -> { - DomainFolder folder = dataTreeSaveDialog.getDomainFolder(); - String newName = dataTreeSaveDialog.getNameText(); - if (newName.length() == 0) { - dataTreeSaveDialog.setStatusText("Please enter a name"); - return; - } - else if (folder == null) { - dataTreeSaveDialog.setStatusText("Please select a folder"); - return; - } + ActionListener listener = event -> { + DomainFolder folder = dialog.getDomainFolder(); + String newName = dialog.getNameText(); + if (newName.length() == 0) { + dialog.setStatusText("Please enter a name"); + return; + } + else if (folder == null) { + dialog.setStatusText("Please select a folder"); + return; + } - DomainFile file = folder.getFile(newName); - if (file != null && file.isReadOnly()) { - dataTreeSaveDialog.setStatusText("Read Only. Choose new name/folder"); - } - else { - dataTreeSaveDialog.close(); - treeDialogCancelled = false; - } - }; - dataTreeSaveDialog = - new DataTreeDialog(null, "Save As", DataTreeDialog.SAVE, createArchiveFileFilter); + DomainFile file = folder.getFile(newName); + if (file != null && file.isReadOnly()) { + dialog.setStatusText("Read Only. Choose new name/folder"); + } + else { + dialog.close(); + treeDialogCancelled = false; + } + }; - dataTreeSaveDialog.addOkActionListener(listener); - dataTreeSaveDialog - .setHelpLocation(new HelpLocation(HelpTopics.PROGRAM, "Save_As_File")); - } - return dataTreeSaveDialog; + dialog.addOkActionListener(listener); + dialog.setHelpLocation(new HelpLocation(HelpTopics.PROGRAM, "Save_As_File")); + return dialog; } private CreateDataTypeArchiveDataTreeDialog getCreateDialog() { - if (dataTreeCreateDialog == null) { - ActionListener listener = event -> { - DomainFolder folder = dataTreeCreateDialog.getDomainFolder(); - String newName = dataTreeCreateDialog.getNameText(); - if (newName.length() == 0) { - dataTreeCreateDialog.setStatusText("Please enter a name"); - return; - } - else if (folder == null) { - dataTreeCreateDialog.setStatusText("Please select a folder"); - return; - } - - DomainFile file = folder.getFile(newName); - if (file != null) { - dataTreeCreateDialog.setStatusText("Choose a name that doesn't exist."); - return; - } - - if (!dataTreeCreateDialog.createNewDataTypeArchive()) { - return; - } - - // everything is OK - dataTreeCreateDialog.close(); - treeDialogCancelled = false; - }; - - dataTreeCreateDialog = new CreateDataTypeArchiveDataTreeDialog(null, "Create", + CreateDataTypeArchiveDataTreeDialog dialog = + new CreateDataTypeArchiveDataTreeDialog(null, "Create", DataTreeDialog.CREATE, createArchiveFileFilter); - dataTreeCreateDialog.addOkActionListener(listener); - dataTreeCreateDialog.setHelpLocation( - new HelpLocation(HelpTopics.DATA_MANAGER, "Create_Data_Type_Archive")); - } - return dataTreeCreateDialog; + ActionListener listener = event -> { + DomainFolder folder = dialog.getDomainFolder(); + String newName = dialog.getNameText(); + if (newName.length() == 0) { + dialog.setStatusText("Please enter a name"); + return; + } + else if (folder == null) { + dialog.setStatusText("Please select a folder"); + return; + } + + DomainFile file = folder.getFile(newName); + if (file != null) { + dialog.setStatusText("Choose a name that doesn't exist."); + return; + } + + if (!dialog.createNewDataTypeArchive()) { + return; + } + + // everything is OK + dialog.close(); + treeDialogCancelled = false; + }; + + dialog.addOkActionListener(listener); + dialog.setHelpLocation( + new HelpLocation(HelpTopics.DATA_MANAGER, "Create_Data_Type_Archive")); + + return dialog; } public DataTypeManager getDataTypeManager(SourceArchive source) { @@ -1520,14 +1515,14 @@ public class DataTypeManagerHandler { return true; } catch (DuplicateNameException e) { - dataTreeCreateDialog.setStatusText("Duplicate Name: " + e.getMessage()); + setStatusText("Duplicate Name: " + e.getMessage()); } catch (InvalidNameException e) { - dataTreeCreateDialog.setStatusText("Invalid Name: " + e.getMessage()); + setStatusText("Invalid Name: " + e.getMessage()); } catch (IOException e) { - dataTreeCreateDialog.setStatusText("Unexpected IOException!"); - Msg.showError(null, dataTreeCreateDialog.getComponent(), "Unexpected Exception", + setStatusText("Unexpected IOException!"); + Msg.showError(null, getComponent(), "Unexpected Exception", e.getMessage(), e); } diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/util/ConflictDialog.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/util/ConflictDialog.java deleted file mode 100644 index 2b7cfb779e..0000000000 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/util/ConflictDialog.java +++ /dev/null @@ -1,150 +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.plugin.core.datamgr.util; - -import java.awt.BorderLayout; -import java.awt.event.ItemEvent; -import java.awt.event.ItemListener; - -import javax.swing.*; - -import docking.DialogComponentProvider; -import docking.widgets.button.GRadioButton; -import docking.widgets.label.GIconLabel; -import docking.widgets.label.GLabel; -import generic.theme.GIcon; -import ghidra.util.HelpLocation; - -/** - * Dialog to get user input on how to handle data type conflicts. - */ -public class ConflictDialog extends DialogComponentProvider { - - final static int REPLACE = 1; - final static int USE_EXISTING = 2; - final static int RENAME = 3; - - private boolean applyToAll; - private JRadioButton replaceRB; - private JRadioButton useExistingRB; - private JRadioButton renameRB; - private JButton applyToAllButton; - private int selectedOption = RENAME; - - private Icon INFORM_ICON = new GIcon("icon.warning"); - - /** - * Constructor - * @param dtName data type name - * @param categoryPath category path - * @param newDTName new name to resolve conflict - */ - public ConflictDialog(String dtName, String categoryPath, String newDTName) { - super("Data Type Conflict for " + dtName); - setHelpLocation(new HelpLocation("DataManagerPlugin", "DataTypeConflicts")); - addWorkPanel(buildMainPanel(dtName, categoryPath, newDTName)); - - addOKButton(); - applyToAllButton = new JButton("Apply to All"); - applyToAllButton.addActionListener(e -> { - applyToAll = true; - close(); - }); - addButton(applyToAllButton); - } - - @Override - protected void okCallback() { - close(); - } - - @Override - protected void cancelCallback() { - close(); - } - - int getSelectedOption() { - return selectedOption; - } - - boolean applyChoiceToAll() { - return applyToAll; - } - - private JPanel buildMainPanel(String dtName, String categoryPath, String newDTName) { - JPanel outerPanel = new JPanel(new BorderLayout(20, 0)); - - outerPanel.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5)); - JPanel mainPanel = new JPanel(); - mainPanel.setBorder(BorderFactory.createTitledBorder("Resolve Data Type Conflict")); - - mainPanel.setLayout(new BoxLayout(mainPanel, BoxLayout.Y_AXIS)); - - ItemListener listener = e -> { - if (e.getStateChange() == ItemEvent.SELECTED) { - Object source = e.getSource(); - if (source == replaceRB) { - selectedOption = REPLACE; - } - else if (source == useExistingRB) { - selectedOption = USE_EXISTING; - } - else { - selectedOption = RENAME; - } - } - }; - - ButtonGroup bg = new ButtonGroup(); - renameRB = new GRadioButton("Rename new data type to " + newDTName, true); - replaceRB = new GRadioButton("Replace existing data type"); - useExistingRB = new GRadioButton("Use existing data type"); - - renameRB.addItemListener(listener); - useExistingRB.addItemListener(listener); - replaceRB.addItemListener(listener); - - bg.add(renameRB); - bg.add(replaceRB); - bg.add(useExistingRB); - - mainPanel.add(Box.createVerticalStrut(5)); - mainPanel.add(renameRB); - mainPanel.add(replaceRB); - mainPanel.add(useExistingRB); - - outerPanel.add(createLabelPanel(dtName, categoryPath), BorderLayout.NORTH); - outerPanel.add(mainPanel, BorderLayout.CENTER); - return outerPanel; - } - - private JPanel createLabelPanel(String dtName, String categoryPath) { - JPanel labelPanel = new JPanel(); - labelPanel.setBorder(BorderFactory.createEmptyBorder(10, 0, 0, 20)); - BoxLayout bl = new BoxLayout(labelPanel, BoxLayout.X_AXIS); - labelPanel.setLayout(bl); - labelPanel.add(Box.createHorizontalStrut(5)); - labelPanel.add(new GIconLabel(INFORM_ICON)); - labelPanel.add(Box.createHorizontalStrut(5)); - labelPanel.add(new GLabel("Conflict exists in " + categoryPath + " for " + dtName)); - - JPanel panel = new JPanel(new BorderLayout()); - panel.add(labelPanel); - panel.setBorder(BorderFactory.createEmptyBorder(0, 0, 20, 0)); - return panel; - } - -} diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datawindow/DataWindowPlugin.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datawindow/DataWindowPlugin.java index ac48780d16..1954262ac9 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datawindow/DataWindowPlugin.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datawindow/DataWindowPlugin.java @@ -219,7 +219,6 @@ public class DataWindowPlugin extends ProgramPlugin implements DomainObjectListe filterAction.addType(type.getDisplayName()); } filterAction.selectTypes(selectedList); - filterAction.repaint(); provider.reload(); } } diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datawindow/FilterAction.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datawindow/FilterAction.java index 64c2d52027..d51a491813 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datawindow/FilterAction.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datawindow/FilterAction.java @@ -52,8 +52,6 @@ class FilterAction extends ToggleDockingAction { private boolean viewMode = false; private boolean selectionMode = false; - private FilterDialog dialog; - private static class SortMapComparatorASC implements Comparator { @Override @@ -82,10 +80,7 @@ class FilterAction extends ToggleDockingAction { @Override public void actionPerformed(ActionContext context) { - if (dialog == null) { - dialog = new FilterDialog(); - } - + FilterDialog dialog = new FilterDialog(); dialog.setSelectionEnabled(plugin.getSelection() != null); dialog.updateButtonEnabledState(); plugin.getTool().showDialog(dialog); @@ -93,19 +88,11 @@ class FilterAction extends ToggleDockingAction { synchronized void clearTypes() { typeEnabledMap.clear(); - - if (dialog != null) { - dialog.clearTypes(); - } } synchronized void addType(String type) { - Boolean bool = new Boolean(!filterEnabled); + Boolean bool = !filterEnabled; typeEnabledMap.put(type, bool); - - if (dialog != null) { - dialog.createCheckBox(type, type, bool.booleanValue()); - } } synchronized boolean typeEnabled(String type) { @@ -137,16 +124,6 @@ class FilterAction extends ToggleDockingAction { for (String element : list) { typeEnabledMap.put(element, Boolean.TRUE); } - if (dialog != null) { - dialog.selectTypes(list); - } - } - - void repaint() { - if (dialog == null) { - return; - } - dialog.repaint(); } boolean getViewMode() { @@ -170,7 +147,6 @@ class FilterAction extends ToggleDockingAction { filterEnabled = false; viewMode = false; selectionMode = false; - dialog = null; setEnabled(false); clearTypes(); } diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/disassembler/AddressTableDialog.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/disassembler/AddressTableDialog.java index 9ba9b60d61..40603ca4f2 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/disassembler/AddressTableDialog.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/disassembler/AddressTableDialog.java @@ -23,7 +23,7 @@ import javax.swing.*; import javax.swing.event.DocumentEvent; import javax.swing.event.DocumentListener; -import docking.DialogComponentProvider; +import docking.ReusableDialogComponentProvider; import docking.action.DockingAction; import docking.widgets.checkbox.GCheckBox; import docking.widgets.label.GDLabel; @@ -39,7 +39,7 @@ import ghidra.util.table.*; import ghidra.util.table.actions.MakeProgramSelectionAction; import ghidra.util.task.Task; -public class AddressTableDialog extends DialogComponentProvider { +public class AddressTableDialog extends ReusableDialogComponentProvider { private static final int DEFAULT_MINIMUM_TABLE_SIZE = 3; private static final String DIALOG_NAME = "Search For Address Tables"; diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/editor/TextEditorComponentProvider.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/editor/TextEditorComponentProvider.java index 28597cca52..3be338b441 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/editor/TextEditorComponentProvider.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/editor/TextEditorComponentProvider.java @@ -44,9 +44,9 @@ public class TextEditorComponentProvider extends ComponentProviderAdapter { private static final String TITLE = "Text Editor"; private static final String FONT_ID = "font.plugin.service.text.editor"; private static final int MAX_UNDO_REDO_SIZE = 50; + private static final String LAST_SAVED_TEXT_FILE_DIR = "LastSavedTextFileDirectory"; private TextEditorManagerPlugin plugin; - private GhidraFileChooser chooser; private File textFile; private String textFileName; private DockingAction saveAction; @@ -146,17 +146,13 @@ public class TextEditorComponentProvider extends ComponentProviderAdapter { } private String loadTextFile(InputStream inputStream) throws IOException { - BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream)); - try { + try (BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream))) { return loadTextFile(reader); } - finally { - reader.close(); - } } private String loadTextFile(BufferedReader reader) throws IOException { - StringBuffer buffer = new StringBuffer(); + StringBuilder buffer = new StringBuilder(); while (true) { String line = reader.readLine(); if (line == null) { @@ -290,21 +286,25 @@ public class TextEditorComponentProvider extends ComponentProviderAdapter { } catch (IOException e) { if (textFile.canWrite()) { - Msg.showError(getClass(), getComponent(), "Error saving file", e.getMessage()); + Msg.showError(getClass(), getComponent(), "Error Saving File", + "Unable to save file", e); } else { Msg.showError(getClass(), getComponent(), "Error Saving File", - "The file is not writable."); + "The file is not writable"); } } } } private void saveAs() { - if (chooser == null) { - chooser = new GhidraFileChooser(getComponent()); - } + + GhidraFileChooser chooser = new GhidraFileChooser(getComponent()); + + chooser.setLastDirectoryPreference(LAST_SAVED_TEXT_FILE_DIR); + File saveAsFile = chooser.getSelectedFile(); + chooser.dispose(); if (saveAsFile == null) { return; } @@ -344,6 +344,7 @@ public class TextEditorComponentProvider extends ComponentProviderAdapter { public void closeComponent() { if (plugin.removeTextFile(this, textFileName)) { clearUndoRedoStack(); + super.closeComponent(); plugin.getTool().removeComponentProvider(this); } } diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/exporter/ExporterDialog.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/exporter/ExporterDialog.java index 5bfb13dfbb..5e8dd0e872 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/exporter/ExporterDialog.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/exporter/ExporterDialog.java @@ -269,6 +269,7 @@ public class ExporterDialog extends DialogComponentProvider implements AddressFa setLastExportDirectory(file); filePathTextField.setText(file.getAbsolutePath()); } + chooser.dispose(); } private void setLastExportDirectory(File file) { diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/function/CommentDialog.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/function/CommentDialog.java index 1dc6712dee..412920e005 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/function/CommentDialog.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/function/CommentDialog.java @@ -1,6 +1,5 @@ /* ### * IP: GHIDRA - * REVIEWED: YES * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,119 +15,118 @@ */ package ghidra.app.plugin.core.function; -import ghidra.app.util.PluginConstants; -import ghidra.framework.plugintool.PluginTool; - import java.awt.BorderLayout; import java.awt.event.KeyAdapter; import java.awt.event.KeyEvent; import javax.swing.*; -import docking.DialogComponentProvider; +import docking.ReusableDialogComponentProvider; +import ghidra.app.util.PluginConstants; +import ghidra.framework.plugintool.PluginTool; -abstract class CommentDialog extends DialogComponentProvider { - private JTextArea commentsField; +abstract class CommentDialog extends ReusableDialogComponentProvider { + private JTextArea commentsField; - private boolean applyWasDone; - private String origComments; + private boolean applyWasDone; + private String origComments; - protected FunctionPlugin plugin; + protected FunctionPlugin plugin; - CommentDialog(FunctionPlugin plugin) { - // changed name - super("Set Comment"); - addWorkPanel(createPanel()); - addListeners(); + CommentDialog(FunctionPlugin plugin) { + // changed name + super("Set Comment"); + addWorkPanel(createPanel()); + addListeners(); - addOKButton(); - addApplyButton(); - addCancelButton(); - this.plugin = plugin; - } + addOKButton(); + addApplyButton(); + addCancelButton(); + this.plugin = plugin; + } - void showDialog(String comment) { - applyWasDone = true; - origComments = comment; + void showDialog(String comment) { + applyWasDone = true; + origComments = comment; - commentsField.setText(origComments); - if (origComments != null && origComments.length() > 0) { - commentsField.selectAll(); - } - PluginTool tool = plugin.getTool(); - tool.showDialog( this, tool.getComponentProvider( - PluginConstants.CODE_BROWSER )); - } - - ///////////////////////////////////////////// - // *** GhidraDialog "callback" methods *** - ///////////////////////////////////////////// + commentsField.setText(origComments); + if (origComments != null && origComments.length() > 0) { + commentsField.selectAll(); + } + PluginTool tool = plugin.getTool(); + tool.showDialog(this, tool.getComponentProvider( + PluginConstants.CODE_BROWSER)); + } - /** - * Callback for the cancel button. - */ - @Override - protected void cancelCallback() { - close(); - } + ///////////////////////////////////////////// + // *** GhidraDialog "callback" methods *** + ///////////////////////////////////////////// - /** - * Callback for the OK button. - */ - @Override - protected void okCallback() { - applyCallback(); - close(); - } + /** + * Callback for the cancel button. + */ + @Override + protected void cancelCallback() { + close(); + } - /** - * Callback for the Apply button. - */ - @Override - protected void applyCallback() { - if (!applyWasDone) { - // Apply was hit - origComments = commentsField.getText(); - doApply(origComments); - applyWasDone = true; - } - } - - abstract protected void doApply(String comment); + /** + * Callback for the OK button. + */ + @Override + protected void okCallback() { + applyCallback(); + close(); + } - //////////////////////////////////////////////////////////////////// - // ** private methods ** - //////////////////////////////////////////////////////////////////// + /** + * Callback for the Apply button. + */ + @Override + protected void applyCallback() { + if (!applyWasDone) { + // Apply was hit + origComments = commentsField.getText(); + doApply(origComments); + applyWasDone = true; + } + } - /** - * Create the panel for the dialog. - */ - private JPanel createPanel() { + abstract protected void doApply(String comment); - JPanel panel = new JPanel(); - panel.setLayout(new BorderLayout()); + //////////////////////////////////////////////////////////////////// + // ** private methods ** + //////////////////////////////////////////////////////////////////// - JPanel p = new JPanel(); - commentsField = new JTextArea(10, 50); - commentsField.setLineWrap(true); - commentsField.setWrapStyleWord(true); - JScrollPane scrollP = new JScrollPane(commentsField); + /** + * Create the panel for the dialog. + */ + private JPanel createPanel() { - p.add(scrollP); - panel.add(scrollP, BorderLayout.CENTER); + JPanel panel = new JPanel(); + panel.setLayout(new BorderLayout()); - return panel; - } + JPanel p = new JPanel(); + commentsField = new JTextArea(10, 50); + commentsField.setLineWrap(true); + commentsField.setWrapStyleWord(true); + JScrollPane scrollP = new JScrollPane(commentsField); - /** - * Add listeners to the radio buttons. - */ - private void addListeners() { - commentsField.addKeyListener(new KeyAdapter() { - @Override - public void keyPressed(KeyEvent e) { - applyWasDone = false; - } - }); - } + p.add(scrollP); + panel.add(scrollP, BorderLayout.CENTER); + + return panel; + } + + /** + * Add listeners to the radio buttons. + */ + private void addListeners() { + commentsField.addKeyListener(new KeyAdapter() { + @Override + public void keyPressed(KeyEvent e) { + applyWasDone = false; + } + }); + } } diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/function/FunctionPlugin.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/function/FunctionPlugin.java index bbf69558f6..c625e6988c 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/function/FunctionPlugin.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/function/FunctionPlugin.java @@ -173,8 +173,7 @@ public class FunctionPlugin extends Plugin implements DataService { * Add the cycle group actions */ private void addCycleGroupActions() { - for (int i = 0; i < cgActions.size(); i++) { - DockingAction action = cgActions.get(i); + for (CycleGroupAction action : cgActions) { tool.removeAction(action); } cgActions.clear(); diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/function/VariableCommentAction.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/function/VariableCommentAction.java index 31b94a4f68..bf654d6b63 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/function/VariableCommentAction.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/function/VariableCommentAction.java @@ -60,16 +60,12 @@ class VariableCommentAction extends ListingContextAction { return; } VariableCommentDialog dialog = funcPlugin.getVariableCommentDialog(); - if (dialog == null) { - dialog = new VariableCommentDialog(funcPlugin); - } dialog.showDialog(function.getProgram(), var); } - ///////////////////////////////////////////////////////////// /** * Get a variable using the current location. - * @param function + * @param function the function * @return null if function is null or if current location is not * a stack variable location. */ diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/help/ProcessorListPlugin.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/help/ProcessorListPlugin.java index 39abac0831..936b17641b 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/help/ProcessorListPlugin.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/help/ProcessorListPlugin.java @@ -15,15 +15,14 @@ */ package ghidra.app.plugin.core.help; -import java.util.*; - import java.awt.datatransfer.Clipboard; import java.awt.datatransfer.Transferable; +import java.util.*; import javax.swing.*; import docking.ActionContext; -import docking.DialogComponentProvider; +import docking.ReusableDialogComponentProvider; import docking.action.DockingAction; import docking.action.MenuData; import docking.dnd.GClipboard; @@ -70,6 +69,10 @@ public class ProcessorListPlugin extends Plugin implements ApplicationLevelPlugi public void dispose() { tool.removeAction(processorListAction); processorListAction.dispose(); + + if (dialogProvider != null) { + dialogProvider.dispose(); + } super.dispose(); } @@ -154,7 +157,7 @@ public class ProcessorListPlugin extends Plugin implements ApplicationLevelPlugi return strBuilder.toString(); } - class ProcessorListDialogProvider extends DialogComponentProvider { + class ProcessorListDialogProvider extends ReusableDialogComponentProvider { ProcessorListDialogProvider() { super("Installed Processor Modules", false, false, true, false); diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/instructionsearch/InstructionSearchPlugin.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/instructionsearch/InstructionSearchPlugin.java index 123bd91d8e..67fea0d700 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/instructionsearch/InstructionSearchPlugin.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/instructionsearch/InstructionSearchPlugin.java @@ -94,6 +94,16 @@ public class InstructionSearchPlugin extends ProgramPlugin { createActions(); } + @Override + protected void dispose() { + super.dispose(); + + if (searchDialog != null) { + searchDialog.dispose(); + } + + } + public InstructionSearchDialog getSearchDialog() { return searchDialog; } diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/instructionsearch/ui/InsertBytesWidget.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/instructionsearch/ui/InsertBytesWidget.java index 154a7db003..d878427944 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/instructionsearch/ui/InsertBytesWidget.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/instructionsearch/ui/InsertBytesWidget.java @@ -25,7 +25,7 @@ import java.util.List; import javax.swing.JPanel; import javax.swing.JScrollPane; -import docking.DialogComponentProvider; +import docking.ReusableDialogComponentProvider; import generic.theme.GThemeDefaults.Colors.Messages; import ghidra.app.plugin.core.instructionsearch.model.*; import ghidra.app.plugin.core.instructionsearch.ui.SelectionModeWidget.InputMode; @@ -43,7 +43,7 @@ import ghidra.util.SystemUtilities; * will then be disassembled and displayed in the {@link InstructionTable}. * */ -public class InsertBytesWidget extends DialogComponentProvider implements KeyListener { +public class InsertBytesWidget extends ReusableDialogComponentProvider implements KeyListener { // The input text area. This is a generic JTextArea but displays a textual 'hint' to inform // the user of what type of input is required. diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/instructionsearch/ui/InstructionSearchDialog.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/instructionsearch/ui/InstructionSearchDialog.java index 9d7beb1fdb..6f36b209db 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/instructionsearch/ui/InstructionSearchDialog.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/instructionsearch/ui/InstructionSearchDialog.java @@ -22,7 +22,7 @@ import java.util.*; import javax.swing.*; import docking.ComponentProvider; -import docking.DialogComponentProvider; +import docking.ReusableDialogComponentProvider; import generic.theme.GColor; import generic.theme.GThemeDefaults.Colors.Messages; import ghidra.app.events.ProgramSelectionPluginEvent; @@ -61,7 +61,7 @@ import ghidra.util.task.TaskMonitor; * ------------------------------------ */ -public class InstructionSearchDialog extends DialogComponentProvider implements Observer { +public class InstructionSearchDialog extends ReusableDialogComponentProvider implements Observer { private static final Color BG_COLOR_MARKERS = new GColor("color.bg.plugin.instructionsearch.search.markers"); diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/instructionsearch/ui/InstructionTablePanel.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/instructionsearch/ui/InstructionTablePanel.java index 08ea3ef4c4..747f69b435 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/instructionsearch/ui/InstructionTablePanel.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/instructionsearch/ui/InstructionTablePanel.java @@ -41,12 +41,6 @@ public class InstructionTablePanel extends JPanel { private JPanel workPanel; - /** - * - * @param numColumns - * @param plugin - * @param dialog - */ public InstructionTablePanel(int numColumns, InstructionSearchPlugin plugin, InstructionSearchDialog dialog) { @@ -74,11 +68,6 @@ public class InstructionTablePanel extends JPanel { return workPanel; } - /********************************************************************************************* - * PRIVATE METHODS - * @throws InvalidInputException - ********************************************************************************************/ - private void setup() throws InvalidInputException { workPanel = new JPanel(); diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/label/LabelMgrPlugin.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/label/LabelMgrPlugin.java index 73225710aa..396d0cfec0 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/label/LabelMgrPlugin.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/label/LabelMgrPlugin.java @@ -49,9 +49,7 @@ import ghidra.util.Msg; //@formatter:on public class LabelMgrPlugin extends Plugin { - private OperandLabelDialog operandDialog; private AddEditDialog addEditDialog; - private EditFieldNameDialog editFieldDialog; /** * Constructor @@ -62,6 +60,8 @@ public class LabelMgrPlugin extends Plugin { super(tool); // Setup list of actions setupActions(); + + addEditDialog = new AddEditDialog("", tool); } private void setupActions() { @@ -88,25 +88,21 @@ public class LabelMgrPlugin extends Plugin { tool.addAction(allHistoryAction); } + @Override + protected void dispose() { + addEditDialog.dispose(); + } + AddEditDialog getAddEditDialog() { - if (addEditDialog == null) { - addEditDialog = new AddEditDialog("", tool); - } return addEditDialog; } EditFieldNameDialog getEditFieldDialog() { - if (editFieldDialog == null) { - editFieldDialog = new EditFieldNameDialog("", tool); - } - return editFieldDialog; + return new EditFieldNameDialog("", tool); } OperandLabelDialog getOperandLabelDialog() { - if (operandDialog == null) { - operandDialog = new OperandLabelDialog(this); - } - return operandDialog; + return new OperandLabelDialog(this); } /** diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/memory/MemoryMapProvider.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/memory/MemoryMapProvider.java index 1b7d304f91..aca8fb37d5 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/memory/MemoryMapProvider.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/memory/MemoryMapProvider.java @@ -614,8 +614,11 @@ class MemoryMapProvider extends ComponentProviderAdapter { else { model = new ExpandBlockDownModel(tool, program); } - new ExpandBlockDialog(tool, model, block, program.getAddressFactory(), dialogType); + + ExpandBlockDialog dialog = + new ExpandBlockDialog(tool, model, block, program.getAddressFactory(), dialogType); model.initialize(block); + dialog.dispose(); } private void showMoveBlockDialog(MemoryBlock block) { diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/memory/SplitBlockDialog.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/memory/SplitBlockDialog.java index a2d35f2c74..3b41270b58 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/memory/SplitBlockDialog.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/memory/SplitBlockDialog.java @@ -16,7 +16,6 @@ package ghidra.app.plugin.core.memory; import java.awt.Cursor; -import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import javax.swing.*; @@ -54,12 +53,6 @@ class SplitBlockDialog extends DialogComponentProvider { private AddressFactory addrFactory; private MemoryMapPlugin plugin; - /** - * Constructor - * @param parent - * @param block - * @param af - */ SplitBlockDialog(MemoryMapPlugin plugin, MemoryBlock block, AddressFactory af) { super("Split Block"); this.plugin = plugin; @@ -74,9 +67,6 @@ class SplitBlockDialog extends DialogComponentProvider { addListeners(); } - /** - * @see ghidra.util.bean.GhidraDialog#okCallback() - */ @Override protected void okCallback() { // call plugin to do the work @@ -195,12 +185,7 @@ class SplitBlockDialog extends DialogComponentProvider { blockOneEnd.addChangeListener(new AddressChangeListener(blockOneEnd)); blockTwoStart.addChangeListener(new AddressChangeListener(blockTwoStart)); - ActionListener al = new ActionListener() { - @Override - public void actionPerformed(ActionEvent e) { - setStatusText(""); - } - }; + ActionListener al = e -> setStatusText(""); blockOneLengthField.addActionListener(al); blockTwoLengthField.addActionListener(al); blockOneEnd.addActionListener(al); diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/navigation/locationreferences/LocationReferencesProvider.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/navigation/locationreferences/LocationReferencesProvider.java index 911b1c1893..4a76e9cd3a 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/navigation/locationreferences/LocationReferencesProvider.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/navigation/locationreferences/LocationReferencesProvider.java @@ -366,6 +366,7 @@ public class LocationReferencesProvider extends ComponentProviderAdapter @Override public void closeComponent() { + super.closeComponent(); locationReferencesPlugin.providerDismissed(this); } diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/osgi/BundleStatusComponentProvider.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/osgi/BundleStatusComponentProvider.java index c97b5bafbb..53786cfb7a 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/osgi/BundleStatusComponentProvider.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/osgi/BundleStatusComponentProvider.java @@ -60,7 +60,6 @@ public class BundleStatusComponentProvider extends ComponentProviderAdapter { private final BundleStatusTableModel bundleStatusTableModel; private GTableFilterPanel filterPanel; - private GhidraFileChooser fileChooser; private GhidraFileFilter filter; private final BundleHost bundleHost; private transient boolean isDisposed; @@ -94,7 +93,6 @@ public class BundleStatusComponentProvider extends ComponentProviderAdapter { return GhidraBundle.getType(file) != GhidraBundle.Type.INVALID; } }; - this.fileChooser = null; build(); addToTool(); @@ -249,38 +247,29 @@ public class BundleStatusComponentProvider extends ComponentProviderAdapter { } private void showAddBundlesFileChooser() { - if (fileChooser == null) { - fileChooser = new GhidraFileChooser(getComponent()); - fileChooser.setMultiSelectionEnabled(true); - fileChooser.setFileSelectionMode(GhidraFileChooserMode.FILES_AND_DIRECTORIES); - fileChooser.setTitle("Select Bundle(s)"); - // fileChooser.setApproveButtonToolTipText(title); - if (filter != null) { - fileChooser.addFileFilter(new GhidraFileFilter() { - @Override - public String getDescription() { - return filter.getDescription(); - } - @Override - public boolean accept(File f, GhidraFileChooserModel model) { - return filter.accept(f, model); - } - }); - } - String lastSelected = Preferences.getProperty(PREFERENCE_LAST_SELECTED_BUNDLE); - if (lastSelected != null) { - File lastSelectedFile = new File(lastSelected); - fileChooser.setSelectedFile(lastSelectedFile); - } + GhidraFileChooser fileChooser = new GhidraFileChooser(getComponent()); + fileChooser.setMultiSelectionEnabled(true); + fileChooser.setFileSelectionMode(GhidraFileChooserMode.FILES_AND_DIRECTORIES); + fileChooser.setTitle("Select Bundle(s)"); + // fileChooser.setApproveButtonToolTipText(title); + if (filter != null) { + fileChooser.addFileFilter(new GhidraFileFilter() { + @Override + public String getDescription() { + return filter.getDescription(); + } + + @Override + public boolean accept(File f, GhidraFileChooserModel model) { + return filter.accept(f, model); + } + }); } - else { - String lastSelected = Preferences.getProperty(PREFERENCE_LAST_SELECTED_BUNDLE); - if (lastSelected != null) { - File lastSelectedFile = new File(lastSelected); - fileChooser.setSelectedFile(lastSelectedFile); - } - fileChooser.rescanCurrentDirectory(); + String lastSelected = Preferences.getProperty(PREFERENCE_LAST_SELECTED_BUNDLE); + if (lastSelected != null) { + File lastSelectedFile = new File(lastSelected); + fileChooser.setSelectedFile(lastSelectedFile); } List files = fileChooser.getSelectedFiles(); @@ -304,6 +293,8 @@ public class BundleStatusComponentProvider extends ComponentProviderAdapter { } }); } + + fileChooser.dispose(); } protected List getSelectedStatuses() { diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/overview/addresstype/AddressTypeOverviewColorService.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/overview/addresstype/AddressTypeOverviewColorService.java index 26b590edeb..109b14426f 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/overview/addresstype/AddressTypeOverviewColorService.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/overview/addresstype/AddressTypeOverviewColorService.java @@ -69,7 +69,6 @@ public class AddressTypeOverviewColorService private Listing listing; private OverviewColorComponent overviewComponent; private PluginTool tool; - private DialogComponentProvider legendDialog; private AddressTypeOverviewLegendPanel legendPanel; @Override @@ -336,12 +335,12 @@ public class AddressTypeOverviewColorService } private DialogComponentProvider getLegendDialog() { - if (legendDialog == null) { + if (legendPanel == null) { legendPanel = new AddressTypeOverviewLegendPanel(this); - - legendDialog = - new OverviewColorLegendDialog("Overview Legend", legendPanel, getHelpLocation()); } + + OverviewColorLegendDialog legendDialog = + new OverviewColorLegendDialog("Overview Legend", legendPanel, getHelpLocation()); return legendDialog; } diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/overview/entropy/EntropyOverviewColorService.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/overview/entropy/EntropyOverviewColorService.java index ff26592b01..f30270a506 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/overview/entropy/EntropyOverviewColorService.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/overview/entropy/EntropyOverviewColorService.java @@ -45,7 +45,6 @@ public class EntropyOverviewColorService implements OverviewColorService { private OverviewPalette palette; private EntropyOverviewOptionsManager entropyOptionsManager; private OverviewColorComponent overviewComponent; - private OverviewColorLegendDialog legendDialog; @Override public String getName() { @@ -193,9 +192,6 @@ public class EntropyOverviewColorService implements OverviewColorService { if (overviewComponent != null) { overviewComponent.refreshAll(); } - if (legendDialog != null) { - legendDialog.refresh(); - } } @Override @@ -219,12 +215,11 @@ public class EntropyOverviewColorService implements OverviewColorService { } private DialogComponentProvider getLegendDialog() { - if (legendDialog == null) { - LegendPanel legendPanel = new LegendPanel(); - legendPanel.setPalette(palette); - legendDialog = - new OverviewColorLegendDialog("Entropy Legend", legendPanel, getHelpLocation()); - } + + LegendPanel legendPanel = new LegendPanel(); + legendPanel.setPalette(palette); + OverviewColorLegendDialog legendDialog = + new OverviewColorLegendDialog("Entropy Legend", legendPanel, getHelpLocation()); return legendDialog; } } diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/printing/PrintOptionsDialog.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/printing/PrintOptionsDialog.java index 059cd32b20..c2e622c005 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/printing/PrintOptionsDialog.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/printing/PrintOptionsDialog.java @@ -20,13 +20,13 @@ import java.awt.event.*; import javax.swing.*; -import docking.DialogComponentProvider; +import docking.ReusableDialogComponentProvider; import docking.widgets.button.GRadioButton; import docking.widgets.checkbox.GCheckBox; import generic.theme.Gui; import ghidra.util.HelpLocation; -public class PrintOptionsDialog extends DialogComponentProvider { +public class PrintOptionsDialog extends ReusableDialogComponentProvider { private static final String FONT_ID = "font.print"; private boolean selectionEnabled; diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/printing/PrintingPlugin.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/printing/PrintingPlugin.java index ba418b1de9..cc900ab836 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/printing/PrintingPlugin.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/printing/PrintingPlugin.java @@ -76,6 +76,15 @@ public class PrintingPlugin extends ProgramPlugin { cvService = tool.getService(CodeViewerService.class); } + @Override + protected void dispose() { + super.dispose(); + + if (pod != null) { + pod.dispose(); + } + } + @Override protected void programActivated(Program program) { printAction.setEnabled(true); @@ -336,19 +345,19 @@ public class PrintingPlugin extends ProgramPlugin { while (curAddress.compareTo(curRange.getMaxAddress()) <= 0) { //Add the layout for the present address BigInteger curIndex = indexMap.getIndex(curAddress); - + // curIndex may be null when processing resource images; just // move to the next address and try again. if (curIndex == null) { curAddress = curAddress.next(); - + if (curAddress == null) { break; } - + continue; } - + if (!curIndex.equals(lastIndex)) { Layout layout = lm.getLayout(curIndex); if (layout != null) { diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/progmgr/ProgramManagerPlugin.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/progmgr/ProgramManagerPlugin.java index d69dd31b39..9be3c62080 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/progmgr/ProgramManagerPlugin.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/progmgr/ProgramManagerPlugin.java @@ -16,7 +16,6 @@ package ghidra.app.plugin.core.progmgr; import java.awt.Component; -import java.awt.event.ActionListener; import java.beans.PropertyEditor; import java.net.MalformedURLException; import java.net.URL; @@ -83,12 +82,13 @@ public class ProgramManagerPlugin extends Plugin implements ProgramManager { private MultiProgramManager programMgr; private ProgramSaveManager programSaveMgr; private int transactionID = -1; - private OpenVersionedFileDialog openDialog; private boolean locked = false; private UndoAction undoAction; private RedoAction redoAction; private ProgramLocation currentLocation; + private OpenVersionedFileDialog openDialog; + public ProgramManagerPlugin(PluginTool tool) { super(tool); @@ -297,6 +297,9 @@ public class ProgramManagerPlugin extends Plugin implements ProgramManager { public void dispose() { programMgr.dispose(); tool.clearLastEvents(); + if (openDialog != null) { + openDialog.dispose(); + } } @Override @@ -567,6 +570,7 @@ public class ProgramManagerPlugin extends Plugin implements ProgramManager { }); dialog.setHelpLocation(new HelpLocation(HelpTopics.PROGRAM, "Program_Options")); tool.showDialog(dialog); + dialog.dispose(); } /** @@ -605,8 +609,12 @@ public class ProgramManagerPlugin extends Plugin implements ProgramManager { } private void open() { + if (openDialog == null) { - ActionListener listener = e -> { + openDialog = new OpenVersionedFileDialog<>(tool, "Open Program", Program.class); + openDialog.setHelpLocation(new HelpLocation(HelpTopics.PROGRAM, "Open_File_Dialog")); + + openDialog.addOkActionListener(e -> { DomainFile domainFile = openDialog.getDomainFile(); int version = openDialog.getVersion(); if (domainFile == null) { @@ -616,11 +624,9 @@ public class ProgramManagerPlugin extends Plugin implements ProgramManager { openDialog.close(); doOpenProgram(domainFile, version, OPEN_CURRENT); } - }; - openDialog = new OpenVersionedFileDialog<>(tool, "Open Program", Program.class); - openDialog.setHelpLocation(new HelpLocation(HelpTopics.PROGRAM, "Open_File_Dialog")); - openDialog.addOkActionListener(listener); + }); } + tool.showDialog(openDialog); contextChanged(); } diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/progmgr/ProgramSaveManager.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/progmgr/ProgramSaveManager.java index 6301568dd2..ab3dd9c489 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/progmgr/ProgramSaveManager.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/progmgr/ProgramSaveManager.java @@ -38,7 +38,6 @@ import ghidra.util.task.*; class ProgramSaveManager { private ProgramManager programMgr; private PluginTool tool; - private DataTreeDialog dataTreeSaveDialog; private boolean treeDialogCancelled; private DomainFileFilter domainFileFilter; @@ -450,37 +449,35 @@ class ProgramSaveManager { } private DataTreeDialog getSaveDialog() { - if (dataTreeSaveDialog == null) { + DataTreeDialog dialog = + new DataTreeDialog(null, "Save As", DataTreeDialog.SAVE, domainFileFilter); - ActionListener listener = event -> { - DomainFolder folder = dataTreeSaveDialog.getDomainFolder(); - String newName = dataTreeSaveDialog.getNameText(); - if (newName.length() == 0) { - dataTreeSaveDialog.setStatusText("Please enter a name"); - return; - } - else if (folder == null) { - dataTreeSaveDialog.setStatusText("Please select a folder"); - return; - } + ActionListener listener = event -> { + DomainFolder folder = dialog.getDomainFolder(); + String newName = dialog.getNameText(); + if (newName.length() == 0) { + dialog.setStatusText("Please enter a name"); + return; + } + else if (folder == null) { + dialog.setStatusText("Please select a folder"); + return; + } - DomainFile file = folder.getFile(newName); - if (file != null && file.isReadOnly()) { - dataTreeSaveDialog.setStatusText("Read Only. Choose new name/folder"); - } - else { - dataTreeSaveDialog.close(); - treeDialogCancelled = false; - } - }; - dataTreeSaveDialog = - new DataTreeDialog(null, "Save As", DataTreeDialog.SAVE, domainFileFilter); + DomainFile file = folder.getFile(newName); + if (file != null && file.isReadOnly()) { + dialog.setStatusText("Read Only. Choose new name/folder"); + } + else { + dialog.close(); + treeDialogCancelled = false; + } + }; - dataTreeSaveDialog.addOkActionListener(listener); - dataTreeSaveDialog.setHelpLocation( - new HelpLocation(HelpTopics.PROGRAM, "Save_As_File")); - } - return dataTreeSaveDialog; + dialog.addOkActionListener(listener); + dialog.setHelpLocation(new HelpLocation(HelpTopics.PROGRAM, "Save_As_File")); + + return dialog; } class SaveFileTask extends Task { diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/references/EditReferenceDialog.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/references/EditReferenceDialog.java index b4a55f4b46..6705dedddf 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/references/EditReferenceDialog.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/references/EditReferenceDialog.java @@ -19,12 +19,11 @@ import java.awt.*; import javax.swing.*; import javax.swing.border.*; -import javax.swing.event.ChangeEvent; import javax.swing.event.ChangeListener; import org.jdom.Element; -import docking.DialogComponentProvider; +import docking.ReusableDialogComponentProvider; import docking.widgets.button.GRadioButton; import ghidra.framework.options.SaveState; import ghidra.program.model.address.Address; @@ -35,7 +34,7 @@ import ghidra.program.model.symbol.Reference; import ghidra.util.HelpLocation; import ghidra.util.exception.AssertException; -public class EditReferenceDialog extends DialogComponentProvider { +public class EditReferenceDialog extends ReusableDialogComponentProvider { static final int PREFERRED_PANEL_HEIGHT = 190; static final int PREFERRED_PANEL_WIDTH = 450; @@ -63,7 +62,7 @@ public class EditReferenceDialog extends DialogComponentProvider { private boolean initializing; public EditReferenceDialog(ReferencesPlugin plugin) { - super("Edit Reference", true); + super("Edit Reference"); this.plugin = plugin; addWorkPanel(buildMainPanel()); addApplyButton(); @@ -72,17 +71,12 @@ public class EditReferenceDialog extends DialogComponentProvider { setDefaultButton(applyButton); } - /** - * Dispose of this dialog. - */ + @Override public void dispose() { close(); cleanup(); } - /** - * Returns the current code unit displayed. - */ CodeUnit getCurrentCodeUnit() { return instrPanel.getCurrentCodeUnit(); } @@ -120,15 +114,12 @@ public class EditReferenceDialog extends DialogComponentProvider { JPanel refTypePanel = new JPanel(new FlowLayout(FlowLayout.LEFT, 5, 5)); refTypePanel.setBorder(new TitledBorder(new EtchedBorder(), "Type of Reference")); - ChangeListener refChoiceListener = new ChangeListener() { - @Override - public void stateChanged(ChangeEvent e) { - Object src = e.getSource(); - if (src instanceof JRadioButton) { - JRadioButton refChoiceButton = (JRadioButton) src; - if (refChoiceButton.isSelected()) { - refChoiceActivated(refChoiceButton); - } + ChangeListener refChoiceListener = e -> { + Object src = e.getSource(); + if (src instanceof JRadioButton) { + JRadioButton refChoiceButton = (JRadioButton) src; + if (refChoiceButton.isSelected()) { + refChoiceActivated(refChoiceButton); } } }; diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/resources/ResourceActionsPlugin.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/resources/ResourceActionsPlugin.java index 9b17c73008..b956d386ce 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/resources/ResourceActionsPlugin.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/resources/ResourceActionsPlugin.java @@ -101,6 +101,7 @@ public class ResourceActionsPlugin extends Plugin { chooser.setApproveButtonText("Save Image As"); chooser.addFileFilter(GRAPHIC_FORMATS_FILTER); File f = chooser.getSelectedFile(); + chooser.dispose(); if (f != null) { if (f.exists() && OptionDialog.showYesNoDialog(tool.getActiveWindow(), "Overwrite Existing File?", @@ -146,6 +147,7 @@ public class ResourceActionsPlugin extends Plugin { chooser.setApproveButtonText("Save Image As"); chooser.addFileFilter(GRAPHIC_FORMATS_FILTER); File f = chooser.getSelectedFile(); + chooser.dispose(); if (f != null) { if (f.exists() && OptionDialog.showYesNoDialog(tool.getActiveWindow(), "Overwrite Existing File?", diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/script/GhidraScriptEditorComponentProvider.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/script/GhidraScriptEditorComponentProvider.java index 62bbdf4135..9d6101cd9f 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/script/GhidraScriptEditorComponentProvider.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/script/GhidraScriptEditorComponentProvider.java @@ -628,11 +628,15 @@ public class GhidraScriptEditorComponentProvider extends ComponentProvider { } private void closeComponentSavingAsNecessary() { - provider.removeScriptEditor(scriptSourceFile, true); + if (provider.removeScriptEditor(scriptSourceFile, true)) { + super.closeComponent(); + } } private void closeComponentWithoutSaving() { - provider.removeScriptEditor(scriptSourceFile, false); + if (provider.removeScriptEditor(scriptSourceFile, false)) { + super.closeComponent(); + } } @Override diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/searchmem/MemSearchDialog.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/searchmem/MemSearchDialog.java index 58a48bb5a8..ee57b50e27 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/searchmem/MemSearchDialog.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/searchmem/MemSearchDialog.java @@ -50,7 +50,7 @@ import ghidra.util.task.Task; * backward searching, proper endianness and whether to find just * the next occurrence or all of them in the program. */ -class MemSearchDialog extends DialogComponentProvider { +class MemSearchDialog extends ReusableDialogComponentProvider { static final String ADVANCED_BUTTON_NAME = "mem.search.advanced"; private static final String CODE_UNIT_SCOPE_NAME = "Code Unit Scope"; diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/searchtext/SearchTextDialog.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/searchtext/SearchTextDialog.java index d015d6a7c8..364c576c9b 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/searchtext/SearchTextDialog.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/searchtext/SearchTextDialog.java @@ -39,7 +39,7 @@ import ghidra.util.task.TaskMonitorComponent; /** * Dialog for showing options to search text in a Program. */ -class SearchTextDialog extends DialogComponentProvider { +class SearchTextDialog extends ReusableDialogComponentProvider { private static final int DEFAULT_MAX_ENTRIES = 10; diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/searchtext/SearchTextPlugin.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/searchtext/SearchTextPlugin.java index f7676357e2..003ea99e99 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/searchtext/SearchTextPlugin.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/searchtext/SearchTextPlugin.java @@ -179,14 +179,17 @@ public class SearchTextPlugin extends ProgramPlugin implements OptionsChangeList navigatable = null; - if (searchDialog != null && searchDialog.isVisible()) { - TaskMonitor taskMonitor = searchDialog.getTaskMonitorComponent(); - taskMonitor.cancel(); - searchDialog.dispose(); + if (searchDialog != null) { - if (searchAllTaskMonitor != null) { - searchAllTaskMonitor.cancel(); + if (searchDialog.isVisible()) { + TaskMonitor taskMonitor = searchDialog.getTaskMonitorComponent(); + taskMonitor.cancel(); + if (searchAllTaskMonitor != null) { + searchAllTaskMonitor.cancel(); + } } + + searchDialog.dispose(); } if (currentTask != null) { diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/select/SelectBlockDialog.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/select/SelectBlockDialog.java index 2303e14ac1..76c097d1b2 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/select/SelectBlockDialog.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/select/SelectBlockDialog.java @@ -16,14 +16,12 @@ package ghidra.app.plugin.core.select; import java.awt.*; -import java.awt.event.ActionEvent; -import java.awt.event.ActionListener; import java.math.BigInteger; import javax.swing.*; import docking.ComponentProvider; -import docking.DialogComponentProvider; +import docking.ReusableDialogComponentProvider; import docking.widgets.button.GRadioButton; import docking.widgets.label.GLabel; import docking.widgets.textfield.IntegerTextField; @@ -39,7 +37,7 @@ import ghidra.util.layout.PairLayout; * Class to set up dialog box that will enable the user * to set the available options for block selection */ -class SelectBlockDialog extends DialogComponentProvider { +class SelectBlockDialog extends ReusableDialogComponentProvider { private static final String OVERFLOW_SELECTION_WARNING = "Selection is larger than available " + "bytes, using the end of the address space"; @@ -53,7 +51,7 @@ class SelectBlockDialog extends DialogComponentProvider { private PluginTool tool; SelectBlockDialog(PluginTool tool, Navigatable navigatable) { - super("Select Bytes", false); + super("Select Bytes", false, true, true, false); this.tool = tool; this.navigatable = navigatable; // navigatable.addNavigatableListener(this); @@ -87,7 +85,7 @@ class SelectBlockDialog extends DialogComponentProvider { private JPanel buildBlockPanel() { JPanel main = new JPanel(); main.setBorder(BorderFactory.createTitledBorder("Byte Selection")); - + main.setLayout(new PairLayout()); main.add(new GLabel("Ending Address:")); @@ -113,46 +111,34 @@ class SelectBlockDialog extends DialogComponentProvider { forwardButton = new GRadioButton("Select Forward", true); forwardButton.setName("forwardButton"); - forwardButton.addActionListener(new ActionListener() { - @Override - public void actionPerformed(ActionEvent ae) { - setStatusText("Enter number of bytes to select"); - setAddressFieldEnabled(false); - setLengthInputEnabled(true); - } + forwardButton.addActionListener(ae -> { + setStatusText("Enter number of bytes to select"); + setAddressFieldEnabled(false); + setLengthInputEnabled(true); }); buttonGroup.add(forwardButton); backwardButton = new GRadioButton("Select Backward"); backwardButton.setName("backwardButton"); - backwardButton.addActionListener(new ActionListener() { - @Override - public void actionPerformed(ActionEvent ae) { - setStatusText("Enter number of bytes to select"); - setAddressFieldEnabled(false); - setLengthInputEnabled(true); - } + backwardButton.addActionListener(ae -> { + setStatusText("Enter number of bytes to select"); + setAddressFieldEnabled(false); + setLengthInputEnabled(true); }); buttonGroup.add(backwardButton); allButton = new GRadioButton("Select All"); allButton.setName("allButton"); - allButton.addActionListener(new ActionListener() { - @Override - public void actionPerformed(ActionEvent ae) { - setItemsEnabled(false); - clearStatusText(); - } + allButton.addActionListener(ae -> { + setItemsEnabled(false); + clearStatusText(); }); buttonGroup.add(allButton); toButton = new GRadioButton("To Address"); toButton.setName("toButton"); - toButton.addActionListener(new ActionListener() { - @Override - public void actionPerformed(ActionEvent ae) { - setStatusText("Enter an Address to go to"); - setAddressFieldEnabled(true); - setLengthInputEnabled(false); - } + toButton.addActionListener(ae -> { + setStatusText("Enter an Address to go to"); + setAddressFieldEnabled(true); + setLengthInputEnabled(false); }); buttonGroup.add(toButton); gbc.gridx = 0; @@ -298,7 +284,6 @@ class SelectBlockDialog extends DialogComponentProvider { Address currentAddress = navigatable.getLocation().getAddress(); length *= currentAddress.getAddressSpace().getAddressableUnitSize(); - AddressFactory addressFactory = navigatable.getProgram().getAddressFactory(); AddressSet addressSet = new AddressSet(navigatable.getSelection()); if (addressSet.isEmpty()) { addressSet.addRange(currentAddress, currentAddress); @@ -361,12 +346,7 @@ class SelectBlockDialog extends DialogComponentProvider { } private void showWarningDialog(final String text) { - SwingUtilities.invokeLater(new Runnable() { - @Override - public void run() { - JOptionPane.showMessageDialog(getComponent(), text); - } - }); + SwingUtilities.invokeLater(() -> JOptionPane.showMessageDialog(getComponent(), text)); } public void setNavigatable(Navigatable navigatable) { diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/select/SelectBlockPlugin.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/select/SelectBlockPlugin.java index d7aa4d2d7b..9680dca01f 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/select/SelectBlockPlugin.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/select/SelectBlockPlugin.java @@ -57,6 +57,15 @@ public class SelectBlockPlugin extends Plugin { createActions(); } + @Override + protected void dispose() { + super.dispose(); + + if (dialog != null) { + dialog.dispose(); + } + } + private void createActions() { toolBarAction = new NavigatableContextAction("SelectBlock", getName()) { diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/string/SearchStringDialog.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/string/SearchStringDialog.java index db9a6daef5..742a22b649 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/string/SearchStringDialog.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/string/SearchStringDialog.java @@ -16,8 +16,6 @@ package ghidra.app.plugin.core.string; import java.awt.*; -import java.awt.event.ActionEvent; -import java.awt.event.ActionListener; import java.io.File; import java.io.IOException; @@ -231,23 +229,21 @@ public class SearchStringDialog extends DialogComponentProvider { // Set up a file chooser that allows the user to select a new *.sng file. JButton browseButton = new BrowseButton(); - browseButton.addActionListener(new ActionListener() { - @Override - public void actionPerformed(ActionEvent e) { - GhidraFileChooser chooser = new GhidraFileChooser(panel); - chooser.setTitle("Select Word Model File"); - chooser.setMultiSelectionEnabled(false); - chooser.setFileFilter(new ExtensionFileFilter("sng", "Word File")); + browseButton.addActionListener(e -> { + GhidraFileChooser chooser = new GhidraFileChooser(panel); + chooser.setTitle("Select Word Model File"); + chooser.setMultiSelectionEnabled(false); + chooser.setFileFilter(new ExtensionFileFilter("sng", "Word File")); - File selectedFile = chooser.getSelectedFile(); - if (selectedFile == null) { - return; - } - - // Important to only save off the name of the file. The NGramUtils call that - // loads the file will search for the file given this name. - wordModelField.setText(selectedFile.getName()); + File selectedFile = chooser.getSelectedFile(); + chooser.dispose(); + if (selectedFile == null) { + return; } + + // Important to only save off the name of the file. The NGramUtils call that + // loads the file will search for the file given this name. + wordModelField.setText(selectedFile.getName()); }); modelFieldPanel.add(browseButton); diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/symtable/FilterDialog.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/symtable/FilterDialog.java index 647576b7e8..71a9f247fc 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/symtable/FilterDialog.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/symtable/FilterDialog.java @@ -25,7 +25,7 @@ import javax.swing.*; import org.jdom.Element; import docking.ComponentProvider; -import docking.DialogComponentProvider; +import docking.ReusableDialogComponentProvider; import docking.widgets.checkbox.GCheckBox; import docking.widgets.label.GHtmlLabel; import docking.widgets.label.GIconLabel; @@ -35,7 +35,7 @@ import ghidra.util.*; import ghidra.util.layout.*; import resources.Icons; -public class FilterDialog extends DialogComponentProvider { +public class FilterDialog extends ReusableDialogComponentProvider { private NewSymbolFilter filter; private JPanel advancedPanel; private JPanel advancedFilterPanel; @@ -48,7 +48,7 @@ public class FilterDialog extends DialogComponentProvider { private PluginTool tool; public FilterDialog(PluginTool tool) { - super("Symbol Table Filter", false); + super("Symbol Table Filter", false, true, true, false); this.tool = tool; filter = new NewSymbolFilter(); addWorkPanel(buildWorkPanel()); diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/symtable/SymbolPanel.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/symtable/SymbolPanel.java index 9dafc87e06..90d4d339a4 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/symtable/SymbolPanel.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/symtable/SymbolPanel.java @@ -133,9 +133,7 @@ class SymbolPanel extends JPanel { symTable.dispose(); threadedTablePanel.dispose(); tableFilterPanel.dispose(); - symProvider = null; - filterDialog.close(); - filterDialog = null; + filterDialog.dispose(); } void setFilter() { diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/table/TableComponentProvider.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/table/TableComponentProvider.java index 8358f573c1..e253b65e13 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/table/TableComponentProvider.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/table/TableComponentProvider.java @@ -287,7 +287,7 @@ public class TableComponentProvider extends ComponentProviderAdapter navigatable.removeNavigatableListener(this); } - tool.removeComponentProvider(this); + super.closeComponent(); tableServicePlugin.remove(this); if (markerSet != null) { diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/totd/TipOfTheDayDialog.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/totd/TipOfTheDayDialog.java index 5fbf6ce20d..b315c9b68a 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/totd/TipOfTheDayDialog.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/totd/TipOfTheDayDialog.java @@ -22,8 +22,8 @@ import java.util.List; import javax.swing.*; import javax.swing.border.Border; -import docking.DialogComponentProvider; import docking.DockingWindowManager; +import docking.ReusableDialogComponentProvider; import docking.widgets.checkbox.GCheckBox; import docking.widgets.label.GLabel; import generic.theme.GIcon; @@ -31,7 +31,7 @@ import generic.theme.GThemeDefaults.Colors; import generic.theme.GThemeDefaults.Colors.Java; import generic.theme.Gui; -class TipOfTheDayDialog extends DialogComponentProvider { +class TipOfTheDayDialog extends ReusableDialogComponentProvider { private static final String FONT_ID = "font.plugin.tips"; private static final String FONT_LABEL_ID = "font.plugin.tips.label"; private static final int _24_HOURS = 86400000; diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/debug/GenerateOldLanguagePlugin.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/debug/GenerateOldLanguagePlugin.java index 9999744a58..55969fdba4 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/debug/GenerateOldLanguagePlugin.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/debug/GenerateOldLanguagePlugin.java @@ -134,7 +134,6 @@ public class GenerateOldLanguagePlugin extends Plugin implements ApplicationLeve private JPanel panel; private SelectLanguagePanel selectLangPanel; - private GhidraFileChooser chooser; GenerateOldLanguageDialog(final boolean skipOldLangGeneration) { super("Select Old Language", true, true, true, false); @@ -169,17 +168,17 @@ public class GenerateOldLanguagePlugin extends Plugin implements ApplicationLeve return; } - if (chooser == null) { - chooser = new GhidraFileChooser(panel); - chooser.setTitle("Specify Old Language Output File"); - chooser.setFileFilter(OLD_LANG_FILTER); - chooser.setApproveButtonText("Create"); - // there's no single directory; you need to pick it yourself now + GhidraFileChooser chooser = new GhidraFileChooser(panel); + chooser.setTitle("Specify Old Language Output File"); + chooser.setFileFilter(OLD_LANG_FILTER); + chooser.setApproveButtonText("Create"); + // there's no single directory; you need to pick it yourself now // chooser.setCurrentDirectory(LANGUAGE_DIR); - chooser.setCurrentDirectory( - Application.getApplicationRootDirectory().getFile(false)); - } + chooser.setCurrentDirectory( + Application.getApplicationRootDirectory().getFile(false)); + File file = chooser.getSelectedFile(true); + chooser.dispose(); if (file == null) { return; } @@ -234,7 +233,6 @@ public class GenerateOldLanguagePlugin extends Plugin implements ApplicationLeve private JPanel panel; private SelectLanguagePanel selectLangPanel; - private GhidraFileChooser chooser; private Language oldLang; private File oldLangFile; @@ -269,17 +267,18 @@ public class GenerateOldLanguagePlugin extends Plugin implements ApplicationLeve File transFile; if (GenerateTranslatorDialog.this.oldLangFile == null) { - if (chooser == null) { - chooser = new GhidraFileChooser(panel); - chooser.setTitle("Specify Old Language Output File"); - chooser.setFileFilter(TRANSLATOR_FILTER); - chooser.setApproveButtonText("Create"); - // there's no single directory; you need to pick it yourself now + + GhidraFileChooser chooser = new GhidraFileChooser(panel); + chooser.setTitle("Specify Old Language Output File"); + chooser.setFileFilter(TRANSLATOR_FILTER); + chooser.setApproveButtonText("Create"); + // there's no single directory; you need to pick it yourself now // chooser.setCurrentDirectory(LANGUAGE_DIR); - chooser.setCurrentDirectory( - Application.getApplicationRootDirectory().getFile(false)); - } + chooser.setCurrentDirectory( + Application.getApplicationRootDirectory().getFile(false)); + transFile = chooser.getSelectedFile(true); + chooser.dispose(); if (transFile == null) { return; } @@ -533,7 +532,7 @@ public class GenerateOldLanguagePlugin extends Plugin implements ApplicationLeve public List getLanguageDescriptions( boolean includeDeprecatedLanguages) { // Include deprecated languages - List list = new ArrayList(); + List list = new ArrayList<>(); list.addAll(langService.getLanguageDescriptions(true)); if (includeOldLanguages) { list.addAll(Arrays.asList(oldLangFactory.getLatestOldLanaguageDescriptions())); diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/script/GhidraScript.java b/Ghidra/Features/Base/src/main/java/ghidra/app/script/GhidraScript.java index 0f458bc7af..4ac81d9bd5 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/script/GhidraScript.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/script/GhidraScript.java @@ -2044,7 +2044,7 @@ public abstract class GhidraScript extends FlatProgramAPI { chooser.setApproveButtonText(approveButtonText); chooser.setFileSelectionMode(GhidraFileChooserMode.FILES_ONLY); File file = chooser.getSelectedFile(); - + chooser.dispose(); if (chooser.wasCancelled()) { throw new CancelledException(); } @@ -2121,7 +2121,7 @@ public abstract class GhidraScript extends FlatProgramAPI { chooser.setApproveButtonText(approveButtonText); chooser.setFileSelectionMode(GhidraFileChooserMode.DIRECTORIES_ONLY); File file = chooser.getSelectedFile(); - + chooser.dispose(); if (chooser.wasCancelled()) { throw new CancelledException(); } diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/EditFieldNameDialog.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/EditFieldNameDialog.java index 5bf661eb28..b261b49086 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/EditFieldNameDialog.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/EditFieldNameDialog.java @@ -15,13 +15,6 @@ */ package ghidra.app.util; -import ghidra.framework.plugintool.PluginTool; -import ghidra.program.model.data.DataType; -import ghidra.program.model.data.DataTypeComponent; -import ghidra.program.model.listing.Program; -import ghidra.util.HelpLocation; -import ghidra.util.exception.DuplicateNameException; - import java.awt.*; import javax.swing.*; @@ -30,24 +23,30 @@ import javax.swing.border.TitledBorder; import docking.ComponentProvider; import docking.DialogComponentProvider; +import ghidra.framework.plugintool.PluginTool; +import ghidra.program.model.data.DataType; +import ghidra.program.model.data.DataTypeComponent; +import ghidra.program.model.listing.Program; +import ghidra.util.HelpLocation; +import ghidra.util.exception.DuplicateNameException; public class EditFieldNameDialog extends DialogComponentProvider { private PluginTool tool; private TitledBorder nameBorder; private JTextField fieldName; - + private Program program; private DataTypeComponent dtComp; - - /** + + /** * Construct a new dialog. * * @param title title for the dialog, null value is acceptable if no title * @param tool the plugin tool */ public EditFieldNameDialog(String title, PluginTool tool) { - super(title, true, true, true, false); + super(title, true, true, true, false); this.tool = tool; setHelpLocation(new HelpLocation(HelpTopics.LABEL, "EditFieldNameDialog")); @@ -59,12 +58,10 @@ public class EditFieldNameDialog extends DialogComponentProvider { addCancelButton(); setDefaultButton(okButton); - + setMinimumSize(new Dimension(300, 50)); } - - - + private String getCurrentFieldName() { String name = dtComp.getFieldName(); if (name == null) { @@ -77,69 +74,73 @@ public class EditFieldNameDialog extends DialogComponentProvider { * This method gets called when the user clicks on the OK Button. The base * class calls this method. */ - @Override - protected void okCallback() { - - String newName = fieldName.getText().trim(); - - if (newName.equals(getCurrentFieldName())) { - close(); - return; - } - - boolean success = false; - int txId = program.startTransaction("Edit Field Name"); - try { + @Override + protected void okCallback() { + + String newName = fieldName.getText().trim(); + + if (newName.equals(getCurrentFieldName())) { + close(); + return; + } + + boolean success = false; + int txId = program.startTransaction("Edit Field Name"); + try { dtComp.setFieldName(newName); DataType parent = dtComp.getParent(); if (parent != null) { long timeNow = System.currentTimeMillis(); - parent.setLastChangeTime(timeNow); + parent.setLastChangeTime(timeNow); } success = true; - } catch (DuplicateNameException e) { + } + catch (DuplicateNameException e) { setStatusText(e.getMessage()); - } finally { + } + finally { program.endTransaction(txId, true); } - + if (success) { dtComp = null; program = null; close(); } - } - - public void editField(DataTypeComponent dataTypeComponent, Program p) { - ComponentProvider componentProvider = tool.getComponentProvider(PluginConstants.CODE_BROWSER); - JComponent component = componentProvider.getComponent(); - editField( dataTypeComponent, p, component ); - } - - public void editField(DataTypeComponent dataTypeComponent, Program p, Component centeredOverComponent ) { - this.dtComp = dataTypeComponent; - this.program = p; - String name = getCurrentFieldName(); - setTitle("Edit Field Name: "+ dataTypeComponent.getParent().getName() + "." + name); - fieldName.setText(name); - clearStatusText(); - tool.showDialog(this, centeredOverComponent); } - + + public void editField(DataTypeComponent dataTypeComponent, Program p) { + ComponentProvider componentProvider = + tool.getComponentProvider(PluginConstants.CODE_BROWSER); + JComponent component = componentProvider.getComponent(); + editField(dataTypeComponent, p, component); + } + + public void editField(DataTypeComponent dataTypeComponent, Program p, + Component centeredOverComponent) { + this.dtComp = dataTypeComponent; + this.program = p; + String name = getCurrentFieldName(); + setTitle("Edit Field Name: " + dataTypeComponent.getParent().getName() + "." + name); + fieldName.setText(name); + clearStatusText(); + tool.showDialog(this, centeredOverComponent); + } + /** * Define the Main panel for the dialog here. */ private JPanel create() { fieldName = new JTextField(); - + JPanel mainPanel = new JPanel(new BorderLayout()); nameBorder = BorderFactory.createTitledBorder("Enter Field Name"); mainPanel.setBorder(nameBorder); - + mainPanel.add(fieldName, BorderLayout.CENTER); - - mainPanel.setBorder(new EmptyBorder(5,5,5,5)); + + mainPanel.setBorder(new EmptyBorder(5, 5, 5, 5)); return mainPanel; } diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/OptionsDialog.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/OptionsDialog.java index e24798c0e3..5685e67725 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/OptionsDialog.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/OptionsDialog.java @@ -31,7 +31,7 @@ public class OptionsDialog extends DialogComponentProvider implements OptionList private OptionValidator validator; /** - * Contructs a new OptionsDialog for editing the options associated with a specific import format + * Constructs a new OptionsDialog for editing the options associated with a specific import format * such as PE, ELF, XML, etc. * * @param originalOptions the list of options generated from the specific import format selected. diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf4/external/DWARFExternalDebugFilesPlugin.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf4/external/DWARFExternalDebugFilesPlugin.java index 613b19ccf1..f5e4e86620 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf4/external/DWARFExternalDebugFilesPlugin.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf4/external/DWARFExternalDebugFilesPlugin.java @@ -15,12 +15,11 @@ */ package ghidra.app.util.bin.format.dwarf4.external; +import java.io.File; import java.util.ArrayList; import java.util.List; import java.util.stream.Collectors; -import java.io.File; - import docking.action.builder.ActionBuilder; import docking.tool.ToolConstants; import docking.widgets.filechooser.GhidraFileChooser; @@ -70,6 +69,7 @@ public class DWARFExternalDebugFilesPlugin extends Plugin { chooser.setFileSelectionMode(GhidraFileChooserMode.DIRECTORIES_ONLY); chooser.setTitle("Select External Debug Files Directory"); File selectedDir = chooser.getSelectedFile(); + chooser.dispose(); if (selectedDir == null) { return; } diff --git a/Ghidra/Features/Base/src/main/java/ghidra/plugin/importer/ImporterDialog.java b/Ghidra/Features/Base/src/main/java/ghidra/plugin/importer/ImporterDialog.java index 7d667bffcd..dc15e02371 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/plugin/importer/ImporterDialog.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/plugin/importer/ImporterDialog.java @@ -62,8 +62,6 @@ import ghidra.util.task.TaskBuilder; */ public class ImporterDialog extends DialogComponentProvider { - public static final String LAST_IMPORTFILE_PREFERENCE_KEY = "Importer.LastFile"; - protected PluginTool tool; private ProgramManager programManager; protected FSRL fsrl; @@ -118,7 +116,7 @@ public class ImporterDialog extends DialogComponentProvider { // only save the imported file's path if its a local filesystem path that // will be valid when used later. FSRL paths that drill into container files // aren't widely supported yet. - Preferences.setProperty(LAST_IMPORTFILE_PREFERENCE_KEY, fsrl.getPath()); + Preferences.setProperty(Preferences.LAST_IMPORT_FILE, fsrl.getPath()); } addWorkPanel(buildWorkPanel()); diff --git a/Ghidra/Features/Base/src/main/java/ghidra/plugin/importer/ImporterPlugin.java b/Ghidra/Features/Base/src/main/java/ghidra/plugin/importer/ImporterPlugin.java index c986188f9f..a8c20375fc 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/plugin/importer/ImporterPlugin.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/plugin/importer/ImporterPlugin.java @@ -15,12 +15,11 @@ */ package ghidra.plugin.importer; -import java.util.*; - import java.awt.event.InputEvent; import java.awt.event.KeyEvent; import java.io.File; import java.io.IOException; +import java.util.*; import docking.ActionContext; import docking.action.*; @@ -139,7 +138,10 @@ public class ImporterPlugin extends Plugin frontEndService.removeProjectListener(this); frontEndService = null; } - chooser = null; + + if (chooser != null) { + chooser.dispose(); + } } @Override @@ -327,7 +329,7 @@ public class ImporterPlugin extends Plugin chooser.setTitle(title); chooser.setApproveButtonText(buttonText); - String lastFile = Preferences.getProperty(ImporterDialog.LAST_IMPORTFILE_PREFERENCE_KEY); + String lastFile = Preferences.getProperty(Preferences.LAST_IMPORT_FILE); if (lastFile != null) { chooser.setSelectedFile(new File(lastFile)); } diff --git a/Ghidra/Features/Base/src/main/java/ghidra/plugins/fsbrowser/FSBActionManager.java b/Ghidra/Features/Base/src/main/java/ghidra/plugins/fsbrowser/FSBActionManager.java index eec3c39acf..722c160ed0 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/plugins/fsbrowser/FSBActionManager.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/plugins/fsbrowser/FSBActionManager.java @@ -144,6 +144,15 @@ class FSBActionManager { } public void dispose() { + + if (chooserExport != null) { + chooserExport.dispose(); + } + + if (chooserExportAll != null) { + chooserExportAll.dispose(); + } + removeActions(); } diff --git a/Ghidra/Features/Base/src/main/java/ghidra/plugins/fsbrowser/FileSystemBrowserPlugin.java b/Ghidra/Features/Base/src/main/java/ghidra/plugins/fsbrowser/FileSystemBrowserPlugin.java index feb8a01738..777ace29cd 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/plugins/fsbrowser/FileSystemBrowserPlugin.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/plugins/fsbrowser/FileSystemBrowserPlugin.java @@ -15,13 +15,12 @@ */ package ghidra.plugins.fsbrowser; -import java.util.*; - import java.awt.Component; import java.awt.event.InputEvent; import java.awt.event.KeyEvent; import java.io.File; import java.io.IOException; +import java.util.*; import javax.swing.KeyStroke; @@ -37,8 +36,8 @@ import ghidra.app.plugin.PluginCategoryNames; import ghidra.app.services.*; import ghidra.app.util.opinion.LoaderService; import ghidra.formats.gfilesystem.*; -import ghidra.framework.main.FrontEndService; import ghidra.framework.main.ApplicationLevelPlugin; +import ghidra.framework.main.FrontEndService; import ghidra.framework.model.Project; import ghidra.framework.model.ProjectListener; import ghidra.framework.plugintool.*; @@ -70,7 +69,8 @@ import utilities.util.FileUtilities; eventsConsumed = { ProgramActivatedPluginEvent.class } ) //@formatter:on -public class FileSystemBrowserPlugin extends Plugin implements ApplicationLevelPlugin, ProjectListener, +public class FileSystemBrowserPlugin extends Plugin + implements ApplicationLevelPlugin, ProjectListener, FileSystemBrowserService { /* package */ DockingAction openFilesystemAction; @@ -128,7 +128,10 @@ public class FileSystemBrowserPlugin extends Plugin implements ApplicationLevelP frontEndService.removeProjectListener(this); frontEndService = null; } - chooserOpen = null; + + if (chooserOpen != null) { + chooserOpen.dispose(); + } for (FileSystemBrowserComponentProvider provider : currentBrowsers.values()) { provider.dispose(); diff --git a/Ghidra/Features/Base/src/main/java/ghidra/plugins/importer/batch/BatchImportDialog.java b/Ghidra/Features/Base/src/main/java/ghidra/plugins/importer/batch/BatchImportDialog.java index e738586a6f..658720af75 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/plugins/importer/batch/BatchImportDialog.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/plugins/importer/batch/BatchImportDialog.java @@ -53,6 +53,8 @@ import ghidra.util.task.TaskLauncher; public class BatchImportDialog extends DialogComponentProvider { + private static final String LAST_IMPORT_DIR = "LastBatchImportDir"; + /** * Shows the batch import dialog (via runSwingLater) and prompts the user to select * a file if the supplied {@code batchInfo} is empty. @@ -96,7 +98,6 @@ public class BatchImportDialog extends DialogComponentProvider { private JButton rescanButton; private JSpinner maxDepthSpinner; - private GhidraFileChooser fileChooser; private SourcesListModel sourceListModel; private BatchImportDialog(BatchInfo batchInfo, DomainFolder defaultFolder) { @@ -387,20 +388,21 @@ public class BatchImportDialog extends DialogComponentProvider { } private boolean addSources() { - if (fileChooser == null) { - fileChooser = new GhidraFileChooser(getComponent()); - fileChooser.setMultiSelectionEnabled(true); - fileChooser.setTitle("Choose File to Batch Import"); - fileChooser.setApproveButtonText("Select files"); - fileChooser.setFileSelectionMode(GhidraFileChooserMode.FILES_AND_DIRECTORIES); - fileChooser.addFileFilter(ImporterUtilities.LOADABLE_FILES_FILTER); - fileChooser.addFileFilter(ImporterUtilities.CONTAINER_FILES_FILTER); - fileChooser.setSelectedFileFilter(GhidraFileFilter.ALL); - } - List selectedFiles = fileChooser.getSelectedFiles(); + GhidraFileChooser chooser = new GhidraFileChooser(getComponent()); + chooser.setMultiSelectionEnabled(true); + chooser.setTitle("Choose File to Batch Import"); + chooser.setApproveButtonText("Select files"); + chooser.setFileSelectionMode(GhidraFileChooserMode.FILES_AND_DIRECTORIES); + chooser.addFileFilter(ImporterUtilities.LOADABLE_FILES_FILTER); + chooser.addFileFilter(ImporterUtilities.CONTAINER_FILES_FILTER); + chooser.setSelectedFileFilter(GhidraFileFilter.ALL); + + chooser.setLastDirectoryPreference(LAST_IMPORT_DIR); + + List selectedFiles = chooser.getSelectedFiles(); if (selectedFiles.isEmpty()) { - return !fileChooser.wasCancelled(); + return !chooser.wasCancelled(); } List filesToAdd = new ArrayList<>(); @@ -408,6 +410,8 @@ public class BatchImportDialog extends DialogComponentProvider { filesToAdd.add(FileSystemService.getInstance().getLocalFSRL(selectedFile)); } + chooser.dispose(); + return addSources(filesToAdd); } diff --git a/Ghidra/Features/Base/src/main/java/ghidra/plugins/importer/batch/BatchProjectDestinationPanel.java b/Ghidra/Features/Base/src/main/java/ghidra/plugins/importer/batch/BatchProjectDestinationPanel.java index 4d4a4de1f6..116a831788 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/plugins/importer/batch/BatchProjectDestinationPanel.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/plugins/importer/batch/BatchProjectDestinationPanel.java @@ -29,7 +29,6 @@ class BatchProjectDestinationPanel extends JPanel { private JComponent parent; private JTextField folderNameTextField; - private DataTreeDialog dataTreeDialog; private DomainFolder selectedDomainFolder; public BatchProjectDestinationPanel(JComponent parent, DomainFolder defaultFolder) { @@ -96,7 +95,7 @@ class BatchProjectDestinationPanel extends JPanel { } private void browseFolders() { - dataTreeDialog = + DataTreeDialog dataTreeDialog = new DataTreeDialog(parent, "Choose a project folder", DataTreeDialog.CHOOSE_FOLDER); dataTreeDialog.addOkActionListener(e -> { dataTreeDialog.close(); @@ -107,9 +106,6 @@ class BatchProjectDestinationPanel extends JPanel { } public void setFolder(DomainFolder folder) { - if (dataTreeDialog != null) { - dataTreeDialog.setSelectedFolder(folder); - } folderNameTextField.setText(folder != null ? folder.toString() : "< Choose a folder >"); this.selectedDomainFolder = folder; onProjectDestinationChange(selectedDomainFolder); diff --git a/Ghidra/Features/Base/src/test.slow/java/ghidra/app/plugin/core/label/OperandLabelDialogTest.java b/Ghidra/Features/Base/src/test.slow/java/ghidra/app/plugin/core/label/OperandLabelDialogTest.java index 2752e663fc..9eb78113b8 100644 --- a/Ghidra/Features/Base/src/test.slow/java/ghidra/app/plugin/core/label/OperandLabelDialogTest.java +++ b/Ghidra/Features/Base/src/test.slow/java/ghidra/app/plugin/core/label/OperandLabelDialogTest.java @@ -15,7 +15,7 @@ */ package ghidra.app.plugin.core.label; -import static org.junit.Assert.assertEquals; +import static org.junit.Assert.*; import org.junit.*; @@ -37,8 +37,6 @@ public class OperandLabelDialogTest extends AbstractGhidraHeadedIntegrationTest private LabelMgrPlugin plugin; private CodeBrowserPlugin cb; private Program program; - private OperandLabelDialog dialog; - private GhidraComboBox combo; private SetOperandLabelAction setLabelAction; @Before @@ -51,10 +49,6 @@ public class OperandLabelDialogTest extends AbstractGhidraHeadedIntegrationTest plugin = getPlugin(tool, LabelMgrPlugin.class); cb = getPlugin(tool, CodeBrowserPlugin.class); - dialog = runSwing(() -> plugin.getOperandLabelDialog()); - - combo = (GhidraComboBox) findComponentByName(dialog, "MYCHOICE"); - setLabelAction = (SetOperandLabelAction) getAction(plugin, "Set Operand Label"); } @@ -80,7 +74,10 @@ public class OperandLabelDialogTest extends AbstractGhidraHeadedIntegrationTest performAction(setLabelAction, context, false); waitForSwing(); - runSwing(() -> combo.setSelectedItem("bob")); + OperandLabelDialog dialog = waitForDialogComponent(OperandLabelDialog.class); + GhidraComboBox combo = (GhidraComboBox) findComponentByName(dialog, "MYCHOICE"); + + setSelectedItem(combo, "bob"); pressButtonByText(dialog, "OK"); waitForSwing(); @@ -94,7 +91,10 @@ public class OperandLabelDialogTest extends AbstractGhidraHeadedIntegrationTest performAction(setLabelAction, context, false); waitForSwing(); - runSwing(() -> combo.setSelectedItem("b")); + dialog = waitForDialogComponent(OperandLabelDialog.class); + combo = (GhidraComboBox) findComponentByName(dialog, "MYCHOICE"); + + setSelectedItem(combo, "b"); pressButtonByText(dialog, "OK"); program.flushEvents(); @@ -108,4 +108,7 @@ public class OperandLabelDialogTest extends AbstractGhidraHeadedIntegrationTest assertEquals("dword ptr [b]", cb.getCurrentFieldText()); } + private void setSelectedItem(GhidraComboBox combo, String s) { + runSwing(() -> combo.setSelectedItem(s)); + } } diff --git a/Ghidra/Features/BytePatterns/src/main/java/ghidra/bitpatterns/gui/ExportPatternFileActionListener.java b/Ghidra/Features/BytePatterns/src/main/java/ghidra/bitpatterns/gui/ExportPatternFileActionListener.java index 01fde7af6d..a1b6456f8a 100644 --- a/Ghidra/Features/BytePatterns/src/main/java/ghidra/bitpatterns/gui/ExportPatternFileActionListener.java +++ b/Ghidra/Features/BytePatterns/src/main/java/ghidra/bitpatterns/gui/ExportPatternFileActionListener.java @@ -24,6 +24,7 @@ import java.util.List; import java.util.Objects; import docking.widgets.filechooser.GhidraFileChooser; +import docking.widgets.filechooser.GhidraFileChooserMode; import ghidra.bitpatterns.info.ContextRegisterFilter; import ghidra.bitpatterns.info.PatternType; import ghidra.framework.preferences.Preferences; @@ -88,7 +89,7 @@ public class ExportPatternFileActionListener implements ActionListener { return; } GhidraFileChooser gFileChooser = new GhidraFileChooser(component); - gFileChooser.setFileSelectionMode(GhidraFileChooser.FILES_ONLY); + gFileChooser.setFileSelectionMode(GhidraFileChooserMode.FILES_ONLY); ExtensionFileFilter xmlFilter = new ExtensionFileFilter("xml", "XML Files"); gFileChooser.setFileFilter(xmlFilter); String baseDir = Preferences.getProperty(XML_EXPORT_DIR_PROPERTY); @@ -97,11 +98,13 @@ public class ExportPatternFileActionListener implements ActionListener { } gFileChooser.setTitle("Select Export File"); File outFile = gFileChooser.getSelectedFile(); + String lastDirPath = gFileChooser.getCurrentDirectory().getAbsolutePath(); + gFileChooser.dispose(); if (gFileChooser.wasCancelled() || outFile == null) { return; } - Preferences.setProperty(XML_EXPORT_DIR_PROPERTY, - gFileChooser.getCurrentDirectory().getAbsolutePath()); + + Preferences.setProperty(XML_EXPORT_DIR_PROPERTY, lastDirPath); Preferences.store(); BitsInputDialogComponentProvider bitsProvider = new BitsInputDialogComponentProvider(BITS_PROVIDER_MESSAGE); @@ -115,7 +118,6 @@ public class ExportPatternFileActionListener implements ActionListener { } catch (IOException e1) { Msg.showError(this, component, "IO Error", "IO error exporting pattern xml file", e1); - e1.printStackTrace(); } } diff --git a/Ghidra/Features/BytePatterns/src/main/java/ghidra/bitpatterns/gui/FunctionBitPatternsMainProvider.java b/Ghidra/Features/BytePatterns/src/main/java/ghidra/bitpatterns/gui/FunctionBitPatternsMainProvider.java index 1391731958..0d5c13fc48 100644 --- a/Ghidra/Features/BytePatterns/src/main/java/ghidra/bitpatterns/gui/FunctionBitPatternsMainProvider.java +++ b/Ghidra/Features/BytePatterns/src/main/java/ghidra/bitpatterns/gui/FunctionBitPatternsMainProvider.java @@ -28,6 +28,7 @@ import docking.action.DockingAction; import docking.action.MenuData; import docking.tool.ToolConstants; import docking.widgets.filechooser.GhidraFileChooser; +import docking.widgets.filechooser.GhidraFileChooserMode; import docking.widgets.label.GLabel; import ghidra.bitpatterns.info.*; import ghidra.framework.options.OptionsChangeListener; @@ -227,13 +228,14 @@ public class FunctionBitPatternsMainProvider extends ComponentProviderAdapter @Override public void actionPerformed(ActionEvent e) { GhidraFileChooser fileChooser = new GhidraFileChooser(component); - fileChooser.setFileSelectionMode(GhidraFileChooser.DIRECTORIES_ONLY); + fileChooser.setFileSelectionMode(GhidraFileChooserMode.DIRECTORIES_ONLY); fileChooser.setTitle("Select Directory Containing XML Files"); String baseDir = Preferences.getProperty(PATTERN_INFO_DIR); if (baseDir != null) { fileChooser.setCurrentDirectory(new File(baseDir)); } File xmlDir = fileChooser.getSelectedFile(); + fileChooser.dispose(); if (xmlDir == null) { return; } diff --git a/Ghidra/Features/BytePatterns/src/main/java/ghidra/bitpatterns/gui/ImportPatternFileActionListener.java b/Ghidra/Features/BytePatterns/src/main/java/ghidra/bitpatterns/gui/ImportPatternFileActionListener.java index bb8a9d6260..7de9629e5d 100644 --- a/Ghidra/Features/BytePatterns/src/main/java/ghidra/bitpatterns/gui/ImportPatternFileActionListener.java +++ b/Ghidra/Features/BytePatterns/src/main/java/ghidra/bitpatterns/gui/ImportPatternFileActionListener.java @@ -25,6 +25,7 @@ import java.math.BigInteger; import org.xml.sax.SAXException; import docking.widgets.filechooser.GhidraFileChooser; +import docking.widgets.filechooser.GhidraFileChooserMode; import generic.jar.ResourceFile; import ghidra.app.analyzers.FunctionStartAnalyzer.ContextAction; import ghidra.bitpatterns.info.ContextRegisterFilter; @@ -59,7 +60,7 @@ public class ImportPatternFileActionListener implements ActionListener { public void actionPerformed(ActionEvent e) { GhidraFileChooser fileChooser = new GhidraFileChooser(component); - fileChooser.setFileSelectionMode(GhidraFileChooser.FILES_ONLY); + fileChooser.setFileSelectionMode(GhidraFileChooserMode.FILES_ONLY); fileChooser.setTitle("Select Pattern File"); String baseDir = Preferences.getProperty(XML_IMPORT_DIR_PROPERTY); if (baseDir != null) { @@ -68,11 +69,13 @@ public class ImportPatternFileActionListener implements ActionListener { ExtensionFileFilter xmlFilter = new ExtensionFileFilter("xml", "XML Files"); fileChooser.setFileFilter(xmlFilter); File patternFile = fileChooser.getSelectedFile(); + String lastDirPath = fileChooser.getCurrentDirectory().getAbsolutePath(); + fileChooser.dispose(); if (fileChooser.wasCancelled() || patternFile == null) { return; } - Preferences.setProperty(XML_IMPORT_DIR_PROPERTY, - fileChooser.getCurrentDirectory().getAbsolutePath()); + + Preferences.setProperty(XML_IMPORT_DIR_PROPERTY, lastDirPath); Preferences.store(); //only clear the patterns if new patterns are loaded from a file ResourceFile resource = new ResourceFile(patternFile); diff --git a/Ghidra/Features/ByteViewer/src/main/java/ghidra/app/plugin/core/byteviewer/ProgramByteViewerComponentProvider.java b/Ghidra/Features/ByteViewer/src/main/java/ghidra/app/plugin/core/byteviewer/ProgramByteViewerComponentProvider.java index bd6c07bb0d..e46389e2a3 100644 --- a/Ghidra/Features/ByteViewer/src/main/java/ghidra/app/plugin/core/byteviewer/ProgramByteViewerComponentProvider.java +++ b/Ghidra/Features/ByteViewer/src/main/java/ghidra/app/plugin/core/byteviewer/ProgramByteViewerComponentProvider.java @@ -146,6 +146,7 @@ public class ProgramByteViewerComponentProvider extends ByteViewerComponentProvi @Override public void closeComponent() { // overridden to handle snapshots + super.closeComponent(); plugin.closeProvider(this); } diff --git a/Ghidra/Features/DebugUtils/src/main/java/db/DbViewer.java b/Ghidra/Features/DebugUtils/src/main/java/db/DbViewer.java index 8f69f80b83..6537a8c4d1 100644 --- a/Ghidra/Features/DebugUtils/src/main/java/db/DbViewer.java +++ b/Ghidra/Features/DebugUtils/src/main/java/db/DbViewer.java @@ -16,8 +16,6 @@ package db; import java.awt.*; -import java.awt.event.ActionEvent; -import java.awt.event.ActionListener; import java.io.File; import java.io.IOException; import java.util.*; @@ -29,6 +27,7 @@ import db.buffers.LocalBufferFile; import docking.framework.DockingApplicationConfiguration; import docking.widgets.combobox.GComboBox; import docking.widgets.filechooser.GhidraFileChooser; +import docking.widgets.filechooser.GhidraFileChooserMode; import docking.widgets.label.GDLabel; import docking.widgets.label.GLabel; import generic.application.GenericApplicationLayout; @@ -47,7 +46,7 @@ import utility.application.ApplicationLayout; * Ghidra database. */ public class DbViewer extends JFrame { - private GhidraFileChooser fileChooser; + private static final String LAST_BUFFER_FILE_DIRECTORY = "LastBufferFileDirectory"; private File dbFile; private DBHandle dbh; private JMenuItem openItem; @@ -60,7 +59,7 @@ public class DbViewer extends JFrame { DbViewer() { super("Database Viewer"); - setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); + setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE); buildGui(); } @@ -70,29 +69,14 @@ public class DbViewer extends JFrame { menuBar.add(menu); openItem = new JMenuItem("Open Database..."); menu.add(openItem); - openItem.addActionListener(new ActionListener() { - @Override - public void actionPerformed(ActionEvent e) { - openDb(); - } - }); + openItem.addActionListener(e -> openDb()); closeItem = new JMenuItem("Close Database"); menu.add(closeItem); closeItem.setEnabled(false); - closeItem.addActionListener(new ActionListener() { - @Override - public void actionPerformed(ActionEvent e) { - closeDb(); - } - }); + closeItem.addActionListener(e -> closeDb()); JMenuItem exitItem = new JMenuItem("Exit"); menu.add(exitItem); - exitItem.addActionListener(new ActionListener() { - @Override - public void actionPerformed(ActionEvent e) { - System.exit(0); - } - }); + exitItem.addActionListener(e -> System.exit(0)); setJMenuBar(menuBar); } @@ -106,14 +90,16 @@ public class DbViewer extends JFrame { } private void openDb() { - if (fileChooser == null) { - fileChooser = new GhidraFileChooser(this); - fileChooser.setFileSelectionMode(GhidraFileChooser.FILES_ONLY); - fileChooser.setFileFilter(new ExtensionFileFilter("gbf", "Ghidra Buffer File")); - fileChooser.setCurrentDirectory(new File("C:\\")); - } + + GhidraFileChooser fileChooser = new GhidraFileChooser(this); + fileChooser.setFileSelectionMode(GhidraFileChooserMode.FILES_ONLY); + fileChooser.setFileFilter(new ExtensionFileFilter("gbf", "Ghidra Buffer File")); + fileChooser.setCurrentDirectory(new File("C:\\")); + + fileChooser.setLastDirectoryPreference(LAST_BUFFER_FILE_DIRECTORY); File selectedFile = fileChooser.getSelectedFile(true); + fileChooser.dispose(); if (selectedFile == null) { return; } @@ -169,12 +155,7 @@ public class DbViewer extends JFrame { tables[i].getName() + " (" + Integer.toString(tables[i].getRecordCount()) + ")"; } combo = new GComboBox<>(names); - combo.addActionListener(new ActionListener() { - @Override - public void actionPerformed(ActionEvent e) { - updateTable(); - } - }); + combo.addActionListener(e -> updateTable()); subNorthPanel.add(combo); northPanel.add(subNorthPanel); mainPanel.add(northPanel, BorderLayout.NORTH); diff --git a/Ghidra/Features/Decompiler/src/main/java/ghidra/app/plugin/core/decompile/DecompilerProvider.java b/Ghidra/Features/Decompiler/src/main/java/ghidra/app/plugin/core/decompile/DecompilerProvider.java index 16afa2cb92..6a0b8accc3 100644 --- a/Ghidra/Features/Decompiler/src/main/java/ghidra/app/plugin/core/decompile/DecompilerProvider.java +++ b/Ghidra/Features/Decompiler/src/main/java/ghidra/app/plugin/core/decompile/DecompilerProvider.java @@ -160,6 +160,7 @@ public class DecompilerProvider extends NavigatableComponentProviderAdapter @Override public void closeComponent() { + super.closeComponent(); controller.clear(); plugin.closeProvider(this); } diff --git a/Ghidra/Features/Decompiler/src/main/java/ghidra/app/plugin/core/decompile/actions/DebugDecompilerAction.java b/Ghidra/Features/Decompiler/src/main/java/ghidra/app/plugin/core/decompile/actions/DebugDecompilerAction.java index fd9ab3c093..70c1aaeb8e 100644 --- a/Ghidra/Features/Decompiler/src/main/java/ghidra/app/plugin/core/decompile/actions/DebugDecompilerAction.java +++ b/Ghidra/Features/Decompiler/src/main/java/ghidra/app/plugin/core/decompile/actions/DebugDecompilerAction.java @@ -53,6 +53,7 @@ public class DebugDecompilerAction extends DockingAction { fileChooser.setTitle("Please Choose Output File"); fileChooser.setFileFilter(new ExtensionFileFilter(new String[] { "xml" }, "XML Files")); File file = fileChooser.getSelectedFile(); + fileChooser.dispose(); if (file == null) { return; } diff --git a/Ghidra/Features/Decompiler/src/main/java/ghidra/app/plugin/core/decompile/actions/ExportToCAction.java b/Ghidra/Features/Decompiler/src/main/java/ghidra/app/plugin/core/decompile/actions/ExportToCAction.java index 94aeca06f1..b85ecadd8a 100644 --- a/Ghidra/Features/Decompiler/src/main/java/ghidra/app/plugin/core/decompile/actions/ExportToCAction.java +++ b/Ghidra/Features/Decompiler/src/main/java/ghidra/app/plugin/core/decompile/actions/ExportToCAction.java @@ -66,6 +66,7 @@ public class ExportToCAction extends AbstractDecompilerAction { fileChooser.setSelectedFile(lastUsedFile); } File file = fileChooser.getSelectedFile(); + fileChooser.dispose(); if (file == null) { return null; } diff --git a/Ghidra/Features/Decompiler/src/main/java/ghidra/app/plugin/core/decompile/actions/FindAction.java b/Ghidra/Features/Decompiler/src/main/java/ghidra/app/plugin/core/decompile/actions/FindAction.java index 30cbf70471..0860b4bf0c 100644 --- a/Ghidra/Features/Decompiler/src/main/java/ghidra/app/plugin/core/decompile/actions/FindAction.java +++ b/Ghidra/Features/Decompiler/src/main/java/ghidra/app/plugin/core/decompile/actions/FindAction.java @@ -44,6 +44,14 @@ public class FindAction extends AbstractDecompilerAction { setEnabled(true); } + @Override + public void dispose() { + if (findDialog != null) { + findDialog.dispose(); + } + super.dispose(); + } + protected FindDialog getFindDialog(DecompilerPanel decompilerPanel) { if (findDialog == null) { findDialog = diff --git a/Ghidra/Features/FileFormats/src/main/java/ghidra/plugins/fileformats/FileFormatsPlugin.java b/Ghidra/Features/FileFormats/src/main/java/ghidra/plugins/fileformats/FileFormatsPlugin.java index 4766899230..81b9e0f33f 100644 --- a/Ghidra/Features/FileFormats/src/main/java/ghidra/plugins/fileformats/FileFormatsPlugin.java +++ b/Ghidra/Features/FileFormats/src/main/java/ghidra/plugins/fileformats/FileFormatsPlugin.java @@ -87,6 +87,14 @@ public class FileFormatsPlugin extends Plugin implements ApplicationLevelPlugin protected void dispose() { super.dispose(); + if (chooserJarFolder != null) { + chooserJarFolder.dispose(); + } + + if (chooserEclipse != null) { + chooserEclipse.dispose(); + } + actions.forEach(action -> getTool().removeAction(action)); } diff --git a/Ghidra/Features/FunctionGraph/src/main/java/ghidra/app/plugin/core/functiongraph/FGProvider.java b/Ghidra/Features/FunctionGraph/src/main/java/ghidra/app/plugin/core/functiongraph/FGProvider.java index 328ba8acb3..4e08ac7d75 100644 --- a/Ghidra/Features/FunctionGraph/src/main/java/ghidra/app/plugin/core/functiongraph/FGProvider.java +++ b/Ghidra/Features/FunctionGraph/src/main/java/ghidra/app/plugin/core/functiongraph/FGProvider.java @@ -1039,6 +1039,7 @@ public class FGProvider extends VisualGraphComponentProvider updateOkEnablement()); panel.add(browseButton, BorderLayout.EAST); diff --git a/Ghidra/Features/GraphServices/src/main/java/ghidra/graph/export/GraphExporterDialog.java b/Ghidra/Features/GraphServices/src/main/java/ghidra/graph/export/GraphExporterDialog.java index 6c17f706ae..1096793923 100644 --- a/Ghidra/Features/GraphServices/src/main/java/ghidra/graph/export/GraphExporterDialog.java +++ b/Ghidra/Features/GraphServices/src/main/java/ghidra/graph/export/GraphExporterDialog.java @@ -167,6 +167,7 @@ public class GraphExporterDialog extends DialogComponentProvider { setLastExportDirectory(file); filePathTextField.setText(file.getAbsolutePath()); } + chooser.dispose(); } private void setLastExportDirectory(File file) { diff --git a/Ghidra/Features/GraphServices/src/main/java/ghidra/graph/visualization/DefaultGraphDisplay.java b/Ghidra/Features/GraphServices/src/main/java/ghidra/graph/visualization/DefaultGraphDisplay.java index ad1dedf0e0..43dfe2ab0d 100644 --- a/Ghidra/Features/GraphServices/src/main/java/ghidra/graph/visualization/DefaultGraphDisplay.java +++ b/Ghidra/Features/GraphServices/src/main/java/ghidra/graph/visualization/DefaultGraphDisplay.java @@ -136,7 +136,6 @@ public class DefaultGraphDisplay implements GraphDisplay { private final SatelliteVisualizationViewer satelliteViewer; - private FilterDialog filterDialog; private AttributeFilters edgeFilters; private AttributeFilters vertexFilters; @@ -555,6 +554,7 @@ public class DefaultGraphDisplay implements GraphDisplay { // we have one less level for these transient tool options, so no need to prepend "graph." dialog.displayCategory(relativePath, ""); tool.showDialog(dialog, componentProvider); + dialog.dispose(); } } @@ -772,14 +772,14 @@ public class DefaultGraphDisplay implements GraphDisplay { } private void showFilterDialog() { - if (filterDialog == null) { - if (vertexFilters == null) { - Msg.showWarn(this, null, "No Graph", "Can't set filters with no graph present!"); - return; - } - filterDialog = new FilterDialog(vertexFilters.getButtons(), edgeFilters.getButtons()); + + if (vertexFilters == null) { + Msg.showWarn(this, null, "No Graph", "Can't set filters with no graph present!"); + return; } - componentProvider.getTool().showDialog(filterDialog); + FilterDialog dialog = + new FilterDialog(vertexFilters.getButtons(), edgeFilters.getButtons()); + componentProvider.getTool().showDialog(dialog); } private void toggleSatellite(ActionContext context) { @@ -1014,11 +1014,6 @@ public class DefaultGraphDisplay implements GraphDisplay { * configure filters for the graph, based on the vertex and edge attributes */ private void configureFilters() { - // close and rebuild filter dialog if exists - if (filterDialog != null) { - filterDialog.close(); - filterDialog = null; - } Set vertices = graph.vertexSet(); Set edges = graph.edgeSet(); vertexFilters = AttributeFilters.builder() diff --git a/Ghidra/Features/PDB/src/main/java/pdb/symbolserver/ui/FilePromptDialog.java b/Ghidra/Features/PDB/src/main/java/pdb/symbolserver/ui/FilePromptDialog.java index 14f489602f..b99e2df4b6 100644 --- a/Ghidra/Features/PDB/src/main/java/pdb/symbolserver/ui/FilePromptDialog.java +++ b/Ghidra/Features/PDB/src/main/java/pdb/symbolserver/ui/FilePromptDialog.java @@ -75,7 +75,9 @@ class FilePromptDialog extends DialogComponentProvider { FilePromptDialog filePromptDialog = new FilePromptDialog(title, prompt, chooseButtonText, directory, initialFileValue, chooserMode, fileFilters); DockingWindowManager.showDialog(filePromptDialog); - return filePromptDialog.chosenValue; + File file = filePromptDialog.chosenValue; + filePromptDialog.dispose(); + return file; } private GhidraFileChooser chooser; @@ -145,6 +147,15 @@ class FilePromptDialog extends DialogComponentProvider { addCancelButton(); } + @Override + public void dispose() { + super.dispose(); + + if (chooser != null) { + chooser.dispose(); + } + } + private void updateButtonEnablement() { okButton.setEnabled(!filePathTextField.getText().isBlank()); } diff --git a/Ghidra/Features/PDB/src/main/java/pdb/symbolserver/ui/LoadPdbDialog.java b/Ghidra/Features/PDB/src/main/java/pdb/symbolserver/ui/LoadPdbDialog.java index 5bb7ca1fc8..743cc7469e 100644 --- a/Ghidra/Features/PDB/src/main/java/pdb/symbolserver/ui/LoadPdbDialog.java +++ b/Ghidra/Features/PDB/src/main/java/pdb/symbolserver/ui/LoadPdbDialog.java @@ -131,8 +131,6 @@ public class LoadPdbDialog extends DialogComponentProvider { private JButton configButton; private JToggleButton advancedToggleButton; - private GhidraFileChooser chooser; - private JButton choosePdbLocationButton; private JButton loadPdbButton; @@ -681,7 +679,9 @@ public class LoadPdbDialog extends DialogComponentProvider { } private void choosePdbFile() { - File file = getChooser().getSelectedFile(); + GhidraFileChooser chooser = getChooser(); + File file = chooser.getSelectedFile(); + chooser.dispose(); if (file != null && file.isFile()) { Preferences.setProperty(LAST_PDBFILE_PREFERENCE_KEY, file.getPath()); executeMonitoredRunnable("Get PDB Info", true, true, 0, monitor -> { @@ -720,20 +720,17 @@ public class LoadPdbDialog extends DialogComponentProvider { private GhidraFileChooser getChooser() { - if (chooser == null) { - chooser = new GhidraFileChooser(getComponent()); - chooser.addFileFilter(PDB_FILES_FILTER); - chooser.setMultiSelectionEnabled(false); - chooser.setApproveButtonText("Choose"); - chooser.setFileSelectionMode(GhidraFileChooserMode.FILES_ONLY); - chooser.setTitle("Select PDB"); + GhidraFileChooser chooser = new GhidraFileChooser(getComponent()); + chooser.addFileFilter(PDB_FILES_FILTER); + chooser.setMultiSelectionEnabled(false); + chooser.setApproveButtonText("Choose"); + chooser.setFileSelectionMode(GhidraFileChooserMode.FILES_ONLY); + chooser.setTitle("Select PDB"); - String lastFile = Preferences.getProperty(LAST_PDBFILE_PREFERENCE_KEY); - if (lastFile != null) { - chooser.setSelectedFile(new File(lastFile)); - } + String lastFile = Preferences.getProperty(LAST_PDBFILE_PREFERENCE_KEY); + if (lastFile != null) { + chooser.setSelectedFile(new File(lastFile)); } - return chooser; } diff --git a/Ghidra/Features/PDB/src/main/java/pdb/symbolserver/ui/SymbolServerPanel.java b/Ghidra/Features/PDB/src/main/java/pdb/symbolserver/ui/SymbolServerPanel.java index f700469047..71cfec1037 100644 --- a/Ghidra/Features/PDB/src/main/java/pdb/symbolserver/ui/SymbolServerPanel.java +++ b/Ghidra/Features/PDB/src/main/java/pdb/symbolserver/ui/SymbolServerPanel.java @@ -66,7 +66,6 @@ class SymbolServerPanel extends JPanel { private GTable table; private JPanel additionalSearchLocationsPanel; private JPanel defaultConfigNotice; - private GhidraFileChooser chooser; private Consumer changeCallback; private JButton refreshSearchLocationsStatusButton; @@ -345,8 +344,10 @@ class SymbolServerPanel extends JPanel { private void chooseSymbolStorageLocation() { configChanged = true; - setSymbolStorageLocation(getChooser().getSelectedFile(), true); + GhidraFileChooser chooser = getChooser(); + setSymbolStorageLocation(chooser.getSelectedFile(), true); updateButtonEnablement(); + chooser.dispose(); } private void importLocations() { @@ -530,13 +531,11 @@ class SymbolServerPanel extends JPanel { private GhidraFileChooser getChooser() { - if (chooser == null) { - chooser = new GhidraFileChooser(this); - chooser.setMultiSelectionEnabled(false); - chooser.setApproveButtonText("Choose"); - chooser.setFileSelectionMode(GhidraFileChooserMode.DIRECTORIES_ONLY); - chooser.setTitle("Select Symbol Storage Dir"); - } + GhidraFileChooser chooser = new GhidraFileChooser(this); + chooser.setMultiSelectionEnabled(false); + chooser.setApproveButtonText("Choose"); + chooser.setFileSelectionMode(GhidraFileChooserMode.DIRECTORIES_ONLY); + chooser.setTitle("Select Symbol Storage Dir"); return chooser; } diff --git a/Ghidra/Features/ProgramDiff/src/main/java/ghidra/app/plugin/core/diff/ExecuteDiffDialog.java b/Ghidra/Features/ProgramDiff/src/main/java/ghidra/app/plugin/core/diff/ExecuteDiffDialog.java index 744f4d4f3f..6cf6559f31 100644 --- a/Ghidra/Features/ProgramDiff/src/main/java/ghidra/app/plugin/core/diff/ExecuteDiffDialog.java +++ b/Ghidra/Features/ProgramDiff/src/main/java/ghidra/app/plugin/core/diff/ExecuteDiffDialog.java @@ -23,8 +23,8 @@ import javax.swing.*; import javax.swing.border.Border; import javax.swing.border.TitledBorder; -import docking.DialogComponentProvider; import docking.DockingUtils; +import docking.ReusableDialogComponentProvider; import docking.widgets.checkbox.GCheckBox; import ghidra.program.model.address.*; import ghidra.program.model.listing.Program; @@ -37,7 +37,7 @@ import ghidra.util.HelpLocation; * It allows the user to specify the types of differences to determine * and the address set to diff. */ -public class ExecuteDiffDialog extends DialogComponentProvider { +public class ExecuteDiffDialog extends ReusableDialogComponentProvider { public static final String DIFF_ACTION = "Diff"; private static final String TITLE = "Determine Program Differences"; @@ -108,9 +108,6 @@ public class ExecuteDiffDialog extends DialogComponentProvider { addCancelButton(); } - /** - * @see ghidra.util.bean.GhidraDialog#okCallback() - */ @Override protected void okCallback() { if (!hasDiffSelection()) { @@ -118,16 +115,14 @@ public class ExecuteDiffDialog extends DialogComponentProvider { Toolkit.getDefaultToolkit().beep(); return; } - for (int i = 0; i < listenerList.size(); i++) { - ActionListener listener = listenerList.get(i); - listener.actionPerformed(new ActionEvent(this, 0, DIFF_ACTION)); + + ActionEvent event = new ActionEvent(this, 0, DIFF_ACTION); + for (ActionListener listener : listenerList) { + listener.actionPerformed(event); } close(); } - /** - * @see ghidra.util.bean.GhidraDialog#cancelCallback() - */ @Override protected void cancelCallback() { close(); @@ -318,7 +313,7 @@ public class ExecuteDiffDialog extends DialogComponentProvider { diffPropertiesCB = new GCheckBox("Properties", diffProperties); diffPropertiesCB.setName("PropertiesDiffCB"); diffPropertiesCB.setToolTipText("Highlight user defined property differences. " + - "(for example, Format (space) differences)"); + "(for example, Format (space) differences)"); diffPropertiesCB.addItemListener(event -> { diffProperties = (event.getStateChange() == ItemEvent.SELECTED); diffFilter.setFilter(ProgramDiffFilter.USER_DEFINED_DIFFS, diffProperties); @@ -340,22 +335,12 @@ public class ExecuteDiffDialog extends DialogComponentProvider { } private void createSelectAllButton() { - selectAllButton.addActionListener(new ActionListener() { - @Override - public void actionPerformed(ActionEvent e) { - setSelectAll(true); - } - }); + selectAllButton.addActionListener(e -> setSelectAll(true)); selectAllButton.setMnemonic('S'); } private void createDeselectAllButton() { - deselectAllButton.addActionListener(new ActionListener() { - @Override - public void actionPerformed(ActionEvent e) { - setSelectAll(false); - } - }); + deselectAllButton.addActionListener(e -> setSelectAll(false)); deselectAllButton.setMnemonic('D'); } diff --git a/Ghidra/Features/ProgramDiff/src/main/java/ghidra/app/plugin/core/diff/ProgramDiffPlugin.java b/Ghidra/Features/ProgramDiff/src/main/java/ghidra/app/plugin/core/diff/ProgramDiffPlugin.java index 17b82f509e..13702a3c6c 100644 --- a/Ghidra/Features/ProgramDiff/src/main/java/ghidra/app/plugin/core/diff/ProgramDiffPlugin.java +++ b/Ghidra/Features/ProgramDiff/src/main/java/ghidra/app/plugin/core/diff/ProgramDiffPlugin.java @@ -580,6 +580,11 @@ public class ProgramDiffPlugin extends ProgramPlugin if (diffDetailsProvider != null) { diffDetailsProvider.removeActionListener(diffDetailsListener); } + + if (executeDiffDialog != null) { + executeDiffDialog.dispose(); + } + actionManager.dispose(); applySettingsMgr.dispose(); markerManager.dispose(); diff --git a/Ghidra/Features/VersionTracking/src/main/java/ghidra/feature/vt/gui/filters/AncillaryFilterDialogComponentProvider.java b/Ghidra/Features/VersionTracking/src/main/java/ghidra/feature/vt/gui/filters/AncillaryFilterDialogComponentProvider.java index 751c6374b0..fc1a0da451 100644 --- a/Ghidra/Features/VersionTracking/src/main/java/ghidra/feature/vt/gui/filters/AncillaryFilterDialogComponentProvider.java +++ b/Ghidra/Features/VersionTracking/src/main/java/ghidra/feature/vt/gui/filters/AncillaryFilterDialogComponentProvider.java @@ -20,16 +20,17 @@ import java.util.Map.Entry; import javax.swing.JComponent; -import docking.DialogComponentProvider; +import docking.ReusableDialogComponentProvider; import ghidra.feature.vt.gui.filters.Filter.FilterShortcutState; import ghidra.feature.vt.gui.plugin.VTController; -public abstract class AncillaryFilterDialogComponentProvider extends DialogComponentProvider { +public abstract class AncillaryFilterDialogComponentProvider + extends ReusableDialogComponentProvider { private FilterChangedListener filterChangedListener; - private Set> ancillaryFilters = new HashSet>(); + private Set> ancillaryFilters = new HashSet<>(); private Map, FilterState> originalState = - new HashMap, FilterState>(); + new HashMap<>(); protected final VTController controller; private final FilterDialogModel dialogModel; @@ -38,7 +39,7 @@ public abstract class AncillaryFilterDialogComponentProvider extends DialogCo protected AncillaryFilterDialogComponentProvider(VTController controller, String title, FilterDialogModel dialogModel) { - super(title, true); + super(title); this.controller = controller; this.dialogModel = dialogModel; @@ -141,7 +142,7 @@ public abstract class AncillaryFilterDialogComponentProvider extends DialogCo } private Map, FilterState> getCurrentState() { - Map, FilterState> state = new HashMap, FilterState>(); + Map, FilterState> state = new HashMap<>(); for (AncillaryFilter filter : ancillaryFilters) { state.put(filter, filter.getFilterState()); } diff --git a/Ghidra/Features/VersionTracking/src/main/java/ghidra/feature/vt/gui/provider/markuptable/VTMarkupItemsTableProvider.java b/Ghidra/Features/VersionTracking/src/main/java/ghidra/feature/vt/gui/provider/markuptable/VTMarkupItemsTableProvider.java index 7d7c639712..556588d2a5 100644 --- a/Ghidra/Features/VersionTracking/src/main/java/ghidra/feature/vt/gui/provider/markuptable/VTMarkupItemsTableProvider.java +++ b/Ghidra/Features/VersionTracking/src/main/java/ghidra/feature/vt/gui/provider/markuptable/VTMarkupItemsTableProvider.java @@ -535,6 +535,8 @@ public class VTMarkupItemsTableProvider extends ComponentProviderAdapter filter.dispose(); } + ancillaryFilterDialog.dispose(); + tool.removePopupActionProvider(this); } diff --git a/Ghidra/Features/VersionTracking/src/main/java/ghidra/feature/vt/gui/provider/matchtable/VTMatchTableProvider.java b/Ghidra/Features/VersionTracking/src/main/java/ghidra/feature/vt/gui/provider/matchtable/VTMatchTableProvider.java index e1e355c52e..2a5bcc219b 100644 --- a/Ghidra/Features/VersionTracking/src/main/java/ghidra/feature/vt/gui/provider/matchtable/VTMatchTableProvider.java +++ b/Ghidra/Features/VersionTracking/src/main/java/ghidra/feature/vt/gui/provider/matchtable/VTMatchTableProvider.java @@ -456,6 +456,8 @@ public class VTMatchTableProvider extends ComponentProviderAdapter for (Filter filter : filters) { filter.dispose(); } + + ancillaryFilterDialog.dispose(); } @Override diff --git a/Ghidra/Framework/Docking/src/main/java/docking/AbstractErrDialog.java b/Ghidra/Framework/Docking/src/main/java/docking/AbstractErrDialog.java index b3e4b9a50c..3d7a1c9970 100644 --- a/Ghidra/Framework/Docking/src/main/java/docking/AbstractErrDialog.java +++ b/Ghidra/Framework/Docking/src/main/java/docking/AbstractErrDialog.java @@ -20,7 +20,7 @@ import utility.function.Callback; /** * A dialog that is meant to be extended for showing exceptions */ -public abstract class AbstractErrDialog extends DialogComponentProvider { +public abstract class AbstractErrDialog extends ReusableDialogComponentProvider { // at some point, there are too many exceptions to show protected static final int MAX_EXCEPTIONS = 100; diff --git a/Ghidra/Framework/Docking/src/main/java/docking/DialogComponentProvider.java b/Ghidra/Framework/Docking/src/main/java/docking/DialogComponentProvider.java index 38fe4f4b06..b8b2c8a10a 100644 --- a/Ghidra/Framework/Docking/src/main/java/docking/DialogComponentProvider.java +++ b/Ghidra/Framework/Docking/src/main/java/docking/DialogComponentProvider.java @@ -32,7 +32,7 @@ import docking.event.mouse.GMouseListenerAdapter; import docking.menu.DialogToolbarButton; import docking.util.AnimationUtils; import docking.widgets.label.GDHtmlLabel; -import generic.theme.*; +import generic.theme.GColor; import generic.theme.GThemeDefaults.Colors.Messages; import ghidra.util.*; import ghidra.util.exception.AssertException; @@ -85,7 +85,7 @@ public class DialogComponentProvider private CardLayout progressCardLayout; private JButton defaultButton; - private DockingDialog dialog; + DockingDialog dialog; private Component focusComponent; private JPanel toolbar; @@ -103,7 +103,6 @@ public class DialogComponentProvider private boolean isTransient = false; private Dimension defaultSize; - private ThemeListener themeListener = this::themeChanged; /** * Constructor for a DialogComponentProvider that will be modal and will include a status line and @@ -178,8 +177,6 @@ public class DialogComponentProvider installEscapeAction(); doInitialize(); - - Gui.addThemeListener(themeListener); } private void installEscapeAction() { @@ -344,20 +341,6 @@ public class DialogComponentProvider } } - private void themeChanged(ThemeEvent ev) { - if (!ev.isLookAndFeelChanged()) { - return; // we only care if the Look and Feel changes - } - - // if we are visible, then we don't need to update as the system updates all - // visible components - if (isVisible()) { - return; - } - Component component = dialog != null ? dialog : rootPanel; - SwingUtilities.updateComponentTreeUI(component); - } - private void uninstallMouseListener(Component comp) { if (comp instanceof CellRendererPane) { return; @@ -898,16 +881,25 @@ public class DialogComponentProvider } public void close() { - if (isShowing()) { - dialog.close(); - } - + closeDialog(); + dispose(); } + protected void closeDialog() { + if (isShowing()) { + cancelCurrentTask(); + dialog.close(); + } + } + + /** + * Disposes this dialog. Only call this when the dialog is no longer used. Calling this method + * will close the dialog if it is open. + */ public void dispose() { - Gui.removeThemeListener(themeListener); - cancelCurrentTask(); - close(); + + closeDialog(); + popupManager.dispose(); dialogActions.forEach(DockingActionIf::dispose); diff --git a/Ghidra/Framework/Docking/src/main/java/docking/DockingErrorDisplay.java b/Ghidra/Framework/Docking/src/main/java/docking/DockingErrorDisplay.java index 5cba1dae4a..834ccb7623 100644 --- a/Ghidra/Framework/Docking/src/main/java/docking/DockingErrorDisplay.java +++ b/Ghidra/Framework/Docking/src/main/java/docking/DockingErrorDisplay.java @@ -173,6 +173,7 @@ public class DockingErrorDisplay implements ErrorDisplay { activeDialog = createErrorDialog(title, throwable, messageString); activeDialog.setClosedCallback(() -> { activeDialog.setClosedCallback(null); + activeDialog.dispose(); activeDialog = null; }); DockingWindowManager.showDialog(parent, activeDialog); diff --git a/Ghidra/Framework/Docking/src/main/java/docking/ReusableDialogComponentProvider.java b/Ghidra/Framework/Docking/src/main/java/docking/ReusableDialogComponentProvider.java new file mode 100644 index 0000000000..a8db9a4509 --- /dev/null +++ b/Ghidra/Framework/Docking/src/main/java/docking/ReusableDialogComponentProvider.java @@ -0,0 +1,89 @@ +/* ### + * 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 docking; + +import java.awt.Component; + +import javax.swing.SwingUtilities; + +import generic.theme.*; +import ghidra.util.task.Task; + +/** + * A version of {@link DialogComponentProvider} for clients to extend when they intend for their + * dialog to be reused. Typically, dialogs are used once and then no longer referenced. + * Alternatively, some clients create a dialog and use it for the lifetime of their code. This + * is typical of non-modal plugins. + *

+ * If you extend this class, then you must call the {@link #dispose()} method when you are done + * with the dialog, such as in your plugin's {@code dispose()} method. + *

+ * The primary benefit of using this dialog is that any updates to the current theme will update + * this dialog, even when the dialog is not visible. For dialogs that extend + * {@link DialogComponentProvider} directly, they only receive theme updates if they are visible. + * + * @see DialogComponentProvider + */ +public class ReusableDialogComponentProvider extends DialogComponentProvider { + + private ThemeListener themeListener = this::themeChanged; + + protected ReusableDialogComponentProvider(String title) { + this(title, true, true, true, false); + } + + /** + * Constructs a new ReusableDialogComponentProvider. + * @param title the title for this dialog. + * @param modal true if this dialog should be modal. + * @param includeStatus true if this dialog should include a status line. + * @param includeButtons true if this dialog will have a button panel at the bottom. + * @param canRunTasks true means this dialog can execute tasks + * ({@link #executeProgressTask(Task, int)} and it will show a progress monitor when + * doing so. + */ + protected ReusableDialogComponentProvider(String title, boolean modal, boolean includeStatus, + boolean includeButtons, boolean canRunTasks) { + super(title, modal, includeStatus, includeButtons, canRunTasks); + Gui.addThemeListener(themeListener); + } + + private void themeChanged(ThemeEvent ev) { + if (!ev.isLookAndFeelChanged()) { + return; // we only care if the Look and Feel changes + } + + // if we are visible, then we don't need to update as the system updates all + // visible components + if (isVisible()) { + return; + } + Component component = dialog != null ? dialog : rootPanel; + SwingUtilities.updateComponentTreeUI(component); + } + + @Override + public void close() { + // Overridden to *not* all dispose() when closed, since this dialog is meant to be reused + closeDialog(); + } + + @Override + public void dispose() { + super.dispose(); + Gui.removeThemeListener(themeListener); + } +} diff --git a/Ghidra/Framework/Docking/src/main/java/docking/action/MultipleKeyAction.java b/Ghidra/Framework/Docking/src/main/java/docking/action/MultipleKeyAction.java index b44e96f3ba..952a2b00fd 100644 --- a/Ghidra/Framework/Docking/src/main/java/docking/action/MultipleKeyAction.java +++ b/Ghidra/Framework/Docking/src/main/java/docking/action/MultipleKeyAction.java @@ -33,8 +33,6 @@ import ghidra.util.Swing; public class MultipleKeyAction extends DockingKeyBindingAction { private List actions = new ArrayList<>(); - private MultiActionDialog dialog; - /** * Creates new MultipleKeyAction * @@ -124,12 +122,8 @@ public class MultipleKeyAction extends DockingKeyBindingAction { // If more than one action, prompt user for selection if (list.size() > 1) { // popup dialog to show multiple actions - if (dialog == null) { - dialog = new MultiActionDialog(KeyBindingUtils.parseKeyStroke(keyStroke), list); - } - else { - dialog.setActionList(list); - } + MultiActionDialog dialog = + new MultiActionDialog(KeyBindingUtils.parseKeyStroke(keyStroke), list); // doing the show in an invoke later seems to fix a strange swing bug that lock up // the program if you tried to invoke a new action too quickly after invoking diff --git a/Ghidra/Framework/Docking/src/main/java/docking/actions/KeyBindingUtils.java b/Ghidra/Framework/Docking/src/main/java/docking/actions/KeyBindingUtils.java index 40b01dfec2..b8ddb71011 100644 --- a/Ghidra/Framework/Docking/src/main/java/docking/actions/KeyBindingUtils.java +++ b/Ghidra/Framework/Docking/src/main/java/docking/actions/KeyBindingUtils.java @@ -952,7 +952,7 @@ public class KeyBindingUtils { // return them to that spot if they user the dialog again. Preferences.setProperty(LAST_KEY_BINDING_EXPORT_DIRECTORY, fileChooser.getCurrentDirectory().getAbsolutePath()); - + fileChooser.dispose(); return selectedFile; } } diff --git a/Ghidra/Framework/Docking/src/main/java/docking/help/HelpViewSearcher.java b/Ghidra/Framework/Docking/src/main/java/docking/help/HelpViewSearcher.java index e1ef7e54b6..33045e9ff8 100644 --- a/Ghidra/Framework/Docking/src/main/java/docking/help/HelpViewSearcher.java +++ b/Ghidra/Framework/Docking/src/main/java/docking/help/HelpViewSearcher.java @@ -15,12 +15,13 @@ */ package docking.help; -import java.awt.*; +import java.awt.Component; +import java.awt.Window; import java.awt.event.*; +import java.awt.geom.Rectangle2D; import java.io.File; import java.net.URL; import java.util.*; -import java.util.List; import java.util.regex.*; import javax.help.*; @@ -291,8 +292,8 @@ class HelpViewSearcher { } try { - Rectangle rectangle = htmlEditorPane.modelToView(start); - htmlEditorPane.scrollRectToVisible(rectangle); + Rectangle2D rectangle = htmlEditorPane.modelToView2D(start); + htmlEditorPane.scrollRectToVisible(rectangle.getBounds()); } catch (BadLocationException e) { // shouldn't happen diff --git a/Ghidra/Framework/Docking/src/main/java/docking/options/editor/FileChooserEditor.java b/Ghidra/Framework/Docking/src/main/java/docking/options/editor/FileChooserEditor.java index 42628ca6cd..53b46e104d 100644 --- a/Ghidra/Framework/Docking/src/main/java/docking/options/editor/FileChooserEditor.java +++ b/Ghidra/Framework/Docking/src/main/java/docking/options/editor/FileChooserEditor.java @@ -28,6 +28,7 @@ import org.apache.commons.lang3.StringUtils; import docking.widgets.button.BrowseButton; import docking.widgets.filechooser.GhidraFileChooser; +import docking.widgets.filechooser.GhidraFileChooserMode; /** * Bean editor to show a text field and a browse button to bring @@ -160,7 +161,7 @@ public class FileChooserEditor extends PropertyEditorSupport { fileChooser.setApproveButtonText("Choose Path"); fileChooser.setTitle("Choose Path"); - fileChooser.setFileSelectionMode(GhidraFileChooser.FILES_AND_DIRECTORIES); + fileChooser.setFileSelectionMode(GhidraFileChooserMode.FILES_AND_DIRECTORIES); if (currentFileValue != null) { fileChooser.setSelectedFile(currentFileValue); } diff --git a/Ghidra/Framework/Docking/src/main/java/docking/options/editor/FontEditor.java b/Ghidra/Framework/Docking/src/main/java/docking/options/editor/FontEditor.java index b44509de46..e66a1d4d81 100644 --- a/Ghidra/Framework/Docking/src/main/java/docking/options/editor/FontEditor.java +++ b/Ghidra/Framework/Docking/src/main/java/docking/options/editor/FontEditor.java @@ -81,7 +81,7 @@ public class FontEditor extends PropertyEditorSupport { setValue(font); } - class EditorDialogProvider extends DialogComponentProvider { + private class EditorDialogProvider extends DialogComponentProvider { private Font originalFont = (Font) getValue(); EditorDialogProvider() { diff --git a/Ghidra/Framework/Docking/src/main/java/docking/options/editor/IconPropertyEditor.java b/Ghidra/Framework/Docking/src/main/java/docking/options/editor/IconPropertyEditor.java index d04d76393c..f068b3bcec 100644 --- a/Ghidra/Framework/Docking/src/main/java/docking/options/editor/IconPropertyEditor.java +++ b/Ghidra/Framework/Docking/src/main/java/docking/options/editor/IconPropertyEditor.java @@ -193,6 +193,7 @@ public class IconPropertyEditor extends PropertyEditorSupport { Preferences.setProperty(LAST_ICON_DIR_PREFERENCE_KEY, dir.getAbsolutePath()); importIconFile(file); } + chooser.dispose(); } private void importIconFile(File file) { diff --git a/Ghidra/Framework/Docking/src/main/java/docking/options/editor/OptionsDialog.java b/Ghidra/Framework/Docking/src/main/java/docking/options/editor/OptionsDialog.java index 973c012b7a..bef0d8d71e 100644 --- a/Ghidra/Framework/Docking/src/main/java/docking/options/editor/OptionsDialog.java +++ b/Ghidra/Framework/Docking/src/main/java/docking/options/editor/OptionsDialog.java @@ -20,14 +20,14 @@ import java.beans.PropertyChangeListener; import javax.swing.tree.TreePath; -import docking.DialogComponentProvider; +import docking.ReusableDialogComponentProvider; import docking.widgets.OptionDialog; import ghidra.framework.options.Options; /** * Dialog for editing options within a tool. */ -public class OptionsDialog extends DialogComponentProvider { +public class OptionsDialog extends ReusableDialogComponentProvider { private OptionsPanel panel; private boolean hasChanges; diff --git a/Ghidra/Framework/Docking/src/main/java/docking/theme/gui/ExportThemeDialog.java b/Ghidra/Framework/Docking/src/main/java/docking/theme/gui/ExportThemeDialog.java index 9c3de8614f..deeb593394 100644 --- a/Ghidra/Framework/Docking/src/main/java/docking/theme/gui/ExportThemeDialog.java +++ b/Ghidra/Framework/Docking/src/main/java/docking/theme/gui/ExportThemeDialog.java @@ -158,6 +158,7 @@ public class ExportThemeDialog extends DialogComponentProvider { if (file != null) { fileTextField.setText(file.getAbsolutePath()); } + chooser.dispose(); } // used for testing diff --git a/Ghidra/Framework/Docking/src/main/java/docking/theme/gui/ThemeUtils.java b/Ghidra/Framework/Docking/src/main/java/docking/theme/gui/ThemeUtils.java index 58aa283cc3..7fa27c6f97 100644 --- a/Ghidra/Framework/Docking/src/main/java/docking/theme/gui/ThemeUtils.java +++ b/Ghidra/Framework/Docking/src/main/java/docking/theme/gui/ThemeUtils.java @@ -113,6 +113,7 @@ public class ThemeUtils { GTheme.FILE_EXTENSION, GTheme.ZIP_FILE_EXTENSION)); File file = chooser.getSelectedFile(); + chooser.dispose(); if (file == null) { return; } diff --git a/Ghidra/Framework/Docking/src/main/java/docking/theme/gui/ThemeValueEditor.java b/Ghidra/Framework/Docking/src/main/java/docking/theme/gui/ThemeValueEditor.java index 068bd640ae..3cd789a8b3 100644 --- a/Ghidra/Framework/Docking/src/main/java/docking/theme/gui/ThemeValueEditor.java +++ b/Ghidra/Framework/Docking/src/main/java/docking/theme/gui/ThemeValueEditor.java @@ -20,8 +20,8 @@ import java.beans.*; import javax.swing.*; -import docking.DialogComponentProvider; import docking.DockingWindowManager; +import docking.ReusableDialogComponentProvider; import generic.theme.ThemeValue; /** @@ -106,7 +106,7 @@ public abstract class ThemeValueEditor { clientListener.propertyChange(event); } - class EditorDialog extends DialogComponentProvider { + class EditorDialog extends ReusableDialogComponentProvider { private PropertyChangeListener internalListener = ev -> editorChanged(); private ThemeValue originalValue; diff --git a/Ghidra/Framework/Docking/src/main/java/docking/widgets/FindDialog.java b/Ghidra/Framework/Docking/src/main/java/docking/widgets/FindDialog.java index 52b8639c23..ccfce998e9 100644 --- a/Ghidra/Framework/Docking/src/main/java/docking/widgets/FindDialog.java +++ b/Ghidra/Framework/Docking/src/main/java/docking/widgets/FindDialog.java @@ -23,12 +23,12 @@ import javax.swing.*; import javax.swing.event.DocumentEvent; import javax.swing.event.DocumentListener; -import docking.DialogComponentProvider; +import docking.ReusableDialogComponentProvider; import docking.widgets.button.GRadioButton; import docking.widgets.combobox.GhidraComboBox; import docking.widgets.label.GLabel; -public class FindDialog extends DialogComponentProvider { +public class FindDialog extends ReusableDialogComponentProvider { private GhidraComboBox comboBox; diff --git a/Ghidra/Framework/Docking/src/main/java/docking/widgets/PasswordDialog.java b/Ghidra/Framework/Docking/src/main/java/docking/widgets/PasswordDialog.java index 287d24c7f7..8a84b609cd 100644 --- a/Ghidra/Framework/Docking/src/main/java/docking/widgets/PasswordDialog.java +++ b/Ghidra/Framework/Docking/src/main/java/docking/widgets/PasswordDialog.java @@ -269,13 +269,16 @@ public class PasswordDialog extends DialogComponentProvider { close(); } + @Override + public void close() { + // overridden to not call dispose, since this class does special cleanup on close + closeDialog(); + } + @Override public void dispose() { - if (passwordField != null) { - passwordField.setText(""); - rootPanel.remove(passwordField); - passwordField = null; - } + passwordField.setText(""); + rootPanel.remove(passwordField); } } diff --git a/Ghidra/Framework/Docking/src/main/java/docking/widgets/filechooser/GFileChooserOptionsDialog.java b/Ghidra/Framework/Docking/src/main/java/docking/widgets/filechooser/GFileChooserOptionsDialog.java index 552fb522d4..20282b3897 100644 --- a/Ghidra/Framework/Docking/src/main/java/docking/widgets/filechooser/GFileChooserOptionsDialog.java +++ b/Ghidra/Framework/Docking/src/main/java/docking/widgets/filechooser/GFileChooserOptionsDialog.java @@ -17,13 +17,13 @@ package docking.widgets.filechooser; import javax.swing.*; -import docking.DialogComponentProvider; +import docking.ReusableDialogComponentProvider; import docking.widgets.checkbox.GCheckBox; import docking.widgets.label.GLabel; import ghidra.framework.preferences.Preferences; import ghidra.util.layout.PairLayout; -class GFileChooserOptionsDialog extends DialogComponentProvider { +class GFileChooserOptionsDialog extends ReusableDialogComponentProvider { static final String SHOW_DOT_FILES_PROPERTY_NAME = "G_FILE_CHOOSER.ShowDotFiles"; private static final String SHOW_DOT_FILES_DEFAULT = "false"; @@ -31,7 +31,7 @@ class GFileChooserOptionsDialog extends DialogComponentProvider { private JCheckBox showDotFilesCheckBox; GFileChooserOptionsDialog() { - super("File Chooser Options", true); + super("File Chooser Options"); addWorkPanel(buildComponent()); diff --git a/Ghidra/Framework/Docking/src/main/java/docking/widgets/filechooser/GhidraFileChooser.java b/Ghidra/Framework/Docking/src/main/java/docking/widgets/filechooser/GhidraFileChooser.java index 9a30edb1de..713f9d39b3 100644 --- a/Ghidra/Framework/Docking/src/main/java/docking/widgets/filechooser/GhidraFileChooser.java +++ b/Ghidra/Framework/Docking/src/main/java/docking/widgets/filechooser/GhidraFileChooser.java @@ -30,6 +30,8 @@ import javax.swing.event.CellEditorListener; import javax.swing.event.ChangeEvent; import javax.swing.filechooser.FileSystemView; +import org.apache.commons.lang3.StringUtils; + import docking.*; import docking.widgets.*; import docking.widgets.combobox.GComboBox; @@ -68,7 +70,7 @@ import util.HistoryList; *

  • This class provides shortcut buttons similar to those of the Windows native chooser
  • * */ -public class GhidraFileChooser extends DialogComponentProvider implements FileFilter { +public class GhidraFileChooser extends ReusableDialogComponentProvider implements FileFilter { static final String UP_BUTTON_NAME = "UP_BUTTON"; private static final Color FOREROUND_COLOR = new GColor("color.fg.filechooser"); @@ -202,6 +204,8 @@ public class GhidraFileChooser extends DialogComponentProvider implements FileFi // Listener for selections on the filename drop-down private SelectionListener selectionListener; + private String lastDirectoryPreferencKey; + /** * Constructs a new ghidra file chooser. * @param parent the parent component @@ -848,6 +852,29 @@ public class GhidraFileChooser extends DialogComponentProvider implements FileFi updateShortCutPanel(); } + /** + * Sets the preference key for this chooser to use when saving the last directory that was used + * to successfully choose a file. + * @param newKey the key + */ + public void setLastDirectoryPreference(String newKey) { + this.lastDirectoryPreferencKey = newKey; + + if (StringUtils.isBlank(newKey)) { + return; + } + + String path = Preferences.getProperty(newKey); + if (path == null) { + return; + } + + File dir = new File(path); + if (isDirectory(dir)) { + updateDirOnly(dir, true); + } + } + /** * Returns the selected file. This can be set either by the programmer via * {@link #setSelectedFile(File)} or by a user action, such as either typing the @@ -1046,6 +1073,7 @@ public class GhidraFileChooser extends DialogComponentProvider implements FileFi private void savePreferences() { saveSize(); saveViewStyle(); + saveLastDirectory(); Preferences.store(); } @@ -1070,6 +1098,24 @@ public class GhidraFileChooser extends DialogComponentProvider implements FileFi Preferences.setProperty(VIEW_STYLE_PREFIX + titleKey, detailsString); } + private void saveLastDirectory() { + if (lastDirectoryPreferencKey == null) { + return; + } + + File file = validatedFiles.getFile(); + if (file == null) { + return; + } + + File dir = file.getParentFile(); + if (dir == null) { + return; + } + + Preferences.setProperty(lastDirectoryPreferencKey, dir.getPath()); + } + private void restoreSize() { String titleKey = getTitle(); String savedWidth = Preferences.getProperty(WIDTH_PREFERENCE_PREFIX + titleKey); @@ -1466,6 +1512,7 @@ public class GhidraFileChooser extends DialogComponentProvider implements FileFi @Override public void dispose() { actionManager.dispose(); + optionsDialog.dispose(); close(); fileChooserModel = null; } @@ -1803,7 +1850,7 @@ public class GhidraFileChooser extends DialogComponentProvider implements FileFi } // - // Handle the case where the current directly name can get double appended + // Handle the case where the current directory name can get double appended // if (!testFile.exists() && testFile.getName().equals(currentDirectory.getName())) { testFile = currentDirectory; diff --git a/Ghidra/Framework/Docking/src/main/java/docking/widgets/filechooser/GhidraFileChooserPanel.java b/Ghidra/Framework/Docking/src/main/java/docking/widgets/filechooser/GhidraFileChooserPanel.java index e390661150..4e14d8647d 100644 --- a/Ghidra/Framework/Docking/src/main/java/docking/widgets/filechooser/GhidraFileChooserPanel.java +++ b/Ghidra/Framework/Docking/src/main/java/docking/widgets/filechooser/GhidraFileChooserPanel.java @@ -73,6 +73,7 @@ public class GhidraFileChooserPanel extends JPanel implements Droppable { * @param propertyName the property name to save state * @param defaultFileName the default file name. * @param createBorder flag to create the border or not. + * @param mode whether {@link #INPUT_MODE} or {@link #OUTPUT_MODE} */ public GhidraFileChooserPanel(String title, String propertyName, String defaultFileName, boolean createBorder, int mode) { @@ -86,6 +87,12 @@ public class GhidraFileChooserPanel extends JPanel implements Droppable { setupDragAndDrop(); } + public void dispose() { + if (fileChooser != null) { + fileChooser.dispose(); + } + } + /** * Sets the listener. * @param listener the new listener diff --git a/Ghidra/Framework/Docking/src/main/java/docking/widgets/imagepanel/actions/SaveImageAction.java b/Ghidra/Framework/Docking/src/main/java/docking/widgets/imagepanel/actions/SaveImageAction.java index 1dd5f15769..ff5f350a31 100644 --- a/Ghidra/Framework/Docking/src/main/java/docking/widgets/imagepanel/actions/SaveImageAction.java +++ b/Ghidra/Framework/Docking/src/main/java/docking/widgets/imagepanel/actions/SaveImageAction.java @@ -64,7 +64,7 @@ public class SaveImageAction extends ImagePanelDockingAction { chooser.setMultiSelectionEnabled(false); File selected = chooser.getSelectedFile(true); - + chooser.dispose(); if (chooser.wasCancelled()) { return null; } diff --git a/Ghidra/Framework/Docking/src/main/java/docking/widgets/pathmanager/PathManager.java b/Ghidra/Framework/Docking/src/main/java/docking/widgets/pathmanager/PathManager.java index 95cfa0afbb..1d3ee58dca 100644 --- a/Ghidra/Framework/Docking/src/main/java/docking/widgets/pathmanager/PathManager.java +++ b/Ghidra/Framework/Docking/src/main/java/docking/widgets/pathmanager/PathManager.java @@ -54,8 +54,7 @@ public class PathManager { private JButton downButton; private JButton addButton; private JButton removeButton; - private GhidraFileChooser fileChooser; - private String preferenceForLastSelectedDir = Preferences.LAST_IMPORT_DIRECTORY; + private String preferenceForLastSelectedDir = Preferences.LAST_PATH_DIRECTORY; private String title = "Select File"; private GhidraFileChooserMode fileChooserMode = GhidraFileChooserMode.FILES_ONLY; private boolean allowMultiFileSelection; @@ -98,7 +97,6 @@ public class PathManager { fileChooserMode = selectionMode; allowMultiFileSelection = allowMultiSelection; this.filter = filter; - this.fileChooser = null; } /** @@ -295,32 +293,28 @@ public class PathManager { } private void add() { - if (fileChooser == null) { - fileChooser = new GhidraFileChooser(panel); - fileChooser.setMultiSelectionEnabled(allowMultiFileSelection); - fileChooser.setFileSelectionMode(fileChooserMode); - fileChooser.setTitle(title); - fileChooser.setApproveButtonToolTipText(title); - if (filter != null) { - fileChooser.addFileFilter(new GhidraFileFilter() { - @Override - public String getDescription() { - return filter.getDescription(); - } - @Override - public boolean accept(File f, GhidraFileChooserModel l_model) { - return filter.accept(f, l_model); - } - }); - } - String dir = Preferences.getProperty(preferenceForLastSelectedDir); - if (dir != null) { - fileChooser.setCurrentDirectory(new File(dir)); - } + GhidraFileChooser fileChooser = new GhidraFileChooser(panel); + fileChooser.setMultiSelectionEnabled(allowMultiFileSelection); + fileChooser.setFileSelectionMode(fileChooserMode); + fileChooser.setTitle(title); + fileChooser.setApproveButtonToolTipText(title); + if (filter != null) { + fileChooser.addFileFilter(new GhidraFileFilter() { + @Override + public String getDescription() { + return filter.getDescription(); + } + + @Override + public boolean accept(File f, GhidraFileChooserModel l_model) { + return filter.accept(f, l_model); + } + }); } - else { - fileChooser.rescanCurrentDirectory(); + String dir = Preferences.getProperty(preferenceForLastSelectedDir); + if (dir != null) { + fileChooser.setCurrentDirectory(new File(dir)); } List files = fileChooser.getSelectedFiles(); @@ -340,6 +334,8 @@ public class PathManager { Preferences.setProperty(preferenceForLastSelectedDir, path); } } + + fileChooser.dispose(); } private void up() { diff --git a/Ghidra/Framework/Docking/src/main/java/docking/widgets/pathmanager/PathnameTablePanel.java b/Ghidra/Framework/Docking/src/main/java/docking/widgets/pathmanager/PathnameTablePanel.java index 798ba6c242..0cf2ae7952 100644 --- a/Ghidra/Framework/Docking/src/main/java/docking/widgets/pathmanager/PathnameTablePanel.java +++ b/Ghidra/Framework/Docking/src/main/java/docking/widgets/pathmanager/PathnameTablePanel.java @@ -53,8 +53,7 @@ public class PathnameTablePanel extends JPanel { private JButton addButton; private JButton removeButton; private JButton resetButton; - private GhidraFileChooser fileChooser; - private String preferenceForLastSelectedDir = Preferences.LAST_IMPORT_DIRECTORY; + private String preferenceForLastSelectedDir = Preferences.LAST_PATH_DIRECTORY; private String title = "Select File"; private boolean allowMultiFileSelection; private GhidraFileFilter filter; @@ -296,32 +295,28 @@ public class PathnameTablePanel extends JPanel { } private void add() { - if (fileChooser == null) { - fileChooser = new GhidraFileChooser(this); - fileChooser.setMultiSelectionEnabled(allowMultiFileSelection); - fileChooser.setFileSelectionMode(fileChooserMode); - fileChooser.setTitle(title); - fileChooser.setApproveButtonToolTipText(title); - if (filter != null) { - fileChooser.addFileFilter(new GhidraFileFilter() { - @Override - public String getDescription() { - return filter.getDescription(); - } - @Override - public boolean accept(File f, GhidraFileChooserModel model) { - return filter.accept(f, model); - } - }); - } - String dir = Preferences.getProperty(preferenceForLastSelectedDir); - if (dir != null) { - fileChooser.setCurrentDirectory(new File(dir)); - } + GhidraFileChooser fileChooser = new GhidraFileChooser(this); + fileChooser.setMultiSelectionEnabled(allowMultiFileSelection); + fileChooser.setFileSelectionMode(fileChooserMode); + fileChooser.setTitle(title); + fileChooser.setApproveButtonToolTipText(title); + if (filter != null) { + fileChooser.addFileFilter(new GhidraFileFilter() { + @Override + public String getDescription() { + return filter.getDescription(); + } + + @Override + public boolean accept(File f, GhidraFileChooserModel model) { + return filter.accept(f, model); + } + }); } - else { - fileChooser.rescanCurrentDirectory(); + String dir = Preferences.getProperty(preferenceForLastSelectedDir); + if (dir != null) { + fileChooser.setCurrentDirectory(new File(dir)); } List files = fileChooser.getSelectedFiles(); @@ -342,6 +337,8 @@ public class PathnameTablePanel extends JPanel { } } + fileChooser.dispose(); + tableModel.addPaths(paths, addToTop); } diff --git a/Ghidra/Framework/Docking/src/main/java/docking/widgets/table/GTable.java b/Ghidra/Framework/Docking/src/main/java/docking/widgets/table/GTable.java index 35335b9bdd..254e56a3d1 100644 --- a/Ghidra/Framework/Docking/src/main/java/docking/widgets/table/GTable.java +++ b/Ghidra/Framework/Docking/src/main/java/docking/widgets/table/GTable.java @@ -1197,6 +1197,7 @@ public class GTable extends JTable { private File chooseExportFile() { GhidraFileChooser chooser = createExportFileChooser(); File file = chooser.getSelectedFile(); + chooser.dispose(); if (file == null) { return null; } diff --git a/Ghidra/Framework/Docking/src/main/java/docking/widgets/table/GTableFilterPanel.java b/Ghidra/Framework/Docking/src/main/java/docking/widgets/table/GTableFilterPanel.java index fdc644ee66..a26666ae29 100644 --- a/Ghidra/Framework/Docking/src/main/java/docking/widgets/table/GTableFilterPanel.java +++ b/Ghidra/Framework/Docking/src/main/java/docking/widgets/table/GTableFilterPanel.java @@ -578,6 +578,10 @@ public class GTableFilterPanel extends JPanel { columnModel.removeColumnModelListener(columnModelListener); columnModelListener = null; + if (columnFilterDialog != null) { + columnFilterDialog.dispose(); + } + table.removePropertyChangeListener(badProgrammingPropertyChangeListener); updateManager.dispose(); diff --git a/Ghidra/Framework/Docking/src/main/java/docking/widgets/table/constraint/dialog/ColumnFilterDialog.java b/Ghidra/Framework/Docking/src/main/java/docking/widgets/table/constraint/dialog/ColumnFilterDialog.java index 82e9ad055b..ed1d4efec9 100644 --- a/Ghidra/Framework/Docking/src/main/java/docking/widgets/table/constraint/dialog/ColumnFilterDialog.java +++ b/Ghidra/Framework/Docking/src/main/java/docking/widgets/table/constraint/dialog/ColumnFilterDialog.java @@ -47,7 +47,7 @@ import utility.function.Callback; * * @param the row type of the table being filtered. */ -public class ColumnFilterDialog extends DialogComponentProvider +public class ColumnFilterDialog extends ReusableDialogComponentProvider implements TableFilterDialogModelListener { private final ColumnFilterDialogModel filterModel; @@ -72,7 +72,7 @@ public class ColumnFilterDialog extends DialogComponentProvider */ public ColumnFilterDialog(GTableFilterPanel gTableFilterPanel, JTable table, RowObjectFilterModel tableModel) { - super("Table Column Filters", WindowUtilities.areModalDialogsVisible()); + super("Table Column Filters", WindowUtilities.areModalDialogsVisible(), true, true, false); this.gTableFilterPanel = gTableFilterPanel; this.table = table; this.tableModel = tableModel; diff --git a/Ghidra/Framework/Docking/src/main/java/docking/widgets/tree/DefaultGTreeFilterProvider.java b/Ghidra/Framework/Docking/src/main/java/docking/widgets/tree/DefaultGTreeFilterProvider.java index f398f8f015..fb2e2fc23f 100644 --- a/Ghidra/Framework/Docking/src/main/java/docking/widgets/tree/DefaultGTreeFilterProvider.java +++ b/Ghidra/Framework/Docking/src/main/java/docking/widgets/tree/DefaultGTreeFilterProvider.java @@ -4,9 +4,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. diff --git a/Ghidra/Framework/Docking/src/main/java/docking/wizard/WizardManager.java b/Ghidra/Framework/Docking/src/main/java/docking/wizard/WizardManager.java index 7024d97153..a80170bd5a 100644 --- a/Ghidra/Framework/Docking/src/main/java/docking/wizard/WizardManager.java +++ b/Ghidra/Framework/Docking/src/main/java/docking/wizard/WizardManager.java @@ -23,8 +23,8 @@ import java.io.IOException; import javax.swing.*; import javax.swing.border.TitledBorder; -import docking.DialogComponentProvider; import docking.DockingWindowManager; +import docking.ReusableDialogComponentProvider; import docking.widgets.EmptyBorderButton; import docking.widgets.label.GDLabel; import generic.theme.GThemeDefaults.Colors.Messages; @@ -37,7 +37,7 @@ import resources.Icons; * A dialog that controls the panels for going to "Next" and "Previous" in some * process that the user is being led through. */ -public class WizardManager extends DialogComponentProvider implements WizardPanelListener { +public class WizardManager extends ReusableDialogComponentProvider implements WizardPanelListener { /**Default text for the 'finish' button*/ public static final String FINISH = "Finish"; /**Default text for the 'next' button*/ @@ -75,7 +75,7 @@ public class WizardManager extends DialogComponentProvider implements WizardPane * @param wizardIcon icon to use for this dialog */ public WizardManager(String title, boolean modal, PanelManager pmgr, Icon wizardIcon) { - super(title, modal); + super(title, modal, true, true, false); init(pmgr, wizardIcon); } diff --git a/Ghidra/Framework/Docking/src/test.slow/java/docking/widgets/filechooser/GhidraFileChooserTest.java b/Ghidra/Framework/Docking/src/test.slow/java/docking/widgets/filechooser/GhidraFileChooserTest.java index 8f9b036e65..8294ab6e4a 100644 --- a/Ghidra/Framework/Docking/src/test.slow/java/docking/widgets/filechooser/GhidraFileChooserTest.java +++ b/Ghidra/Framework/Docking/src/test.slow/java/docking/widgets/filechooser/GhidraFileChooserTest.java @@ -19,11 +19,14 @@ package docking.widgets.filechooser; import static docking.widgets.filechooser.GhidraFileChooserMode.*; -import static org.hamcrest.Matchers.empty; -import static org.hamcrest.Matchers.is; -import static org.hamcrest.text.IsEmptyString.isEmptyOrNullString; +import static org.hamcrest.Matchers.*; import static org.junit.Assert.*; +import java.awt.*; +import java.awt.event.FocusListener; +import java.awt.event.MouseEvent; +import java.io.*; +import java.nio.file.*; import java.util.ArrayList; import java.util.Arrays; import java.util.List; @@ -32,12 +35,6 @@ import java.util.concurrent.CompletableFuture; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicReference; -import java.awt.*; -import java.awt.event.FocusListener; -import java.awt.event.MouseEvent; -import java.io.*; -import java.nio.file.*; - import javax.swing.*; import javax.swing.table.JTableHeader; @@ -1917,7 +1914,7 @@ public class GhidraFileChooserTest extends AbstractDockingTest { waitForChooser(); filenameFieldText = getFilenameFieldText(); assertThat("Filename text field not cleared upon multi-file selection", filenameFieldText, - isEmptyOrNullString()); + is(emptyOrNullString())); // // Clear the multi-selection; a single file selection will set the text field text @@ -1929,10 +1926,78 @@ public class GhidraFileChooserTest extends AbstractDockingTest { filenameFieldText); } + @Test + public void testLastDirectoryPreference() throws Exception { + + // remove the default test chooser + close(); + String key = "SomePreferenceKey"; + clearPreference(key); + + runSwing(() -> { + chooser = new GhidraFileChooser(null); + chooser.setLastDirectoryPreference(key); + chooser.setMultiSelectionEnabled(true); + chooser.setLastDirectoryPreference(key); + }); + + runSwing(() -> { + lastSelectedFile = chooser.getSelectedFile(true); + }, false); + + File startDir = createTempDir(); + setDir(startDir); + String nonExistentFilename = getClass().getName() + ".foo.bar.baz.test"; + setFilenameFieldText(nonExistentFilename); + pressOk(); + + waitForChooser(); + + File selectedFile = getSelectedFile(); + assertEquals(nonExistentFilename, selectedFile.getName()); + + assertChooserPreference(key, selectedFile.getParentFile()); + } + + @Test + public void testLastDirectoryPreference_Cancel() throws Exception { + + // remove the default test chooser + close(); + String key = "SomePreferenceKey"; + clearPreference(key); + + runSwing(() -> { + chooser = new GhidraFileChooser(null); + chooser.setLastDirectoryPreference(key); + chooser.setMultiSelectionEnabled(true); + chooser.setLastDirectoryPreference(key); + chooser.show(); + }, false); + waitForChooser(); + + pressCancel(); + assertChooserPreference(key, null); + } + //================================================================================================== // Private Methods //================================================================================================== + private void clearPreference(String key) { + Preferences.setProperty(key, ""); + } + + private void assertChooserPreference(String key, File dir) { + String value = Preferences.getProperty(key); + if (dir == null) { + assertEquals("", value); + } + else { + assertEquals(dir.getPath(), value); + } + } + private List getExistingFiles(File dir, int count) { assertTrue(dir.isDirectory()); diff --git a/Ghidra/Framework/FileSystem/src/main/java/ghidra/framework/client/DefaultClientAuthenticator.java b/Ghidra/Framework/FileSystem/src/main/java/ghidra/framework/client/DefaultClientAuthenticator.java index 3e8e1d29d0..79b96b84a9 100644 --- a/Ghidra/Framework/FileSystem/src/main/java/ghidra/framework/client/DefaultClientAuthenticator.java +++ b/Ghidra/Framework/FileSystem/src/main/java/ghidra/framework/client/DefaultClientAuthenticator.java @@ -153,16 +153,17 @@ public class DefaultClientAuthenticator extends PopupKeyStorePasswordProvider @Override public void run() { - PasswordDialog pwdDialog; + String choicePrompt = null; String[] choices = null; if (choiceCb != null) { choicePrompt = choiceCb.getPrompt(); choices = choiceCb.getChoices(); } - pwdDialog = new PasswordDialog(title, serverType, serverName, passCb.getPrompt(), - nameCb != null ? nameCb.getPrompt() : null, getDefaultUserName(), choicePrompt, - choices, getDefaultChoice(), anonymousCb != null); + PasswordDialog pwdDialog = + new PasswordDialog(title, serverType, serverName, passCb.getPrompt(), + nameCb != null ? nameCb.getPrompt() : null, getDefaultUserName(), choicePrompt, + choices, getDefaultChoice(), anonymousCb != null); if (errorMsg != null) { pwdDialog.setErrorText(errorMsg); } diff --git a/Ghidra/Framework/Generic/src/main/java/ghidra/framework/preferences/Preferences.java b/Ghidra/Framework/Generic/src/main/java/ghidra/framework/preferences/Preferences.java index 92458491e0..d00698c7e7 100644 --- a/Ghidra/Framework/Generic/src/main/java/ghidra/framework/preferences/Preferences.java +++ b/Ghidra/Framework/Generic/src/main/java/ghidra/framework/preferences/Preferences.java @@ -65,10 +65,15 @@ public class Preferences { public final static String LAST_NEW_PROJECT_DIRECTORY = "LastNewProjectDirectory"; /** - * Preference name for the import directory that was last accessed for - * domain files. + * Preference name for the last chosen directory for path related items. */ - public final static String LAST_IMPORT_DIRECTORY = "LastImportDirectory"; + public final static String LAST_PATH_DIRECTORY = "LastPathDirectory"; + + /** + * Preference name for the import directory that was last accessed for domain files. + */ + public final static String LAST_IMPORT_FILE = "LastImportFile"; + /** * Preference name for the export directory that was last accessed. */ diff --git a/Ghidra/Framework/Project/src/main/java/ghidra/app/plugin/debug/MemoryUsagePlugin.java b/Ghidra/Framework/Project/src/main/java/ghidra/app/plugin/debug/MemoryUsagePlugin.java index 8e50566fef..b60b230965 100644 --- a/Ghidra/Framework/Project/src/main/java/ghidra/app/plugin/debug/MemoryUsagePlugin.java +++ b/Ghidra/Framework/Project/src/main/java/ghidra/app/plugin/debug/MemoryUsagePlugin.java @@ -45,6 +45,15 @@ public class MemoryUsagePlugin extends Plugin implements ApplicationLevelOnlyPlu setupActions(); } + @Override + protected void dispose() { + super.dispose(); + + if (dialog != null) { + dialog.dispose(); + } + } + private void setupActions() { DockingAction action; diff --git a/Ghidra/Framework/Project/src/main/java/ghidra/app/plugin/debug/ShowMemoryDialog.java b/Ghidra/Framework/Project/src/main/java/ghidra/app/plugin/debug/ShowMemoryDialog.java index 5c5afa1140..8d48f7c2bd 100644 --- a/Ghidra/Framework/Project/src/main/java/ghidra/app/plugin/debug/ShowMemoryDialog.java +++ b/Ghidra/Framework/Project/src/main/java/ghidra/app/plugin/debug/ShowMemoryDialog.java @@ -15,18 +15,16 @@ */ package ghidra.app.plugin.debug; -import java.awt.event.ActionEvent; -import java.awt.event.ActionListener; import java.text.DecimalFormat; import javax.swing.*; -import docking.DialogComponentProvider; +import docking.ReusableDialogComponentProvider; import docking.widgets.label.GDLabel; import docking.widgets.label.GLabel; import ghidra.util.layout.PairLayout; -class ShowMemoryDialog extends DialogComponentProvider { +class ShowMemoryDialog extends ReusableDialogComponentProvider { private MemoryUsagePlugin plugin; private JLabel maxMem; private JLabel totalMem; @@ -42,16 +40,13 @@ class ShowMemoryDialog extends DialogComponentProvider { addWorkPanel(createWorkPanel()); plugin.getTool().showDialog(this); final DecimalFormat df = new DecimalFormat(); - timer = new Timer(2000, new ActionListener() { - @Override - public void actionPerformed(ActionEvent e) { - Runtime runtime = Runtime.getRuntime(); - maxMem.setText(df.format(runtime.maxMemory() / 1000) + "K"); - totalMem.setText(df.format(runtime.totalMemory() / 1000) + "K"); - freeMem.setText(df.format(runtime.freeMemory() / 1000) + "K"); - usedMem.setText( - df.format((runtime.totalMemory() - runtime.freeMemory()) / 1000) + "K"); - } + timer = new Timer(2000, e -> { + Runtime runtime = Runtime.getRuntime(); + maxMem.setText(df.format(runtime.maxMemory() / 1000) + "K"); + totalMem.setText(df.format(runtime.totalMemory() / 1000) + "K"); + freeMem.setText(df.format(runtime.freeMemory() / 1000) + "K"); + usedMem.setText( + df.format((runtime.totalMemory() - runtime.freeMemory()) / 1000) + "K"); }); timer.start(); } diff --git a/Ghidra/Framework/Project/src/main/java/ghidra/framework/main/EditActionManager.java b/Ghidra/Framework/Project/src/main/java/ghidra/framework/main/EditActionManager.java index 0ad0d08dbe..b63efcd412 100644 --- a/Ghidra/Framework/Project/src/main/java/ghidra/framework/main/EditActionManager.java +++ b/Ghidra/Framework/Project/src/main/java/ghidra/framework/main/EditActionManager.java @@ -23,6 +23,7 @@ import docking.action.MenuData; import docking.tool.ToolConstants; import docking.widgets.OptionDialog; import docking.widgets.filechooser.GhidraFileChooser; +import docking.widgets.filechooser.GhidraFileChooserMode; import ghidra.net.ApplicationKeyManagerFactory; import ghidra.net.ApplicationKeyManagerUtils; import ghidra.util.HelpLocation; @@ -44,8 +45,6 @@ class EditActionManager { private DockingAction editPluginPathAction; private DockingAction editCertPathAction; private DockingAction clearCertPathAction; - private EditPluginPathDialog pluginPathDialog; - private GhidraFileChooser certFileChooser; EditActionManager(FrontEndPlugin plugin) { this.plugin = plugin; @@ -107,9 +106,7 @@ class EditActionManager { * Pop up the edit plugin path dialog. */ private void editPluginPath() { - if (pluginPathDialog == null) { - pluginPathDialog = new EditPluginPathDialog(); - } + EditPluginPathDialog pluginPathDialog = new EditPluginPathDialog(); pluginPathDialog.show(tool); } @@ -132,9 +129,8 @@ class EditActionManager { } private void editCertPath() { - if (certFileChooser == null) { - certFileChooser = createCertFileChooser(); - } + + GhidraFileChooser certFileChooser = createCertFileChooser(); File dir = null; File oldFile = null; @@ -171,6 +167,8 @@ class EditActionManager { clearCertPathAction.setEnabled(true); validInput = true; } + + certFileChooser.dispose(); } private GhidraFileChooser createCertFileChooser() { @@ -179,7 +177,7 @@ class EditActionManager { fileChooser.setTitle("Select Certificate (req'd for PKI authentication only)"); fileChooser.setApproveButtonText("Set Certificate"); fileChooser.setFileFilter(CERTIFICATE_FILE_FILTER); - fileChooser.setFileSelectionMode(GhidraFileChooser.FILES_ONLY); + fileChooser.setFileSelectionMode(GhidraFileChooserMode.FILES_ONLY); fileChooser.setHelpLocation(new HelpLocation(plugin.getName(), "Set_PKI_Certificate")); return fileChooser; } diff --git a/Ghidra/Framework/Project/src/main/java/ghidra/framework/main/EditPluginPathDialog.java b/Ghidra/Framework/Project/src/main/java/ghidra/framework/main/EditPluginPathDialog.java index b0ddff2323..b175ce06c1 100644 --- a/Ghidra/Framework/Project/src/main/java/ghidra/framework/main/EditPluginPathDialog.java +++ b/Ghidra/Framework/Project/src/main/java/ghidra/framework/main/EditPluginPathDialog.java @@ -80,7 +80,7 @@ class EditPluginPathDialog extends DialogComponentProvider { // gui members needed for dis/enabling and other state-dependent actions private JScrollPane scrollPane; // need for preferred size when resizing private JList pluginPathsList; - private GhidraFileChooser fileChooser; + private JButton upButton; private JButton downButton; private JButton removeButton; @@ -199,15 +199,15 @@ class EditPluginPathDialog extends DialogComponentProvider { setStatusMessage(EditPluginPathDialog.EMPTY_STATUS); - if (fileChooser == null) { - fileChooser = new GhidraFileChooser(getComponent()); - fileChooser.setCurrentDirectory(new File(System.getProperty("user.home"))); - } + GhidraFileChooser fileChooser = new GhidraFileChooser(getComponent()); + fileChooser.setCurrentDirectory(new File(System.getProperty("user.home"))); fileChooser.setFileSelectionMode(GhidraFileChooserMode.FILES_ONLY); fileChooser.setFileFilter(JAR_FILTER); fileChooser.setApproveButtonToolTipText("Choose Plugin Jar File"); fileChooser.setApproveButtonText("Add Jar File"); + fileChooser.setLastDirectoryPreference(Preferences.LAST_PATH_DIRECTORY); + File dir = fileChooser.getSelectedFile(); if (dir != null) { try { @@ -225,16 +225,16 @@ class EditPluginPathDialog extends DialogComponentProvider { setStatusMessage(e.getMessage()); } } + + fileChooser.dispose(); } private void addDirCallback() { setStatusMessage(EditPluginPathDialog.EMPTY_STATUS); - if (fileChooser == null) { - fileChooser = new GhidraFileChooser(getComponent()); - fileChooser.setCurrentDirectory(new File(System.getProperty("user.home"))); - } + GhidraFileChooser fileChooser = new GhidraFileChooser(getComponent()); + fileChooser.setCurrentDirectory(new File(System.getProperty("user.home"))); fileChooser.setFileSelectionMode(GhidraFileChooserMode.DIRECTORIES_ONLY); fileChooser.setFileFilter(GhidraFileFilter.ALL); fileChooser.setApproveButtonToolTipText("Choose Directory with Plugin class Files"); @@ -258,6 +258,7 @@ class EditPluginPathDialog extends DialogComponentProvider { Msg.error(this, "Unexpected Exception: " + e.getMessage(), e); } } + fileChooser.dispose(); } private String[] getUserPluginPaths() { 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 97f3b40eb4..0bfc016c29 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 @@ -65,7 +65,6 @@ class FileActionManager { private DockingAction saveAction; private List reopenList; - private GhidraFileChooser fileChooser; private boolean firingProjectOpened; @@ -238,19 +237,16 @@ class FileActionManager { if (activeProject != null) { currentProjectLocator = activeProject.getProjectLocator(); } - if (fileChooser == null) { - fileChooser = plugin.createFileChooser(LAST_SELECTED_PROJECT_DIRECTORY); - } + GhidraFileChooser fileChooser = plugin.createFileChooser(LAST_SELECTED_PROJECT_DIRECTORY); ProjectLocator projectLocator = plugin.chooseProject(fileChooser, "Open", LAST_SELECTED_PROJECT_DIRECTORY); if (projectLocator != null) { - if (!doOpenProject(projectLocator) && currentProjectLocator != null) { doOpenProject(currentProjectLocator); } - } + fileChooser.dispose(); } private class OpenTaskRunnable implements Runnable { @@ -579,11 +575,11 @@ class FileActionManager { * menu listener for File | Delete Project... */ private void deleteProject() { - if (fileChooser == null) { - fileChooser = plugin.createFileChooser(LAST_SELECTED_PROJECT_DIRECTORY); - } + + GhidraFileChooser fileChooser = plugin.createFileChooser(LAST_SELECTED_PROJECT_DIRECTORY); ProjectLocator projectLocator = plugin.chooseProject(fileChooser, "Delete", LAST_SELECTED_PROJECT_DIRECTORY); + fileChooser.dispose(); if (projectLocator == null) { return; // user canceled } @@ -603,7 +599,7 @@ class FileActionManager { confirmMsg.append(" ?\n"); boolean isActiveProject = (activeProject != null && activeProject.getProjectLocator().equals(projectLocator)); - // also give special warning if we open this project as read-only voew + // also give special warning if we open this project as read-only view boolean isOpenProjectView = isOpenProjectView(projectLocator); if (!allowDelete(isActiveProject ? activeProject : null)) { 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 a7c2b24637..0912d2a0c7 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 @@ -820,6 +820,7 @@ public class FrontEndPlugin extends Plugin protected void dispose() { dataTablePanel.dispose(); dataTreePanel.dispose(); + projectActionManager.dispose(); } private void buildPanels() { 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 272341dfc1..49a8eed17f 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 @@ -161,6 +161,15 @@ public class FrontEndTool extends PluginTool implements OptionsChangeListener { initFrontEndOptions(); } + @Override + protected void dispose() { + super.dispose(); + + if (logProvider != null) { + logProvider.dispose(); + } + } + private void ensureSize() { JFrame frame = getToolFrame(); Dimension size = frame.getSize(); @@ -607,8 +616,6 @@ public class FrontEndTool extends PluginTool implements OptionsChangeListener { @Override public void actionPerformed(ActionContext context) { showExtensions(); - extensionTableProvider.setHelpLocation( - new HelpLocation(GenericHelpTopics.FRONT_END, "Extensions")); } @Override @@ -834,7 +841,7 @@ public class FrontEndTool extends PluginTool implements OptionsChangeListener { // Inner Classes //================================================================================================== - private static class LogComponentProvider extends DialogComponentProvider { + private static class LogComponentProvider extends ReusableDialogComponentProvider { private final File logFile; private Dimension defaultSize = new Dimension(600, 400); diff --git a/Ghidra/Framework/Project/src/main/java/ghidra/framework/main/ProjectActionManager.java b/Ghidra/Framework/Project/src/main/java/ghidra/framework/main/ProjectActionManager.java index 6ece295885..05d1362656 100644 --- a/Ghidra/Framework/Project/src/main/java/ghidra/framework/main/ProjectActionManager.java +++ b/Ghidra/Framework/Project/src/main/java/ghidra/framework/main/ProjectActionManager.java @@ -46,7 +46,6 @@ class ProjectActionManager { private List openViewsList; private List reopenViewsList; private Project activeProject; - private GhidraFileChooser fileChooser; private RepositoryChooser repositoryChooser; private DockingAction openProjectViewAction; @@ -73,6 +72,15 @@ class ProjectActionManager { createSwitchWorkspaceAction(); } + void dispose() { + if (infoDialog != null) { + infoDialog.dispose(); + } + if (repositoryChooser != null) { + repositoryChooser.dispose(); + } + } + private void openRecentView(String urlPath) { URL url = GhidraURL.toURL(urlPath); openView(url); @@ -508,14 +516,14 @@ class ProjectActionManager { * menu listener for Project | Add View... */ private void openProjectView() { - if (fileChooser == null) { - fileChooser = plugin.createFileChooser(LAST_VIEWED_PROJECT_DIRECTORY); - } + + GhidraFileChooser fileChooser = plugin.createFileChooser(LAST_VIEWED_PROJECT_DIRECTORY); ProjectLocator projectView = plugin.chooseProject(fileChooser, "Select", LAST_VIEWED_PROJECT_DIRECTORY); if (projectView != null) { openView(projectView.getURL()); } + fileChooser.dispose(); } private void openRepositoryView() { @@ -619,8 +627,9 @@ class ProjectActionManager { tool.showDialog(dlg); pwd = dlg.getPassword(); if (pwd != null) { - repository.getServer().setPassword( - HashUtilities.getSaltedHash(HashUtilities.SHA256_ALGORITHM, pwd)); + repository.getServer() + .setPassword( + HashUtilities.getSaltedHash(HashUtilities.SHA256_ALGORITHM, pwd)); Msg.showInfo(getClass(), tool.getToolFrame(), "Password Changed", "Password was changed successfully"); } diff --git a/Ghidra/Framework/Project/src/main/java/ghidra/framework/main/RepositoryChooser.java b/Ghidra/Framework/Project/src/main/java/ghidra/framework/main/RepositoryChooser.java index b0a6156ef9..086a1299e6 100644 --- a/Ghidra/Framework/Project/src/main/java/ghidra/framework/main/RepositoryChooser.java +++ b/Ghidra/Framework/Project/src/main/java/ghidra/framework/main/RepositoryChooser.java @@ -26,7 +26,7 @@ import javax.swing.*; import javax.swing.event.ChangeListener; import javax.swing.event.MouseInputAdapter; -import docking.DialogComponentProvider; +import docking.ReusableDialogComponentProvider; import docking.widgets.button.GButton; import docking.widgets.button.GRadioButton; import docking.widgets.label.GDLabel; @@ -42,7 +42,7 @@ import ghidra.util.layout.MiddleLayout; import ghidra.util.layout.PairLayout; import resources.Icons; -class RepositoryChooser extends DialogComponentProvider { +class RepositoryChooser extends ReusableDialogComponentProvider { static final Icon REFRESH_ICON = Icons.REFRESH_ICON; diff --git a/Ghidra/Framework/Project/src/main/java/ghidra/framework/main/SelectProjectPanel.java b/Ghidra/Framework/Project/src/main/java/ghidra/framework/main/SelectProjectPanel.java index ff9c4df2f9..616d0ad5f9 100644 --- a/Ghidra/Framework/Project/src/main/java/ghidra/framework/main/SelectProjectPanel.java +++ b/Ghidra/Framework/Project/src/main/java/ghidra/framework/main/SelectProjectPanel.java @@ -16,8 +16,6 @@ package ghidra.framework.main; import java.awt.*; -import java.awt.event.ActionEvent; -import java.awt.event.ActionListener; import java.io.File; import javax.swing.*; @@ -55,7 +53,6 @@ class SelectProjectPanel extends AbstractWizardJPanel { private JTextField projectNameField; private JTextField directoryField; private JButton browseButton; - private GhidraFileChooser fileChooser; private ProjectLocator projectLocator; private NewProjectPanelManager panelManager; private DocumentListener docListener; @@ -152,12 +149,7 @@ class SelectProjectPanel extends AbstractWizardJPanel { JLabel projectNameLabel = new GDLabel("Project Name:", SwingConstants.RIGHT); projectNameField = new JTextField(25); projectNameField.setName("Project Name"); - projectNameField.addActionListener(new ActionListener() { - @Override - public void actionPerformed(ActionEvent e) { - setProjectFile(); - } - }); + projectNameField.addActionListener(e -> setProjectFile()); docListener = new DocumentListener() { @Override @@ -179,12 +171,7 @@ class SelectProjectPanel extends AbstractWizardJPanel { directoryField.getDocument().addDocumentListener(docListener); browseButton = new BrowseButton(); - browseButton.addActionListener(new ActionListener() { - @Override - public void actionPerformed(ActionEvent e) { - displayFileChooser(); - } - }); + browseButton.addActionListener(e -> displayFileChooser()); // sharedProjectCB = new GCheckBox("Project can be Shared with Others"); // sharedProjectCB.addItemListener(new ItemListener() { @@ -305,9 +292,7 @@ class SelectProjectPanel extends AbstractWizardJPanel { } private void displayFileChooser() { - if (fileChooser == null) { - createFileChooser(); - } + GhidraFileChooser fileChooser = createFileChooser(); fileChooser.setTitle("Select a Ghidra Project Directory"); fileChooser.setApproveButtonText("Select Project Directory"); fileChooser.setApproveButtonToolTipText("Select a Ghidra Project Directory"); @@ -323,6 +308,8 @@ class SelectProjectPanel extends AbstractWizardJPanel { checkProjectFile(true); } + + fileChooser.dispose(); } private String getProjectName(String name) { @@ -332,10 +319,10 @@ class SelectProjectPanel extends AbstractWizardJPanel { return name; } - private void createFileChooser() { + private GhidraFileChooser createFileChooser() { WizardManager wm = panelManager.getWizardManager(); - fileChooser = new GhidraFileChooser(wm.getComponent()); + GhidraFileChooser fileChooser = new GhidraFileChooser(wm.getComponent()); File projectDirectory = new File(GenericRunInfo.getProjectsDirPath()); String lastDirSelected = Preferences.getProperty(Preferences.LAST_NEW_PROJECT_DIRECTORY, null, true); @@ -356,5 +343,6 @@ class SelectProjectPanel extends AbstractWizardJPanel { } }); fileChooser.setCurrentDirectory(projectDirectory);//start the browsing in the user's preferred project directory + return fileChooser; } } diff --git a/Ghidra/Framework/Project/src/main/java/ghidra/framework/main/ToolActionManager.java b/Ghidra/Framework/Project/src/main/java/ghidra/framework/main/ToolActionManager.java index d7d66ceeab..6de6bfedbc 100644 --- a/Ghidra/Framework/Project/src/main/java/ghidra/framework/main/ToolActionManager.java +++ b/Ghidra/Framework/Project/src/main/java/ghidra/framework/main/ToolActionManager.java @@ -66,8 +66,6 @@ class ToolActionManager implements ToolChestChangeListener { private Map delToolActionMap; private Map exportToolActionMap; - private GhidraFileChooser fileChooser; - ToolActionManager(FrontEndPlugin fePlugin) { plugin = fePlugin; tool = (FrontEndTool) plugin.getTool(); @@ -211,8 +209,7 @@ class ToolActionManager implements ToolChestChangeListener { } List list = dialog.getSelectedList(); - for (int i = 0; i < list.size(); i++) { - String filename = list.get(i); + for (String filename : list) { addDefaultTool(filename); } } @@ -319,7 +316,7 @@ class ToolActionManager implements ToolChestChangeListener { Workspace ws = plugin.getActiveWorkspace(); // create the running tool - PluginTool runningTool = (PluginTool) ws.createTool(); + PluginTool runningTool = ws.createTool(); // whenever we create a new tool, the first thing the // user will want to do is configure it, so automatically @@ -417,22 +414,22 @@ class ToolActionManager implements ToolChestChangeListener { * tool. */ private void importTool() { - if (fileChooser == null) { - fileChooser = new GhidraFileChooser(tool.getToolFrame()); - fileChooser.setFileFilter( - new ExtensionFileFilter(new String[] { "tool", "tcd" }, "Tools")); - fileChooser.setTitle("Import Tool"); - fileChooser.setApproveButtonText("Import"); - String importDir = Preferences.getProperty(Preferences.LAST_TOOL_IMPORT_DIRECTORY); - if (importDir != null) { - fileChooser.setCurrentDirectory(new File(importDir)); - } + GhidraFileChooser fileChooser = new GhidraFileChooser(tool.getToolFrame()); + fileChooser.setFileFilter( + new ExtensionFileFilter(new String[] { "tool", "tcd" }, "Tools")); + fileChooser.setTitle("Import Tool"); + fileChooser.setApproveButtonText("Import"); + + String importDir = Preferences.getProperty(Preferences.LAST_TOOL_IMPORT_DIRECTORY); + if (importDir != null) { + fileChooser.setCurrentDirectory(new File(importDir)); } fileChooser.rescanCurrentDirectory(); File selectedFile = fileChooser.getSelectedFile(true); + fileChooser.dispose(); if (selectedFile == null) { return; } diff --git a/Ghidra/Framework/Project/src/main/java/ghidra/framework/main/ToolConnectionDialog.java b/Ghidra/Framework/Project/src/main/java/ghidra/framework/main/ToolConnectionDialog.java index 202e6f0c7e..1e51951b86 100644 --- a/Ghidra/Framework/Project/src/main/java/ghidra/framework/main/ToolConnectionDialog.java +++ b/Ghidra/Framework/Project/src/main/java/ghidra/framework/main/ToolConnectionDialog.java @@ -20,7 +20,7 @@ import java.beans.PropertyChangeEvent; import javax.swing.JButton; import javax.swing.JPanel; -import docking.DialogComponentProvider; +import docking.ReusableDialogComponentProvider; import ghidra.app.util.GenericHelpTopics; import ghidra.framework.model.*; import ghidra.framework.plugintool.PluginTool; @@ -30,7 +30,8 @@ import ghidra.util.HelpLocation; * Dialog to show existing connections between tools and * to connect tools. */ -class ToolConnectionDialog extends DialogComponentProvider implements WorkspaceChangeListener { +class ToolConnectionDialog extends ReusableDialogComponentProvider + implements WorkspaceChangeListener { private ToolManager toolManager; private ToolConnectionPanel panel; @@ -41,7 +42,7 @@ class ToolConnectionDialog extends DialogComponentProvider implements WorkspaceC private JButton disconnectAllButton; ToolConnectionDialog(FrontEndTool tool, ToolManager toolManager) { - super("Connect Tools", false); + super("Connect Tools", false, true, true, false); this.frontEndTool = tool; this.toolManager = toolManager; setHelpLocation(new HelpLocation(GenericHelpTopics.FRONT_END, "Connect_Tools")); 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 e77753c89d..e6f26ec0f6 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 @@ -113,7 +113,6 @@ public abstract class PluginTool extends AbstractDockingTool { private OptionsChangeListener optionsListener = new ToolOptionsListener(); protected ManagePluginsDialog manageDialog; - protected ExtensionTableProvider extensionTableProvider; protected ToolIconURL iconURL = new ToolIconURL("view_detailed.png"); @@ -336,11 +335,7 @@ public abstract class PluginTool extends AbstractDockingTool { * Displays the extensions installation dialog. */ public void showExtensions() { - if (extensionTableProvider != null) { - extensionTableProvider.close(); - } - extensionTableProvider = new ExtensionTableProvider(this); - showDialog(extensionTableProvider); + showDialog(new ExtensionTableProvider(this)); } /** diff --git a/Ghidra/Framework/Project/src/main/java/ghidra/framework/plugintool/dialog/ExtensionTableProvider.java b/Ghidra/Framework/Project/src/main/java/ghidra/framework/plugintool/dialog/ExtensionTableProvider.java index 1c051f07d4..685a94f79f 100644 --- a/Ghidra/Framework/Project/src/main/java/ghidra/framework/plugintool/dialog/ExtensionTableProvider.java +++ b/Ghidra/Framework/Project/src/main/java/ghidra/framework/plugintool/dialog/ExtensionTableProvider.java @@ -55,6 +55,7 @@ public class ExtensionTableProvider extends DialogComponentProvider { public ExtensionTableProvider(PluginTool tool) { super("Install Extensions"); addWorkPanel(createMainPanel(tool)); + setHelpLocation(new HelpLocation(GenericHelpTopics.FRONT_END, "Extensions")); } /** @@ -141,6 +142,7 @@ public class ExtensionTableProvider extends DialogComponentProvider { chooser.addFileFilter(new ExtensionFileFilter()); List files = chooser.getSelectedFiles(); + chooser.dispose(); for (File file : files) { try { if (!ExtensionUtils.isExtension(new ResourceFile(file))) { diff --git a/Ghidra/Framework/Project/src/main/java/ghidra/framework/plugintool/dialog/ManagePluginsDialog.java b/Ghidra/Framework/Project/src/main/java/ghidra/framework/plugintool/dialog/ManagePluginsDialog.java index 95d3cca9c8..bf28134df4 100644 --- a/Ghidra/Framework/Project/src/main/java/ghidra/framework/plugintool/dialog/ManagePluginsDialog.java +++ b/Ghidra/Framework/Project/src/main/java/ghidra/framework/plugintool/dialog/ManagePluginsDialog.java @@ -20,7 +20,7 @@ import java.awt.Point; import javax.swing.*; import docking.ActionContext; -import docking.DialogComponentProvider; +import docking.ReusableDialogComponentProvider; import docking.action.*; import docking.tool.ToolConstants; import docking.widgets.OptionDialog; @@ -34,7 +34,7 @@ import ghidra.framework.plugintool.util.PluginPackage; import ghidra.util.HelpLocation; import resources.Icons; -public class ManagePluginsDialog extends DialogComponentProvider { +public class ManagePluginsDialog extends ReusableDialogComponentProvider { private PluginTool tool; private boolean isNewTool; diff --git a/Ghidra/Framework/Project/src/main/java/ghidra/framework/plugintool/dialog/SaveToolConfigDialog.java b/Ghidra/Framework/Project/src/main/java/ghidra/framework/plugintool/dialog/SaveToolConfigDialog.java index 234b3aae04..b572f94bf7 100644 --- a/Ghidra/Framework/Project/src/main/java/ghidra/framework/plugintool/dialog/SaveToolConfigDialog.java +++ b/Ghidra/Framework/Project/src/main/java/ghidra/framework/plugintool/dialog/SaveToolConfigDialog.java @@ -16,7 +16,8 @@ package ghidra.framework.plugintool.dialog; import java.awt.*; -import java.awt.event.*; +import java.awt.event.KeyAdapter; +import java.awt.event.KeyEvent; import java.io.File; import java.util.List; @@ -30,6 +31,7 @@ import docking.util.image.ToolIconURL; import docking.widgets.OptionDialog; import docking.widgets.button.BrowseButton; import docking.widgets.filechooser.GhidraFileChooser; +import docking.widgets.filechooser.GhidraFileChooserMode; import docking.widgets.label.GLabel; import ghidra.framework.model.*; import ghidra.framework.plugintool.PluginTool; @@ -75,12 +77,7 @@ public class SaveToolConfigDialog extends DialogComponentProvider implements Lis addWorkPanel(buildMainPanel()); saveButton = new JButton("Save"); - saveButton.addActionListener(new ActionListener() { - @Override - public void actionPerformed(ActionEvent ev) { - save(); - } - }); + saveButton.addActionListener(ev -> save()); addButton(saveButton); addCancelButton(); @@ -186,12 +183,7 @@ public class SaveToolConfigDialog extends DialogComponentProvider implements Lis private void addListeners() { - nameField.addActionListener(new ActionListener() { - @Override - public void actionPerformed(ActionEvent e) { - save(); - } - }); + nameField.addActionListener(e -> save()); nameField.addKeyListener(new KeyAdapter() { @Override public void keyPressed(KeyEvent e) { @@ -327,16 +319,13 @@ public class SaveToolConfigDialog extends DialogComponentProvider implements Lis */ private void addIconPanelListeners() { - iconField.addActionListener(new ActionListener() { - @Override - public void actionPerformed(ActionEvent e) { - String filename = iconField.getText(); - if (filename.length() == 0) { - setStatusText("Please enter a filename for the icon."); - return; - } - setPicture(new ToolIconURL(filename)); + iconField.addActionListener(e -> { + String filename = iconField.getText(); + if (filename.length() == 0) { + setStatusText("Please enter a filename for the icon."); + return; } + setPicture(new ToolIconURL(filename)); }); iconField.addKeyListener(new KeyAdapter() { @@ -372,12 +361,7 @@ public class SaveToolConfigDialog extends DialogComponentProvider implements Lis }; iconField.getDocument().addDocumentListener(dl); - browseButton.addActionListener(new ActionListener() { - @Override - public void actionPerformed(ActionEvent e) { - browseForIcons(); - } - }); + browseButton.addActionListener(e -> browseForIcons()); } @@ -402,17 +386,18 @@ public class SaveToolConfigDialog extends DialogComponentProvider implements Lis * Pop up a file chooser for the user to look for icon images. */ private void browseForIcons() { - GhidraFileChooser iconFileChooser = new GhidraFileChooser(getComponent()); - iconFileChooser.setFileSelectionMode(GhidraFileChooser.FILES_ONLY); - iconFileChooser.setTitle("Choose Icon"); - iconFileChooser.setApproveButtonToolTipText("Choose Icon"); - iconFileChooser.setFileFilter( + GhidraFileChooser chooser = new GhidraFileChooser(getComponent()); + chooser.setFileSelectionMode(GhidraFileChooserMode.FILES_ONLY); + chooser.setTitle("Choose Icon"); + chooser.setApproveButtonToolTipText("Choose Icon"); + chooser.setFileFilter( new ExtensionFileFilter(new String[] { "gif", "jpg", "bmp", "png" }, "Image Files")); String iconDir = Preferences.getProperty(LAST_ICON_DIRECTORY); if (iconDir != null) { - iconFileChooser.setCurrentDirectory(new File(iconDir)); + chooser.setCurrentDirectory(new File(iconDir)); } - File file = iconFileChooser.getSelectedFile(); + File file = chooser.getSelectedFile(); + chooser.dispose(); if (file == null) { return; } diff --git a/Ghidra/Framework/Project/src/main/java/ghidra/framework/plugintool/mgr/DialogManager.java b/Ghidra/Framework/Project/src/main/java/ghidra/framework/plugintool/mgr/DialogManager.java index 5d74790a92..ebbaeeeea4 100644 --- a/Ghidra/Framework/Project/src/main/java/ghidra/framework/plugintool/mgr/DialogManager.java +++ b/Ghidra/Framework/Project/src/main/java/ghidra/framework/plugintool/mgr/DialogManager.java @@ -28,7 +28,6 @@ import ghidra.util.Msg; */ public class DialogManager { private PluginTool tool; - private SaveToolConfigDialog saveToolDialog; public DialogManager(PluginTool tool) { this.tool = tool; @@ -40,11 +39,9 @@ public class DialogManager { * @return false if the user cancelled */ public boolean saveToolAs() { - if (saveToolDialog == null) { - saveToolDialog = new SaveToolConfigDialog(tool, tool.getToolServices()); - } + SaveToolConfigDialog saveToolDialog = + new SaveToolConfigDialog(tool, tool.getToolServices()); saveToolDialog.show(tool.getName(), tool.getToolName()); - return !saveToolDialog.didCancel(); } diff --git a/Ghidra/Framework/Project/src/main/java/ghidra/framework/plugintool/mgr/OptionsManager.java b/Ghidra/Framework/Project/src/main/java/ghidra/framework/plugintool/mgr/OptionsManager.java index fe83f61979..b813290776 100644 --- a/Ghidra/Framework/Project/src/main/java/ghidra/framework/plugintool/mgr/OptionsManager.java +++ b/Ghidra/Framework/Project/src/main/java/ghidra/framework/plugintool/mgr/OptionsManager.java @@ -223,7 +223,7 @@ public class OptionsManager implements OptionsService, OptionsChangeListener { } private OptionsDialog createOptionsDialog() { - OptionsDialog dialog = null; + if (optionsMap.size() == 0) { return null; } @@ -239,8 +239,9 @@ public class OptionsManager implements OptionsService, OptionsChangeListener { } keyBindingOptions.registerOptionsEditor(new KeyBindingOptionsEditor()); - dialog = new OptionsDialog("Options for " + tool.getName(), "Options", getEditableOptions(), - null, true); + OptionsDialog dialog = + new OptionsDialog("Options for " + tool.getName(), "Options", getEditableOptions(), + null, true); dialog.setSelectedPath(path); dialog.setHelpLocation( new HelpLocation(ToolConstants.TOOL_HELP_TOPIC, "ToolOptions_Dialog")); diff --git a/Ghidra/Framework/Project/src/main/java/ghidra/framework/project/tool/ToolServicesImpl.java b/Ghidra/Framework/Project/src/main/java/ghidra/framework/project/tool/ToolServicesImpl.java index cfebe63aee..77bd5fb2b1 100644 --- a/Ghidra/Framework/Project/src/main/java/ghidra/framework/project/tool/ToolServicesImpl.java +++ b/Ghidra/Framework/Project/src/main/java/ghidra/framework/project/tool/ToolServicesImpl.java @@ -115,7 +115,7 @@ class ToolServicesImpl implements ToolServices { } } } - + fileChooser.dispose(); return exportFile; } @@ -449,11 +449,11 @@ class ToolServicesImpl implements ToolServices { @SuppressWarnings("rawtypes") List instances = ClassSearcher.getInstances(ContentHandler.class); for (ContentHandler contentHandler : instances) { - + if (contentHandler instanceof FolderLinkContentHandler) { continue; // ignore folder link handler } - + // a bit of validation String contentType = contentHandler.getContentType(); if (contentType == null) { @@ -461,7 +461,7 @@ class ToolServicesImpl implements ToolServices { contentHandler.getClass().getName() + " does not specify a content type"); continue; } - + String toolName = contentHandler.getDefaultToolName(); if (toolName == null) { Msg.error(DomainObjectAdapter.class, "ContentHandler " + diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/app/plugin/processors/sleigh/SpecExtensionPanel.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/app/plugin/processors/sleigh/SpecExtensionPanel.java index 0842ec309e..03acf9b74e 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/app/plugin/processors/sleigh/SpecExtensionPanel.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/app/plugin/processors/sleigh/SpecExtensionPanel.java @@ -434,7 +434,7 @@ public class SpecExtensionPanel extends JPanel { // return them to that spot if they use the dialog again. Preferences.setProperty(LAST_EXPORT_DIRECTORY, fileChooser.getCurrentDirectory().getAbsolutePath()); - + fileChooser.dispose(); return selectedFile; } diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/DataTypeArchiveTransformerPanel.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/DataTypeArchiveTransformerPanel.java index 79763853ef..3d27079373 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/DataTypeArchiveTransformerPanel.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/DataTypeArchiveTransformerPanel.java @@ -16,8 +16,6 @@ package ghidra.program.database.data; import java.awt.*; -import java.awt.event.ActionEvent; -import java.awt.event.ActionListener; import java.io.File; import java.io.IOException; @@ -34,12 +32,9 @@ import ghidra.util.task.TaskMonitor; public class DataTypeArchiveTransformerPanel extends JPanel { - private final static String DOT_DOT_DOT = ". . ."; private final static Cursor WAIT_CURSOR = new Cursor(Cursor.WAIT_CURSOR); private final static Cursor NORM_CURSOR = new Cursor(Cursor.DEFAULT_CURSOR); - private GhidraFileChooser chooser; - private JPanel filePanel; private JTextField oldFileTextField; private JTextField newFileTextField; @@ -87,15 +82,12 @@ public class DataTypeArchiveTransformerPanel extends JPanel { gbc.gridx = 2; gbc.gridwidth = 1; JButton oldBrowseButton = new BrowseButton(); - oldBrowseButton.addActionListener(new ActionListener() { - @Override - public void actionPerformed(ActionEvent e) { - setCursor(WAIT_CURSOR); - File file = chooseFile("Choose old data type archive"); - setCursor(NORM_CURSOR); - if (file != null) { - oldFileTextField.setText(file.getAbsolutePath()); - } + oldBrowseButton.addActionListener(e -> { + setCursor(WAIT_CURSOR); + File file = chooseFile("Choose old data type archive"); + setCursor(NORM_CURSOR); + if (file != null) { + oldFileTextField.setText(file.getAbsolutePath()); } }); filePanel.add(oldBrowseButton, gbc); @@ -124,15 +116,12 @@ public class DataTypeArchiveTransformerPanel extends JPanel { gbc.gridx = 2; gbc.gridwidth = 1; JButton newBrowseButton = new BrowseButton(); - newBrowseButton.addActionListener(new ActionListener() { - @Override - public void actionPerformed(ActionEvent e) { - setCursor(WAIT_CURSOR); - File file = chooseFile("Choose new data type archive"); - setCursor(NORM_CURSOR); - if (file != null) { - newFileTextField.setText(file.getAbsolutePath()); - } + newBrowseButton.addActionListener(e -> { + setCursor(WAIT_CURSOR); + File file = chooseFile("Choose new data type archive"); + setCursor(NORM_CURSOR); + if (file != null) { + newFileTextField.setText(file.getAbsolutePath()); } }); filePanel.add(newBrowseButton, gbc); @@ -156,31 +145,27 @@ public class DataTypeArchiveTransformerPanel extends JPanel { gbc.gridwidth = 1; JButton destinationBrowseButton = new BrowseButton(); - destinationBrowseButton.addActionListener(new ActionListener() { - @Override - public void actionPerformed(ActionEvent e) { - setCursor(WAIT_CURSOR); - File file = chooseFile("Choose destination file"); - setCursor(NORM_CURSOR); - if (file != null) { - destinationFileTextField.setText(file.getAbsolutePath()); - } + destinationBrowseButton.addActionListener(e -> { + setCursor(WAIT_CURSOR); + File file = chooseFile("Choose destination file"); + setCursor(NORM_CURSOR); + if (file != null) { + destinationFileTextField.setText(file.getAbsolutePath()); } }); filePanel.add(destinationBrowseButton, gbc); } File chooseFile(final String buttonText) { - if (chooser == null) { - chooser = new GhidraFileChooser(this); - chooser.setCurrentDirectory(getLastDataTypeArchiveDirectory()); - } + + GhidraFileChooser chooser = new GhidraFileChooser(this); + chooser.setCurrentDirectory(getLastDataTypeArchiveDirectory()); chooser.setTitle(buttonText); chooser.setApproveButtonText(buttonText); chooser.setApproveButtonToolTipText(buttonText); File file = chooser.getSelectedFile(); - + chooser.dispose(); if (file != null && file.exists()) { Preferences.setProperty(Preferences.LAST_OPENED_ARCHIVE_DIRECTORY, file.getAbsolutePath()); diff --git a/Ghidra/Test/IntegrationTest/src/screen/java/help/screenshot/DataTypeManagerPluginScreenShots.java b/Ghidra/Test/IntegrationTest/src/screen/java/help/screenshot/DataTypeManagerPluginScreenShots.java index 5ca379b769..586b38c9be 100644 --- a/Ghidra/Test/IntegrationTest/src/screen/java/help/screenshot/DataTypeManagerPluginScreenShots.java +++ b/Ghidra/Test/IntegrationTest/src/screen/java/help/screenshot/DataTypeManagerPluginScreenShots.java @@ -34,7 +34,6 @@ import ghidra.app.plugin.core.datamgr.*; import ghidra.app.plugin.core.datamgr.actions.FindStructuresBySizeAction; import ghidra.app.plugin.core.datamgr.archive.DataTypeManagerHandler; import ghidra.app.plugin.core.datamgr.archive.InvalidFileArchive; -import ghidra.app.plugin.core.datamgr.util.ConflictDialog; import ghidra.framework.preferences.Preferences; import ghidra.program.model.data.*; import ghidra.util.UniversalID; @@ -74,13 +73,6 @@ public class DataTypeManagerPluginScreenShots extends GhidraScreenShotGenerator captureDialog(900, 500); } - @Test - public void testDataTypeConflict() { - ConflictDialog dialog = new ConflictDialog("SIZE_T", "/baseDTs", "SIZE_T.conflict"); - showModalDialogInTool(dialog); - captureDialog(); - } - @Test public void testDataTypeManager() { captureIsolatedProvider(DataTypesProvider.class, 500, 400); diff --git a/Ghidra/Test/IntegrationTest/src/test/java/ghidra/util/bean/PathManagerTest.java b/Ghidra/Test/IntegrationTest/src/test/java/ghidra/util/bean/PathManagerTest.java index 69573d1611..41927c2848 100644 --- a/Ghidra/Test/IntegrationTest/src/test/java/ghidra/util/bean/PathManagerTest.java +++ b/Ghidra/Test/IntegrationTest/src/test/java/ghidra/util/bean/PathManagerTest.java @@ -187,9 +187,9 @@ public class PathManagerTest extends AbstractDockingTest { File temp = createTempFileForTest(); - Preferences.setProperty(Preferences.LAST_IMPORT_DIRECTORY, temp.getParent()); + Preferences.setProperty(Preferences.LAST_PATH_DIRECTORY, temp.getParent()); pathManager.setFileChooserProperties("Select Source Files", - Preferences.LAST_IMPORT_DIRECTORY, GhidraFileChooserMode.FILES_AND_DIRECTORIES, true, + Preferences.LAST_PATH_DIRECTORY, GhidraFileChooserMode.FILES_AND_DIRECTORIES, true, new ExtensionFileFilter(new String[] { "h" }, "C Header Files")); assertNotNull(addButton); @@ -223,9 +223,9 @@ public class PathManagerTest extends AbstractDockingTest { File temp = createTempFileForTest(); - Preferences.setProperty(Preferences.LAST_IMPORT_DIRECTORY, temp.getParent()); + Preferences.setProperty(Preferences.LAST_PATH_DIRECTORY, temp.getParent()); pathManager.setFileChooserProperties("Select Source Files", - Preferences.LAST_IMPORT_DIRECTORY, GhidraFileChooserMode.FILES_AND_DIRECTORIES, true, + Preferences.LAST_PATH_DIRECTORY, GhidraFileChooserMode.FILES_AND_DIRECTORIES, true, new ExtensionFileFilter(new String[] { "h" }, "C Header Files")); assertNotNull(addButton); diff --git a/Ghidra/Test/IntegrationTest/src/test/java/ghidra/util/bean/PathnameTablePanelTest.java b/Ghidra/Test/IntegrationTest/src/test/java/ghidra/util/bean/PathnameTablePanelTest.java index 9707476846..d969fde9e7 100644 --- a/Ghidra/Test/IntegrationTest/src/test/java/ghidra/util/bean/PathnameTablePanelTest.java +++ b/Ghidra/Test/IntegrationTest/src/test/java/ghidra/util/bean/PathnameTablePanelTest.java @@ -171,8 +171,8 @@ public class PathnameTablePanelTest extends AbstractDockingTest { public void testAddButton() throws Exception { File temp = createTempFileForTest(); - Preferences.setProperty(Preferences.LAST_IMPORT_DIRECTORY, temp.getParent()); - panel.setFileChooserProperties("Select Source Files", Preferences.LAST_IMPORT_DIRECTORY, + Preferences.setProperty(Preferences.LAST_PATH_DIRECTORY, temp.getParent()); + panel.setFileChooserProperties("Select Source Files", Preferences.LAST_PATH_DIRECTORY, GhidraFileChooserMode.FILES_AND_DIRECTORIES, true, new ExtensionFileFilter(new String[] { "h" }, "C Header Files")); @@ -193,8 +193,8 @@ public class PathnameTablePanelTest extends AbstractDockingTest { File temp = createTempFileForTest(); - Preferences.setProperty(Preferences.LAST_IMPORT_DIRECTORY, temp.getParent()); - panel.setFileChooserProperties("Select Source Files", Preferences.LAST_IMPORT_DIRECTORY, + Preferences.setProperty(Preferences.LAST_PATH_DIRECTORY, temp.getParent()); + panel.setFileChooserProperties("Select Source Files", Preferences.LAST_PATH_DIRECTORY, GhidraFileChooserMode.FILES_AND_DIRECTORIES, true, new ExtensionFileFilter(new String[] { "h" }, "C Header Files")); @@ -227,8 +227,8 @@ public class PathnameTablePanelTest extends AbstractDockingTest { panel.setAddToTop(true); File temp = createTempFileForTest(); - Preferences.setProperty(Preferences.LAST_IMPORT_DIRECTORY, temp.getParent()); - panel.setFileChooserProperties("Select Source Files", Preferences.LAST_IMPORT_DIRECTORY, + Preferences.setProperty(Preferences.LAST_PATH_DIRECTORY, temp.getParent()); + panel.setFileChooserProperties("Select Source Files", Preferences.LAST_PATH_DIRECTORY, GhidraFileChooserMode.FILES_AND_DIRECTORIES, true, new ExtensionFileFilter(new String[] { "h" }, "C Header Files"));