GP-2986 - ComponentProvder and dialog cleanup on dispose

This commit is contained in:
dragonmacher
2023-02-02 17:51:15 -05:00
parent e5a8f26347
commit c252e3b905
174 changed files with 1418 additions and 1529 deletions
@@ -20,13 +20,13 @@ import java.util.Collection;
import javax.swing.*; import javax.swing.*;
import docking.DialogComponentProvider; import docking.ReusableDialogComponentProvider;
import docking.widgets.table.EnumeratedColumnTableModel; import docking.widgets.table.EnumeratedColumnTableModel;
import docking.widgets.table.GTable; import docking.widgets.table.GTable;
import ghidra.framework.plugintool.PluginTool; import ghidra.framework.plugintool.PluginTool;
import ghidra.util.table.GhidraTableFilterPanel; import ghidra.util.table.GhidraTableFilterPanel;
public abstract class AbstractDebuggerMapProposalDialog<R> extends DialogComponentProvider { public abstract class AbstractDebuggerMapProposalDialog<R> extends ReusableDialogComponentProvider {
protected final EnumeratedColumnTableModel<R> tableModel; protected final EnumeratedColumnTableModel<R> tableModel;
protected GTable table; protected GTable table;
@@ -24,7 +24,7 @@ import javax.swing.*;
import javax.swing.table.TableColumn; import javax.swing.table.TableColumn;
import javax.swing.table.TableColumnModel; import javax.swing.table.TableColumnModel;
import docking.DialogComponentProvider; import docking.ReusableDialogComponentProvider;
import docking.widgets.table.*; import docking.widgets.table.*;
import docking.widgets.table.ColumnSortState.SortDirection; import docking.widgets.table.ColumnSortState.SortDirection;
import docking.widgets.table.DefaultEnumeratedColumnTableModel.EnumeratedTableColumn; import docking.widgets.table.DefaultEnumeratedColumnTableModel.EnumeratedTableColumn;
@@ -38,7 +38,7 @@ import ghidra.trace.model.memory.TraceMemoryRegion;
import ghidra.trace.model.modules.TraceSection; import ghidra.trace.model.modules.TraceSection;
import ghidra.util.table.GhidraTableFilterPanel; import ghidra.util.table.GhidraTableFilterPanel;
public class DebuggerBlockChooserDialog extends DialogComponentProvider { public class DebuggerBlockChooserDialog extends ReusableDialogComponentProvider {
public static class MemoryBlockRow { public static class MemoryBlockRow {
private final Program program; private final Program program;
private final MemoryBlock block; private final MemoryBlock block;
@@ -42,14 +42,10 @@ public abstract class DebuggerGoToTrait {
protected DebuggerCoordinates current = DebuggerCoordinates.NOWHERE; protected DebuggerCoordinates current = DebuggerCoordinates.NOWHERE;
protected final DebuggerGoToDialog goToDialog;
public DebuggerGoToTrait(PluginTool tool, Plugin plugin, ComponentProvider provider) { public DebuggerGoToTrait(PluginTool tool, Plugin plugin, ComponentProvider provider) {
this.tool = tool; this.tool = tool;
this.plugin = plugin; this.plugin = plugin;
this.provider = provider; this.provider = provider;
goToDialog = new DebuggerGoToDialog(this);
} }
protected abstract boolean goToAddress(Address address); protected abstract boolean goToAddress(Address address);
@@ -68,6 +64,7 @@ public abstract class DebuggerGoToTrait {
} }
private void activatedGoTo(ActionContext context) { private void activatedGoTo(ActionContext context) {
DebuggerGoToDialog goToDialog = new DebuggerGoToDialog(this);
TracePlatform platform = current.getPlatform(); TracePlatform platform = current.getPlatform();
goToDialog.show((SleighLanguage) platform.getLanguage()); goToDialog.show((SleighLanguage) platform.getLanguage());
} }
@@ -32,19 +32,10 @@ import ghidra.program.util.ProgramSelection;
import ghidra.trace.model.program.TraceProgramView; import ghidra.trace.model.program.TraceProgramView;
import ghidra.trace.model.program.TraceVariableSnapProgramView; import ghidra.trace.model.program.TraceVariableSnapProgramView;
@PluginInfo( @PluginInfo(shortDescription = "Copy and export trace data", description = "Provides tool actions for moving data from traces to various destinations.", category = PluginCategoryNames.DEBUGGER, packageName = DebuggerPluginPackage.NAME, status = PluginStatus.RELEASED, eventsConsumed = {}, eventsProduced = {}, servicesRequired = {
shortDescription = "Copy and export trace data", DebuggerStaticMappingService.class,
description = "Provides tool actions for moving data from traces to various destinations.", ProgramManager.class,
category = PluginCategoryNames.DEBUGGER, }, servicesProvided = {})
packageName = DebuggerPluginPackage.NAME,
status = PluginStatus.RELEASED,
eventsConsumed = {},
eventsProduced = {},
servicesRequired = {
DebuggerStaticMappingService.class,
ProgramManager.class,
},
servicesProvided = {})
public class DebuggerCopyActionsPlugin extends AbstractDebuggerPlugin { public class DebuggerCopyActionsPlugin extends AbstractDebuggerPlugin {
protected static ProgramSelection getSelectionFromContext(ActionContext context) { protected static ProgramSelection getSelectionFromContext(ActionContext context) {
@@ -75,6 +66,13 @@ public class DebuggerCopyActionsPlugin extends AbstractDebuggerPlugin {
createActions(); createActions();
} }
@Override
protected void dispose() {
super.dispose();
copyDialog.dispose();
}
protected void createActions() { protected void createActions() {
actionExportView = ExportTraceViewAction.builder(this) actionExportView = ExportTraceViewAction.builder(this)
.enabled(false) .enabled(false)
@@ -27,7 +27,7 @@ import javax.swing.*;
import javax.swing.table.TableColumn; import javax.swing.table.TableColumn;
import javax.swing.table.TableColumnModel; import javax.swing.table.TableColumnModel;
import docking.DialogComponentProvider; import docking.ReusableDialogComponentProvider;
import docking.widgets.table.*; import docking.widgets.table.*;
import docking.widgets.table.DefaultEnumeratedColumnTableModel.EnumeratedTableColumn; import docking.widgets.table.DefaultEnumeratedColumnTableModel.EnumeratedTableColumn;
import ghidra.app.plugin.core.debug.DebuggerCoordinates; import ghidra.app.plugin.core.debug.DebuggerCoordinates;
@@ -52,7 +52,7 @@ import ghidra.util.exception.CancelledException;
import ghidra.util.table.GhidraTableFilterPanel; import ghidra.util.table.GhidraTableFilterPanel;
import ghidra.util.task.*; import ghidra.util.task.*;
public class DebuggerCopyIntoProgramDialog extends DialogComponentProvider { public class DebuggerCopyIntoProgramDialog extends ReusableDialogComponentProvider {
static final int GAP = 5; static final int GAP = 5;
static final int BUTTON_SIZE = 32; static final int BUTTON_SIZE = 32;
@@ -24,24 +24,17 @@ import ghidra.app.services.*;
import ghidra.framework.plugintool.*; import ghidra.framework.plugintool.*;
import ghidra.framework.plugintool.util.PluginStatus; import ghidra.framework.plugintool.util.PluginStatus;
@PluginInfo( @PluginInfo(shortDescription = "Debugger regions manager", description = "GUI to manage memory regions", category = PluginCategoryNames.DEBUGGER, packageName = DebuggerPluginPackage.NAME, status = PluginStatus.RELEASED, eventsConsumed = {
shortDescription = "Debugger regions manager", ProgramActivatedPluginEvent.class,
description = "GUI to manage memory regions", ProgramLocationPluginEvent.class,
category = PluginCategoryNames.DEBUGGER, ProgramClosedPluginEvent.class,
packageName = DebuggerPluginPackage.NAME, TraceActivatedPluginEvent.class,
status = PluginStatus.RELEASED, }, servicesRequired = {
eventsConsumed = { DebuggerModelService.class,
ProgramActivatedPluginEvent.class, DebuggerStaticMappingService.class,
ProgramLocationPluginEvent.class, DebuggerTraceManagerService.class,
ProgramClosedPluginEvent.class, ProgramManager.class,
TraceActivatedPluginEvent.class, })
},
servicesRequired = {
DebuggerModelService.class,
DebuggerStaticMappingService.class,
DebuggerTraceManagerService.class,
ProgramManager.class,
})
public class DebuggerRegionsPlugin extends AbstractDebuggerPlugin { public class DebuggerRegionsPlugin extends AbstractDebuggerPlugin {
protected DebuggerRegionsProvider provider; protected DebuggerRegionsProvider provider;
@@ -58,6 +51,7 @@ public class DebuggerRegionsPlugin extends AbstractDebuggerPlugin {
@Override @Override
protected void dispose() { protected void dispose() {
tool.removeComponentProvider(provider); tool.removeComponentProvider(provider);
provider.dispose();
super.dispose(); super.dispose();
} }
@@ -204,6 +204,11 @@ public class DebuggerRegionsProvider extends ComponentProviderAdapter {
createActions(); createActions();
} }
void dispose() {
blockChooserDialog.dispose();
regionProposalDialog.dispose();
}
protected void buildMainPanel() { protected void buildMainPanel() {
panel = new DebuggerRegionsPanel(this); panel = new DebuggerRegionsPanel(this);
mainPanel.add(panel); mainPanel.add(panel);
@@ -23,7 +23,7 @@ import java.math.BigInteger;
import javax.swing.*; import javax.swing.*;
import javax.swing.border.EmptyBorder; import javax.swing.border.EmptyBorder;
import docking.DialogComponentProvider; import docking.ReusableDialogComponentProvider;
import docking.widgets.model.GAddressRangeField; import docking.widgets.model.GAddressRangeField;
import docking.widgets.model.GSpanField; import docking.widgets.model.GSpanField;
import ghidra.app.services.DebuggerStaticMappingService; import ghidra.app.services.DebuggerStaticMappingService;
@@ -36,7 +36,7 @@ import ghidra.trace.model.modules.TraceConflictedMappingException;
import ghidra.util.MathUtilities; import ghidra.util.MathUtilities;
import ghidra.util.layout.PairLayout; 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 static final String HEX_BIT64 = "0x" + BigInteger.ONE.shiftLeft(64).toString(16);
private DebuggerStaticMappingService mappingService; private DebuggerStaticMappingService mappingService;
@@ -418,7 +418,6 @@ public class DebuggerModulesProvider extends ComponentProviderAdapter {
private final DebuggerBlockChooserDialog blockChooserDialog; private final DebuggerBlockChooserDialog blockChooserDialog;
private final DebuggerModuleMapProposalDialog moduleProposalDialog; private final DebuggerModuleMapProposalDialog moduleProposalDialog;
private final DebuggerSectionMapProposalDialog sectionProposalDialog; private final DebuggerSectionMapProposalDialog sectionProposalDialog;
private DataTreeDialog programChooserDialog; // Already lazy
private DebuggerCoordinates current = DebuggerCoordinates.NOWHERE; private DebuggerCoordinates current = DebuggerCoordinates.NOWHERE;
private Program currentProgram; private Program currentProgram;
@@ -470,6 +469,7 @@ public class DebuggerModulesProvider extends ComponentProviderAdapter {
GhidraFileChooser chooser = new GhidraFileChooser(getComponent()); GhidraFileChooser chooser = new GhidraFileChooser(getComponent());
chooser.setSelectedFile(new File(module.getName())); chooser.setSelectedFile(new File(module.getName()));
File file = chooser.getSelectedFile(); File file = chooser.getSelectedFile();
chooser.dispose();
if (file == null) { // Perhaps cancelled if (file == null) { // Perhaps cancelled
return; return;
} }
@@ -511,6 +511,10 @@ public class DebuggerModulesProvider extends ComponentProviderAdapter {
consoleService.removeResolutionAction(actionMapMissingModule); consoleService.removeResolutionAction(actionMapMissingModule);
} }
} }
blockChooserDialog.dispose();
moduleProposalDialog.dispose();
sectionProposalDialog.dispose();
} }
@Override @Override
@@ -1071,27 +1075,24 @@ public class DebuggerModulesProvider extends ComponentProviderAdapter {
} }
private DataTreeDialog getProgramChooserDialog() { private DataTreeDialog getProgramChooserDialog() {
if (programChooserDialog != null) {
return programChooserDialog;
}
DomainFileFilter filter = df -> Program.class.isAssignableFrom(df.getDomainObjectClass()); 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 // TODO regarding the hack note below, I believe it's fixed, but not sure how to test
return programChooserDialog = return new DataTreeDialog(null, "Map Module to Program", DataTreeDialog.OPEN, filter) {
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.
{ // TODO/HACK: I get an NPE setting the default selection if I don't fake this. dialogShown();
dialogShown(); }
} };
};
} }
public DomainFile askProgram(Program program) { public DomainFile askProgram(Program program) {
getProgramChooserDialog(); DataTreeDialog dialog = getProgramChooserDialog();
if (program != null) { if (program != null) {
programChooserDialog.selectDomainFile(program.getDomainFile()); dialog.selectDomainFile(program.getDomainFile());
} }
tool.showDialog(programChooserDialog); tool.showDialog(dialog);
return programChooserDialog.getDomainFile(); return dialog.getDomainFile();
} }
public Entry<Program, MemoryBlock> askBlock(TraceSection section, Program program, public Entry<Program, MemoryBlock> askBlock(TraceSection section, Program program,
@@ -25,20 +25,13 @@ import ghidra.app.services.DebuggerTraceManagerService;
import ghidra.framework.plugintool.*; import ghidra.framework.plugintool.*;
import ghidra.framework.plugintool.util.PluginStatus; import ghidra.framework.plugintool.util.PluginStatus;
@PluginInfo( @PluginInfo(shortDescription = "Debugger static mapping manager", description = "GUI to manage static mappings", category = PluginCategoryNames.DEBUGGER, packageName = DebuggerPluginPackage.NAME, status = PluginStatus.RELEASED, eventsConsumed = {
shortDescription = "Debugger static mapping manager", TraceActivatedPluginEvent.class,
description = "GUI to manage static mappings", ProgramActivatedPluginEvent.class,
category = PluginCategoryNames.DEBUGGER, }, servicesRequired = {
packageName = DebuggerPluginPackage.NAME, DebuggerStaticMappingService.class,
status = PluginStatus.RELEASED, DebuggerTraceManagerService.class,
eventsConsumed = { })
TraceActivatedPluginEvent.class,
ProgramActivatedPluginEvent.class,
},
servicesRequired = {
DebuggerStaticMappingService.class,
DebuggerTraceManagerService.class,
})
public class DebuggerStaticMappingPlugin extends AbstractDebuggerPlugin { public class DebuggerStaticMappingPlugin extends AbstractDebuggerPlugin {
protected DebuggerStaticMappingProvider provider; protected DebuggerStaticMappingProvider provider;
@@ -55,6 +48,7 @@ public class DebuggerStaticMappingPlugin extends AbstractDebuggerPlugin {
@Override @Override
protected void dispose() { protected void dispose() {
tool.removeComponentProvider(provider); tool.removeComponentProvider(provider);
provider.dispose();
super.dispose(); super.dispose();
} }
@@ -176,6 +176,10 @@ public class DebuggerStaticMappingProvider extends ComponentProviderAdapter
createActions(); createActions();
} }
void dispose() {
addMappingDialog.dispose();
}
@AutoServiceConsumed @AutoServiceConsumed
private void setMappingService(DebuggerStaticMappingService mappingService) { private void setMappingService(DebuggerStaticMappingService mappingService) {
addMappingDialog.setMappingService(mappingService); addMappingDialog.setMappingService(mappingService);
@@ -132,9 +132,7 @@ public class DebuggerObjectsProvider extends ComponentProviderAdapter
@SuppressWarnings("unused") @SuppressWarnings("unused")
private final AutoService.Wiring autoServiceWiring; private final AutoService.Wiring autoServiceWiring;
@AutoOptionDefined( @AutoOptionDefined(name = "Default Extended Step", description = "The default string for the extended step command")
name = "Default Extended Step",
description = "The default string for the extended step command")
String extendedStep = ""; String extendedStep = "";
@SuppressWarnings("unused") @SuppressWarnings("unused")
@@ -244,6 +242,16 @@ public class DebuggerObjectsProvider extends ComponentProviderAdapter
repeatLastSet.run(); 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 @Override
public void addLocalAction(DockingActionIf action) { public void addLocalAction(DockingActionIf action) {
super.addLocalAction(action); super.addLocalAction(action);
@@ -78,6 +78,7 @@ public abstract class ImportExportAsAction extends DockingAction {
chooser.setCurrentDirectory(Application.getUserSettingsDirectory()); chooser.setCurrentDirectory(Application.getUserSettingsDirectory());
File f = chooser.getSelectedFile(); File f = chooser.getSelectedFile();
chooser.dispose();
if (chooser.wasCancelled() || f == null) { // Redundant? Meh, it's cheap. if (chooser.wasCancelled() || f == null) { // Redundant? Meh, it's cheap.
return; return;
} }
@@ -15,8 +15,7 @@
*/ */
package ghidra.app.plugin.core.debug.gui.objects.components; 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.*;
import static ghidra.app.plugin.core.debug.gui.DebuggerResources.tableRowActivationAction;
import java.awt.BorderLayout; import java.awt.BorderLayout;
import java.util.List; import java.util.List;
@@ -26,7 +25,7 @@ import java.util.concurrent.atomic.AtomicReference;
import javax.swing.*; import javax.swing.*;
import docking.ActionContext; import docking.ActionContext;
import docking.DialogComponentProvider; import docking.ReusableDialogComponentProvider;
import docking.action.ToolBarData; import docking.action.ToolBarData;
import docking.widgets.table.*; import docking.widgets.table.*;
import ghidra.app.plugin.core.debug.gui.DebuggerResources.AbstractAttachAction; import ghidra.app.plugin.core.debug.gui.DebuggerResources.AbstractAttachAction;
@@ -40,7 +39,7 @@ import ghidra.util.MessageType;
import ghidra.util.Msg; import ghidra.util.Msg;
import ghidra.util.table.GhidraTableFilterPanel; import ghidra.util.table.GhidraTableFilterPanel;
public class DebuggerAttachDialog extends DialogComponentProvider { public class DebuggerAttachDialog extends ReusableDialogComponentProvider {
protected class RefreshAction extends AbstractRefreshAction { protected class RefreshAction extends AbstractRefreshAction {
public static final String GROUP = GROUP_GENERAL; public static final String GROUP = GROUP_GENERAL;
@@ -26,7 +26,7 @@ import javax.swing.table.TableColumn;
import javax.swing.table.TableColumnModel; import javax.swing.table.TableColumnModel;
import docking.ActionContext; import docking.ActionContext;
import docking.DialogComponentProvider; import docking.ReusableDialogComponentProvider;
import docking.action.DockingAction; import docking.action.DockingAction;
import docking.widgets.table.DefaultEnumeratedColumnTableModel; import docking.widgets.table.DefaultEnumeratedColumnTableModel;
import docking.widgets.table.DefaultEnumeratedColumnTableModel.EnumeratedTableColumn; import docking.widgets.table.DefaultEnumeratedColumnTableModel.EnumeratedTableColumn;
@@ -37,7 +37,7 @@ import ghidra.program.model.lang.Language;
import ghidra.program.model.lang.Register; import ghidra.program.model.lang.Register;
import ghidra.util.table.GhidraTableFilterPanel; import ghidra.util.table.GhidraTableFilterPanel;
public class DebuggerAvailableRegistersDialog extends DialogComponentProvider { public class DebuggerAvailableRegistersDialog extends ReusableDialogComponentProvider {
protected enum AvailableRegisterTableColumns protected enum AvailableRegisterTableColumns
implements EnumeratedTableColumn<AvailableRegisterTableColumns, AvailableRegisterRow> { implements EnumeratedTableColumn<AvailableRegisterTableColumns, AvailableRegisterRow> {
@@ -553,6 +553,8 @@ public class DebuggerRegistersProvider extends ComponentProviderAdapter
@Override @Override
public void removeFromTool() { public void removeFromTool() {
availableRegsDialog.dispose();
plugin.providerRemoved(this); plugin.providerRemoved(this);
plugin.getTool().removePopupActionProvider(this); plugin.getTool().removePopupActionProvider(this);
super.removeFromTool(); super.removeFromTool();
@@ -1296,7 +1298,8 @@ public class DebuggerRegistersProvider extends ComponentProviderAdapter
return AsyncUtils.NIL; return AsyncUtils.NIL;
} }
toRead.retainAll(regMapper.getRegistersOnTarget()); toRead.retainAll(regMapper.getRegistersOnTarget());
Set<TargetRegisterBank> banks = recorder.getTargetRegisterBanks(traceThread, current.getFrame()); Set<TargetRegisterBank> banks =
recorder.getTargetRegisterBanks(traceThread, current.getFrame());
if (banks == null || banks.isEmpty()) { if (banks == null || banks.isEmpty()) {
Msg.error(this, "Current frame's bank does not exist"); Msg.error(this, "Current frame's bank does not exist");
return AsyncUtils.NIL; return AsyncUtils.NIL;
@@ -31,7 +31,7 @@ import javax.swing.text.View;
import org.apache.commons.collections4.BidiMap; import org.apache.commons.collections4.BidiMap;
import org.apache.commons.collections4.bidimap.DualLinkedHashBidiMap; 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.gui.DebuggerResources.AbstractConnectAction;
import ghidra.app.plugin.core.debug.utils.MiscellaneousUtils; import ghidra.app.plugin.core.debug.utils.MiscellaneousUtils;
import ghidra.app.services.DebuggerModelService; import ghidra.app.services.DebuggerModelService;
@@ -45,7 +45,7 @@ import ghidra.program.model.listing.Program;
import ghidra.util.*; import ghidra.util.*;
import ghidra.util.datastruct.CollectionChangeListener; import ghidra.util.datastruct.CollectionChangeListener;
public class DebuggerConnectDialog extends DialogComponentProvider public class DebuggerConnectDialog extends ReusableDialogComponentProvider
implements PropertyChangeListener { implements PropertyChangeListener {
private static final String KEY_CURRENT_FACTORY_CLASSNAME = "currentFactoryCls"; private static final String KEY_CURRENT_FACTORY_CLASSNAME = "currentFactoryCls";
private static final String KEY_SUCCESS_FACTORY_CLASSNAME = "successFactoryCls"; private static final String KEY_SUCCESS_FACTORY_CLASSNAME = "successFactoryCls";
@@ -62,15 +62,8 @@ import ghidra.util.classfinder.ClassSearcher;
import ghidra.util.datastruct.CollectionChangeListener; import ghidra.util.datastruct.CollectionChangeListener;
import ghidra.util.datastruct.ListenerSet; import ghidra.util.datastruct.ListenerSet;
@PluginInfo( @PluginInfo(shortDescription = "Debugger models manager service", description = "Manage debug sessions, connections, and trace recording", category = PluginCategoryNames.DEBUGGER, packageName = DebuggerPluginPackage.NAME, status = PluginStatus.HIDDEN, servicesRequired = {}, servicesProvided = {
shortDescription = "Debugger models manager service", DebuggerModelService.class, })
description = "Manage debug sessions, connections, and trace recording",
category = PluginCategoryNames.DEBUGGER,
packageName = DebuggerPluginPackage.NAME,
status = PluginStatus.HIDDEN,
servicesRequired = {},
servicesProvided = {
DebuggerModelService.class, })
public class DebuggerModelServicePlugin extends Plugin public class DebuggerModelServicePlugin extends Plugin
implements DebuggerModelServiceInternal, ApplicationLevelOnlyPlugin { implements DebuggerModelServiceInternal, ApplicationLevelOnlyPlugin {
@@ -184,6 +177,14 @@ public class DebuggerModelServicePlugin extends Plugin
createActions(); createActions();
} }
@Override
protected void dispose() {
super.dispose();
connectDialog.dispose();
offerDialog.dispose();
}
protected void createActions() { protected void createActions() {
actionDisconnectAll = DisconnectAllAction.builder(this, this) actionDisconnectAll = DisconnectAllAction.builder(this, this)
.menuPath("Debugger", DisconnectAllAction.NAME) .menuPath("Debugger", DisconnectAllAction.NAME)
@@ -23,7 +23,7 @@ import java.util.function.Function;
import javax.swing.*; import javax.swing.*;
import docking.DialogComponentProvider; import docking.ReusableDialogComponentProvider;
import docking.widgets.table.*; import docking.widgets.table.*;
import docking.widgets.table.ColumnSortState.SortDirection; import docking.widgets.table.ColumnSortState.SortDirection;
import docking.widgets.table.DefaultEnumeratedColumnTableModel.EnumeratedTableColumn; import docking.widgets.table.DefaultEnumeratedColumnTableModel.EnumeratedTableColumn;
@@ -35,7 +35,7 @@ import ghidra.program.util.DefaultLanguageService;
import ghidra.util.table.GhidraTable; import ghidra.util.table.GhidraTable;
import ghidra.util.table.GhidraTableFilterPanel; import ghidra.util.table.GhidraTableFilterPanel;
public class DebuggerSelectMappingOfferDialog extends DialogComponentProvider { public class DebuggerSelectMappingOfferDialog extends ReusableDialogComponentProvider {
protected enum OfferTableColumns protected enum OfferTableColumns
implements EnumeratedTableColumn<OfferTableColumns, DebuggerMappingOffer> { implements EnumeratedTableColumn<OfferTableColumns, DebuggerMappingOffer> {
@@ -66,26 +66,17 @@ import ghidra.util.datastruct.CollectionChangeListener;
import ghidra.util.exception.*; import ghidra.util.exception.*;
import ghidra.util.task.*; import ghidra.util.task.*;
@PluginInfo( @PluginInfo(shortDescription = "Debugger Trace View Management Plugin", description = "Manages UI Components, Wrappers, Focus, etc.", category = PluginCategoryNames.DEBUGGER, packageName = DebuggerPluginPackage.NAME, status = PluginStatus.RELEASED, eventsProduced = {
shortDescription = "Debugger Trace View Management Plugin", TraceActivatedPluginEvent.class,
description = "Manages UI Components, Wrappers, Focus, etc.", }, eventsConsumed = {
category = PluginCategoryNames.DEBUGGER, TraceActivatedPluginEvent.class,
packageName = DebuggerPluginPackage.NAME, TraceClosedPluginEvent.class,
status = PluginStatus.RELEASED, ModelObjectFocusedPluginEvent.class,
eventsProduced = { TraceRecorderAdvancedPluginEvent.class,
TraceActivatedPluginEvent.class, DebuggerPlatformPluginEvent.class,
}, }, servicesRequired = {}, servicesProvided = {
eventsConsumed = { DebuggerTraceManagerService.class,
TraceActivatedPluginEvent.class, })
TraceClosedPluginEvent.class,
ModelObjectFocusedPluginEvent.class,
TraceRecorderAdvancedPluginEvent.class,
DebuggerPlatformPluginEvent.class,
},
servicesRequired = {},
servicesProvided = {
DebuggerTraceManagerService.class,
})
public class DebuggerTraceManagerServicePlugin extends Plugin public class DebuggerTraceManagerServicePlugin extends Plugin
implements DebuggerTraceManagerService { implements DebuggerTraceManagerService {
@@ -277,8 +268,6 @@ public class DebuggerTraceManagerServicePlugin extends Plugin
@SuppressWarnings("unused") @SuppressWarnings("unused")
private final AutoService.Wiring autoServiceWiring; private final AutoService.Wiring autoServiceWiring;
private DataTreeDialog traceChooserDialog;
DockingAction actionCloseTrace; DockingAction actionCloseTrace;
DockingAction actionCloseAllTraces; DockingAction actionCloseAllTraces;
DockingAction actionCloseOtherTraces; DockingAction actionCloseOtherTraces;
@@ -388,9 +377,7 @@ public class DebuggerTraceManagerServicePlugin extends Plugin
} }
protected DataTreeDialog getTraceChooserDialog() { protected DataTreeDialog getTraceChooserDialog() {
if (traceChooserDialog != null) {
return traceChooserDialog;
}
DomainFileFilter filter = new DomainFileFilter() { DomainFileFilter filter = new DomainFileFilter() {
@Override @Override
@@ -405,21 +392,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 // TODO regarding the hack note below, I believe this issue ahs been fixed, but not sure how to test
return traceChooserDialog = return new DataTreeDialog(null, OpenTraceAction.NAME, DataTreeDialog.OPEN, filter) {
new DataTreeDialog(null, OpenTraceAction.NAME, DataTreeDialog.OPEN, filter) { { // TODO/HACK: Why the NPE if I don't do this?
{ // TODO/HACK: Why the NPE if I don't do this? dialogShown();
dialogShown(); }
} };
};
} }
public DomainFile askTrace(Trace trace) { public DomainFile askTrace(Trace trace) {
getTraceChooserDialog(); DataTreeDialog dialog = getTraceChooserDialog();
if (trace != null) { if (trace != null) {
traceChooserDialog.selectDomainFile(trace.getDomainFile()); dialog.selectDomainFile(trace.getDomainFile());
} }
tool.showDialog(traceChooserDialog); tool.showDialog(dialog);
return traceChooserDialog.getDomainFile(); return dialog.getDomainFile();
} }
@Override @Override
@@ -24,7 +24,7 @@ import javax.swing.*;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import docking.DialogComponentProvider; import docking.ReusableDialogComponentProvider;
import docking.action.DockingAction; import docking.action.DockingAction;
import docking.action.builder.ActionBuilder; import docking.action.builder.ActionBuilder;
import docking.widgets.combobox.GComboBox; import docking.widgets.combobox.GComboBox;
@@ -50,7 +50,7 @@ import ghidra.util.task.*;
* for learning function starts, train models, see performance statistics, and * for learning function starts, train models, see performance statistics, and
* apply the models. * 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_TEXT = "Number of Initial Bytes (CSV)";
private static final String INITIAL_BYTES_TIP = private static final String INITIAL_BYTES_TIP =
@@ -96,6 +96,15 @@ public class RandomForestFunctionFinderPlugin extends ProgramPlugin
initOptions(getTool().getOptions("Random Forest Function Finder")); initOptions(getTool().getOptions("Random Forest Function Finder"));
} }
@Override
protected void dispose() {
super.dispose();
if (paramsDialog != null) {
paramsDialog.dispose();
}
}
@Override @Override
public void optionsChanged(ToolOptions options, String optionName, Object oldValue, public void optionsChanged(ToolOptions options, String optionName, Object oldValue,
Object newValue) throws OptionsVetoException { Object newValue) throws OptionsVetoException {
@@ -69,6 +69,7 @@ public class SampleTableProvider extends ComponentProviderAdapter implements Opt
void dispose() { void dispose() {
filterTable.dispose(); filterTable.dispose();
fileChooserPanel.dispose();
removeFromTool(); removeFromTool();
} }
@@ -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_description.htm||GHIDRA||||END|
src/main/help/help/topics/DataTypeManagerPlugin/data_type_manager_window.html||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/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/DataTypeManager.png||GHIDRA||||END|
src/main/help/help/topics/DataTypeManagerPlugin/images/DisassociateDialog.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| src/main/help/help/topics/DataTypeManagerPlugin/images/EditPaths.png||GHIDRA||||END|
@@ -991,35 +991,6 @@
</BLOCKQUOTE> </BLOCKQUOTE>
<H3><A name="DataTypeConflicts"></A>Handling Data Type Conflicts</H3>
<BLOCKQUOTE>
<P>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:</P>
</BLOCKQUOTE>
<P align="center"><IMG src="images/DataTypeConflict.png" alt="" border="0"></P>
<BLOCKQUOTE>
<P>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:</P>
<OL>
<LI><I>Rename</I> the data type that you are dragging to have ".conflict" appended to
it to make a unique name.</LI>
<LI><I>Replace</I> the existing data type with the new one;
this means any use of the existing data types is <B><I>replaced</I></B> with the new
data type; the existing data type is deleted.</LI>
<LI>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.</LI>
</OL>
</BLOCKQUOTE>
<H3><A name="ReplaceDataType"></A>Replacing a Data Type</H3> <H3><A name="ReplaceDataType"></A>Replacing a Data Type</H3>
<BLOCKQUOTE> <BLOCKQUOTE>
Binary file not shown.

Before

Width:  |  Height:  |  Size: 14 KiB

@@ -20,9 +20,10 @@ import java.io.File;
import javax.swing.*; import javax.swing.*;
import docking.DialogComponentProvider; import docking.ReusableDialogComponentProvider;
import docking.widgets.OptionDialog; import docking.widgets.OptionDialog;
import docking.widgets.filechooser.GhidraFileChooser; import docking.widgets.filechooser.GhidraFileChooser;
import docking.widgets.filechooser.GhidraFileChooserMode;
import docking.widgets.label.GDLabel; import docking.widgets.label.GDLabel;
import ghidra.framework.GenericRunInfo; import ghidra.framework.GenericRunInfo;
import ghidra.framework.model.ProjectLocator; import ghidra.framework.model.ProjectLocator;
@@ -32,10 +33,9 @@ import ghidra.util.filechooser.GhidraFileChooserModel;
import ghidra.util.filechooser.GhidraFileFilter; import ghidra.util.filechooser.GhidraFileFilter;
/** /**
* Dialog to prompt the user for the project to archive and the file to archive * Dialog to prompt the user for the project to archive and the file to archive it to.
* it to.
*/ */
public class ArchiveDialog extends DialogComponentProvider { public class ArchiveDialog extends ReusableDialogComponentProvider {
private static final int NUM_TEXT_COLUMNS = 40; private static final int NUM_TEXT_COLUMNS = 40;
private boolean actionComplete; private boolean actionComplete;
@@ -43,14 +43,12 @@ public class ArchiveDialog extends DialogComponentProvider {
private JTextField archiveField; private JTextField archiveField;
private JButton archiveBrowse; private JButton archiveBrowse;
private GhidraFileChooser jarFileChooser;
private ProjectLocator projectLocator; private ProjectLocator projectLocator;
private String archivePathName; private String archivePathName;
/** /**
* Constructor * Constructor
* *
* @param parent the parent frame of the NumberInputDialog.
* @param plugin the archive plugin using this dialog. * @param plugin the archive plugin using this dialog.
*/ */
ArchiveDialog(ArchivePlugin plugin) { ArchiveDialog(ArchivePlugin plugin) {
@@ -179,6 +177,7 @@ public class ArchiveDialog extends DialogComponentProvider {
* Display this dialog. * Display this dialog.
* @param pProjectLocator the project URL to display when the dialog pops up. * @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 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 * @return true if the user submitted valid values for the project and
* archive file, false if user cancelled. * archive file, false if user cancelled.
@@ -237,7 +236,7 @@ public class ArchiveDialog extends DialogComponentProvider {
File file = new File(pathname); File file = new File(pathname);
String name = file.getName(); String name = file.getName();
if (!isValidName(name)) { if (!NamingUtilities.isValidProjectName(name)) {
setStatusText("Archive name contains invalid characters."); setStatusText("Archive name contains invalid characters.");
return false; return false;
} }
@@ -256,8 +255,7 @@ public class ArchiveDialog extends DialogComponentProvider {
String filePathName) { String filePathName) {
GhidraFileChooser fileChooser = new GhidraFileChooser(getComponent()); GhidraFileChooser fileChooser = new GhidraFileChooser(getComponent());
fileChooser.setFileSelectionMode(GhidraFileChooserMode.FILES_ONLY);
fileChooser.setFileSelectionMode(GhidraFileChooser.FILES_ONLY);
fileChooser.setFileFilter(new GhidraFileFilter() { fileChooser.setFileFilter(new GhidraFileFilter() {
@Override @Override
public boolean accept(File file, GhidraFileChooserModel model) { 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 * @param approveToolTip The tool tip for the "Open" button on the file chooser
* @return the archive file path. * @return the archive file path.
*/ */
String chooseArchiveFile(String approveButtonText, String approveToolTip) { private 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); archivePathName);
jarFileChooser.setTitle("Archive a Ghidra Project"); jarFileChooser.setTitle("Archive a Ghidra Project");
}
File jarFile = null; File jarFile = null;
if (archivePathName != null && archivePathName.length() != 0) { if (archivePathName != null && archivePathName.length() != 0) {
jarFile = new File(archivePathName); jarFile = new File(archivePathName);
@@ -338,7 +336,7 @@ public class ArchiveDialog extends DialogComponentProvider {
File file = selectedFile; File file = selectedFile;
String chosenPathname = file.getAbsolutePath(); String chosenPathname = file.getAbsolutePath();
String name = file.getName(); String name = file.getName();
if (!NamingUtilities.isValidName(name)) { if (!NamingUtilities.isValidProjectName(name)) {
Msg.showError(getClass(), null, "Invalid Archive Name", Msg.showError(getClass(), null, "Invalid Archive Name",
name + " is not a valid archive name"); name + " is not a valid archive name");
continue; continue;
@@ -354,32 +352,7 @@ public class ArchiveDialog extends DialogComponentProvider {
pathname = chosenPathname; pathname = chosenPathname;
} }
jarFileChooser.dispose();
return pathname; 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;
}
} }
@@ -96,8 +96,6 @@ public class ArchivePlugin extends Plugin implements ApplicationLevelOnlyPlugin,
private TaskListener archivingListener; private TaskListener archivingListener;
private TaskListener restoringListener; private TaskListener restoringListener;
//////////////////////////////////////////////////////////////////
/** /**
* The archive plugin provides menu action from the front end allowing the * The archive plugin provides menu action from the front end allowing the
* user to archive a project or restore an archived project. * user to archive a project or restore an archived project.
@@ -112,36 +110,34 @@ public class ArchivePlugin extends Plugin implements ApplicationLevelOnlyPlugin,
@Override @Override
public void dispose() { public void dispose() {
super.dispose(); super.dispose();
if (archiveDialog != null) {
archiveDialog.dispose();
}
if (restoreDialog != null) {
restoreDialog.dispose();
}
} }
/////////////////////////////////////////////////////////////////////
/**
* @see ghidra.framework.model.ProjectListener#projectClosed(Project)
*/
@Override @Override
public void projectClosed(Project project) { public void projectClosed(Project project) {
archiveAction.setEnabled(false); archiveAction.setEnabled(false);
restoreAction.setEnabled(true); restoreAction.setEnabled(true);
} }
/**
* @see ghidra.framework.model.ProjectListener#projectOpened(Project)
*/
@Override @Override
public void projectOpened(Project project) { public void projectOpened(Project project) {
archiveAction.setEnabled(true); archiveAction.setEnabled(true);
restoreAction.setEnabled(false); restoreAction.setEnabled(false);
} }
/** /*
* for JUnits... * for JUnits...
*/ */
boolean isArchiving() { boolean isArchiving() {
return isArchiving; return isArchiving;
} }
/** /*
* for JUnits... * for JUnits...
*/ */
boolean isRestoring() { boolean isRestoring() {
@@ -300,12 +296,6 @@ public class ArchivePlugin extends Plugin implements ApplicationLevelOnlyPlugin,
new TaskLauncher(task, tool.getToolFrame()); 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 { private boolean isJarFormat(File jarFile) throws IOException {
JarInputStream jarIn = new JarInputStream(new FileInputStream(jarFile)); JarInputStream jarIn = new JarInputStream(new FileInputStream(jarFile));
JarEntry entry = jarIn.getNextJarEntry(); JarEntry entry = jarIn.getNextJarEntry();
@@ -22,8 +22,9 @@ import java.io.File;
import javax.swing.*; import javax.swing.*;
import docking.DialogComponentProvider; import docking.ReusableDialogComponentProvider;
import docking.widgets.filechooser.GhidraFileChooser; import docking.widgets.filechooser.GhidraFileChooser;
import docking.widgets.filechooser.GhidraFileChooserMode;
import docking.widgets.label.GDLabel; import docking.widgets.label.GDLabel;
import ghidra.framework.GenericRunInfo; import ghidra.framework.GenericRunInfo;
import ghidra.framework.model.ProjectLocator; 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 * Dialog to prompt the user for the archive file to restore
* and where to restore it to. * 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 * Preference name for directory last selected to choose a jar file
* to restore. * to restore.
@@ -54,14 +55,12 @@ public class RestoreDialog extends DialogComponentProvider {
private JButton restoreBrowse; private JButton restoreBrowse;
private JLabel projectNameLabel; private JLabel projectNameLabel;
private JTextField projectNameField; private JTextField projectNameField;
private GhidraFileChooser jarFileChooser;
private GhidraFileChooser dirChooser;
private String archivePathName; private String archivePathName;
private ProjectLocator restoreURL; private ProjectLocator restoreURL;
public RestoreDialog(ArchivePlugin plugin) { public RestoreDialog(ArchivePlugin plugin) {
super("Restore Project Archive", true); super("Restore Project Archive");
this.plugin = plugin; this.plugin = plugin;
initialize(); initialize();
@@ -374,10 +373,9 @@ public class RestoreDialog extends DialogComponentProvider {
GhidraFileChooser fileChooser = new GhidraFileChooser(null); GhidraFileChooser fileChooser = new GhidraFileChooser(null);
// start the browsing in the user's preferred project directory // start the browsing in the user's preferred project directory
File projectDirectory = new File(GenericRunInfo.getProjectsDirPath()); File projectDirectory = new File(GenericRunInfo.getProjectsDirPath());
fileChooser.setFileSelectionMode(GhidraFileChooser.DIRECTORIES_ONLY); fileChooser.setFileSelectionMode(GhidraFileChooserMode.DIRECTORIES_ONLY);
fileChooser.setCurrentDirectory(projectDirectory); fileChooser.setCurrentDirectory(projectDirectory);
fileChooser.setSelectedFile(projectDirectory); fileChooser.setSelectedFile(projectDirectory);
return fileChooser; return fileChooser;
} }
@@ -386,19 +384,19 @@ public class RestoreDialog extends DialogComponentProvider {
* filename that are used for the Project location and name * filename that are used for the Project location and name
* @param approveButtonText The label for the "Open" button on the file chooser * @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 * @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) { 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); archivePathName);
jarFileChooser.setTitle("Restore a Ghidra Project - Archive"); jarFileChooser.setTitle("Restore a Ghidra Project - Archive");
String lastDirSelected = Preferences.getProperty(ArchivePlugin.LAST_ARCHIVE_DIR); String lastDirSelected = Preferences.getProperty(ArchivePlugin.LAST_ARCHIVE_DIR);
if (lastDirSelected != null) { if (lastDirSelected != null) {
File file = new File(lastDirSelected); File file = new File(lastDirSelected);
if (file.exists()) { if (file.exists()) {
jarFileChooser.setCurrentDirectory(file); jarFileChooser.setCurrentDirectory(file);
}
} }
} }
File jarFile = null; File jarFile = null;
@@ -419,7 +417,7 @@ public class RestoreDialog extends DialogComponentProvider {
File file = selectedFile; File file = selectedFile;
String chosenName = file.getName(); String chosenName = file.getName();
if (!NamingUtilities.isValidName(chosenName)) { if (!NamingUtilities.isValidProjectName(chosenName)) {
Msg.showError(getClass(), null, "Invalid Archive Name", Msg.showError(getClass(), null, "Invalid Archive Name",
chosenName + " is not a valid archive name"); chosenName + " is not a valid archive name");
continue; continue;
@@ -428,6 +426,9 @@ public class RestoreDialog extends DialogComponentProvider {
Preferences.setProperty(ArchivePlugin.LAST_ARCHIVE_DIR, file.getParent()); Preferences.setProperty(ArchivePlugin.LAST_ARCHIVE_DIR, file.getParent());
pathname = file.getAbsolutePath(); pathname = file.getAbsolutePath();
} }
jarFileChooser.dispose();
return pathname; return pathname;
} }
@@ -436,13 +437,11 @@ public class RestoreDialog extends DialogComponentProvider {
* project archive will be restored. * project archive will be restored.
* @param approveButtonText The label for the "Open" button on the file chooser * @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 * @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) { String chooseDirectory(String approveButtonText, String approveToolTip) {
if (dirChooser == null) { GhidraFileChooser dirChooser = createDirectoryChooser();
dirChooser = createDirectoryChooser(); dirChooser.setTitle("Restore a Ghidra Project - Directory");
dirChooser.setTitle("Restore a Ghidra Project - Directory");
}
if (restoreURL != null) { if (restoreURL != null) {
dirChooser.setSelectedFile(new File(restoreURL.getLocation())); dirChooser.setSelectedFile(new File(restoreURL.getLocation()));
} }
@@ -450,6 +449,7 @@ public class RestoreDialog extends DialogComponentProvider {
dirChooser.setApproveButtonToolTipText(approveToolTip); dirChooser.setApproveButtonToolTipText(approveToolTip);
File selectedFile = dirChooser.getSelectedFile(true); File selectedFile = dirChooser.getSelectedFile(true);
dirChooser.dispose();
if (selectedFile != null) { if (selectedFile != null) {
return selectedFile.getAbsolutePath(); return selectedFile.getAbsolutePath();
} }
@@ -77,7 +77,6 @@ public class BookmarkPlugin extends ProgramPlugin
private BookmarkProvider provider; private BookmarkProvider provider;
private DockingAction addAction; private DockingAction addAction;
private DockingAction deleteAction; private DockingAction deleteAction;
private CreateBookmarkDialog createDialog;
private GoToService goToService; private GoToService goToService;
private MarkerService markerService; private MarkerService markerService;
private BookmarkManager bookmarkMgr; private BookmarkManager bookmarkMgr;
@@ -206,10 +205,6 @@ public class BookmarkPlugin extends ProgramPlugin
provider.dispose(); provider.dispose();
provider = null; provider = null;
} }
if (createDialog != null) {
createDialog.dispose();
createDialog = null;
}
goToService = null; goToService = null;
disposeAllBookmarkers(); disposeAllBookmarkers();
@@ -444,7 +439,7 @@ public class BookmarkPlugin extends ProgramPlugin
return; return;
} }
boolean hasSelection = currentSelection != null && !currentSelection.isEmpty(); boolean hasSelection = currentSelection != null && !currentSelection.isEmpty();
createDialog = new CreateBookmarkDialog(this, currCU, hasSelection); CreateBookmarkDialog createDialog = new CreateBookmarkDialog(this, currCU, hasSelection);
tool.showDialog(createDialog); tool.showDialog(createDialog);
} }
@@ -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_CODE_BYTES_NAME = "Clear Code Bytes";
private static final String CLEAR_FLOW_AND_REPAIR = "Clear Flow and Repair"; private static final String CLEAR_FLOW_AND_REPAIR = "Clear Flow and Repair";
private ClearDialog clearDialog;
private ClearFlowDialog clearFlowDialog;
/**
* Constructor
*/
public ClearPlugin(PluginTool tool) { public ClearPlugin(PluginTool tool) {
super(tool); super(tool);
createActions(); createActions();
} }
// /////////////////////////////////////////////////////////////////////
/**
* Clear the flow and repair disassembly at the current location
*/
void clearFlowAndRepair(ListingActionContext context, boolean clearSymbols, boolean clearData, void clearFlowAndRepair(ListingActionContext context, boolean clearSymbols, boolean clearData,
boolean repair) { boolean repair) {
ClearFlowAndRepairCmd cmd; ClearFlowAndRepairCmd cmd;
@@ -76,10 +65,6 @@ public class ClearPlugin extends Plugin {
tool.executeBackgroundCommand(cmd, context.getProgram()); 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) { void clear(ClearOptions options, ListingActionContext context) {
if (!options.clearAny()) { if (!options.clearAny()) {
return; return;
@@ -258,13 +243,12 @@ public class ClearPlugin extends Plugin {
clear(opts, context); clear(opts, context);
} }
/** /**
* Pop up the clear with options dialog. * Pop up the clear with options dialog.
*/ */
private void showClearAllDialog(ListingActionContext programActionContext) { private void showClearAllDialog(ListingActionContext programActionContext) {
if (clearDialog == null) { ClearDialog clearDialog = new ClearDialog(this);
clearDialog = new ClearDialog(this);
}
clearDialog.setProgramActionContext(programActionContext); clearDialog.setProgramActionContext(programActionContext);
tool.showDialog(clearDialog); tool.showDialog(clearDialog);
} }
@@ -273,9 +257,7 @@ public class ClearPlugin extends Plugin {
* Pop up the clear flows dialog * Pop up the clear flows dialog
*/ */
private void showClearFlowDialog(ListingActionContext context) { private void showClearFlowDialog(ListingActionContext context) {
if (clearFlowDialog == null) { ClearFlowDialog clearFlowDialog = new ClearFlowDialog(this);
clearFlowDialog = new ClearFlowDialog(this);
}
clearFlowDialog.setProgramActionContext(context); clearFlowDialog.setProgramActionContext(context);
tool.showDialog(clearFlowDialog); tool.showDialog(clearFlowDialog);
} }
@@ -38,7 +38,7 @@ import ghidra.util.HelpLocation;
/** /**
* Dialog for setting the comments for a CodeUnit. * 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 eolField;
private JTextArea preField; private JTextArea preField;
@@ -58,7 +58,6 @@ public class CommentsPlugin extends Plugin implements OptionsChangeListener {
private DockingAction deleteAction; private DockingAction deleteAction;
private DockingAction historyAction; private DockingAction historyAction;
private CommentsDialog dialog; private CommentsDialog dialog;
private CommentHistoryDialog historyDialog;
private DockingAction preCommentEditAction; private DockingAction preCommentEditAction;
private DockingAction postCommentEditAction; private DockingAction postCommentEditAction;
@@ -76,6 +75,12 @@ public class CommentsPlugin extends Plugin implements OptionsChangeListener {
initializeOptions(tool.getOptions("Comments")); initializeOptions(tool.getOptions("Comments"));
} }
@Override
protected void dispose() {
super.dispose();
dialog.dispose();
}
@Override @Override
public void optionsChanged(ToolOptions options, String optionName, Object oldValue, public void optionsChanged(ToolOptions options, String optionName, Object oldValue,
Object newValue) { Object newValue) {
@@ -223,9 +228,7 @@ public class CommentsPlugin extends Plugin implements OptionsChangeListener {
private void showCommentHistory(ListingActionContext context) { private void showCommentHistory(ListingActionContext context) {
CodeUnit cu = context.getCodeUnit(); CodeUnit cu = context.getCodeUnit();
ProgramLocation loc = context.getLocation(); ProgramLocation loc = context.getLocation();
if (historyDialog == null) { CommentHistoryDialog historyDialog = new CommentHistoryDialog();
historyDialog = new CommentHistoryDialog();
}
historyDialog.showDialog(cu, CommentType.getCommentType(null, loc, CodeUnit.EOL_COMMENT), historyDialog.showDialog(cu, CommentType.getCommentType(null, loc, CodeUnit.EOL_COMMENT),
tool, context); tool, context);
} }
@@ -238,14 +241,17 @@ public class CommentsPlugin extends Plugin implements OptionsChangeListener {
} }
if (loc instanceof FunctionRepeatableCommentFieldLocation) { if (loc instanceof FunctionRepeatableCommentFieldLocation) {
action.getPopupMenuData().setMenuPath( action.getPopupMenuData()
new String[] { "Comments", actionString + " Repeatable Comment" + endString }); .setMenuPath(
new String[] { "Comments",
actionString + " Repeatable Comment" + endString });
return; return;
} }
if (loc instanceof PlateFieldLocation) { if (loc instanceof PlateFieldLocation) {
action.getPopupMenuData().setMenuPath( action.getPopupMenuData()
new String[] { "Comments", actionString + " Plate Comment" + endString }); .setMenuPath(
new String[] { "Comments", actionString + " Plate Comment" + endString });
return; return;
} }
@@ -253,23 +259,29 @@ public class CommentsPlugin extends Plugin implements OptionsChangeListener {
int type = cfLoc.getCommentType(); int type = cfLoc.getCommentType();
switch (type) { switch (type) {
case CodeUnit.PRE_COMMENT: case CodeUnit.PRE_COMMENT:
action.getPopupMenuData().setMenuPath( action.getPopupMenuData()
new String[] { "Comments", actionString + " Pre-Comment" + endString }); .setMenuPath(
new String[] { "Comments", actionString + " Pre-Comment" + endString });
break; break;
case CodeUnit.POST_COMMENT: case CodeUnit.POST_COMMENT:
action.getPopupMenuData().setMenuPath( action.getPopupMenuData()
new String[] { "Comments", actionString + " Post-Comment" + endString }); .setMenuPath(
new String[] { "Comments",
actionString + " Post-Comment" + endString });
break; break;
case CodeUnit.EOL_COMMENT: case CodeUnit.EOL_COMMENT:
action.getPopupMenuData().setMenuPath( action.getPopupMenuData()
new String[] { "Comments", actionString + " EOL Comment" + endString }); .setMenuPath(
new String[] { "Comments", actionString + " EOL Comment" + endString });
break; break;
case CodeUnit.REPEATABLE_COMMENT: case CodeUnit.REPEATABLE_COMMENT:
action.getPopupMenuData().setMenuPath( action.getPopupMenuData()
new String[] { "Comments", actionString + " Repeatable Comment" + endString }); .setMenuPath(
new String[] { "Comments",
actionString + " Repeatable Comment" + endString });
break; break;
} }
} }
@@ -150,6 +150,7 @@ public abstract class CompositeEditorProvider extends ComponentProviderAdapter
editorModel.endFieldEditing(); editorModel.endFieldEditing();
} }
if (saveChanges(true) != 0) { if (saveChanges(true) != 0) {
super.closeComponent();
dispose(); dispose();
} }
} }
@@ -59,7 +59,7 @@ import resources.Icons;
* *
* *
*/ */
class ParseDialog extends DialogComponentProvider { class ParseDialog extends ReusableDialogComponentProvider {
final static String PROFILE_DIR = "parserprofiles"; final static String PROFILE_DIR = "parserprofiles";
private static String FILE_EXTENSION = ".prf"; private static String FILE_EXTENSION = ".prf";
@@ -89,11 +89,10 @@ class ParseDialog extends DialogComponentProvider {
private ArrayList<ComboBoxItem> itemList; private ArrayList<ComboBoxItem> itemList;
private ComboBoxItemComparator comparator; private ComboBoxItemComparator comparator;
private ResourceFile parentUserFile; private ResourceFile parentUserFile;
private GhidraFileChooser fileChooser;
private boolean saveAsInProgress; private boolean saveAsInProgress;
ParseDialog(CParserPlugin plugin) { ParseDialog(CParserPlugin plugin) {
super("Parse C Source", false); super("Parse C Source", false, true, true, false);
this.plugin = plugin; this.plugin = plugin;
itemList = new ArrayList<>(); itemList = new ArrayList<>();
@@ -157,7 +156,7 @@ class ParseDialog extends DialogComponentProvider {
pathPanel.setBorder(BorderFactory.createTitledBorder("Source files to parse")); pathPanel.setBorder(BorderFactory.createTitledBorder("Source files to parse"));
String importDir = Preferences.getProperty(LAST_IMPORT_C_DIRECTORY); String importDir = Preferences.getProperty(LAST_IMPORT_C_DIRECTORY);
if (importDir == null) { if (importDir == null) {
importDir = Preferences.getProperty(Preferences.LAST_IMPORT_DIRECTORY); importDir = Preferences.getProperty(Preferences.LAST_PATH_DIRECTORY);
if (importDir != null) { if (importDir != null) {
Preferences.setProperty(LAST_IMPORT_C_DIRECTORY, importDir); Preferences.setProperty(LAST_IMPORT_C_DIRECTORY, importDir);
} }
@@ -625,19 +624,15 @@ class ParseDialog extends DialogComponentProvider {
} }
private File getSaveFile() { private File getSaveFile() {
if (fileChooser == null) {
fileChooser = new GhidraFileChooser(rootPanel); GhidraFileChooser fileChooser = new GhidraFileChooser(rootPanel);
String dir = Preferences.getProperty(Preferences.LAST_EXPORT_DIRECTORY); fileChooser.setTitle("Choose Save Archive File");
if (dir != null) { fileChooser.setApproveButtonText("Choose Save Archive File");
File file = new File(dir); fileChooser.setApproveButtonToolTipText("Choose filename for archive");
fileChooser.setCurrentDirectory(file); fileChooser.setLastDirectoryPreference(Preferences.LAST_EXPORT_DIRECTORY);
fileChooser.setTitle("Choose Save Archive File");
fileChooser.setApproveButtonText("Choose Save Archive File");
fileChooser.setApproveButtonToolTipText("Choose filename for archive");
}
}
fileChooser.rescanCurrentDirectory();
File file = fileChooser.getSelectedFile(); File file = fileChooser.getSelectedFile();
fileChooser.dispose();
if (file != null) { if (file != null) {
File parent = file.getParentFile(); File parent = file.getParentFile();
if (parent != null) { if (parent != null) {
@@ -42,14 +42,9 @@ class CreateStructureAction extends ListingContextAction {
private DataPlugin plugin; private DataPlugin plugin;
private CreateStructureDialog createStructureDialog; private CreateStructureDialog createStructureDialog;
/**
* Constructor
* @param name action name
* @param owner owner of this action (the plugin name)
*/
public CreateStructureAction(DataPlugin plugin) { public CreateStructureAction(DataPlugin plugin) {
super("Create Structure", plugin.getName()); super("Create Structure", plugin.getName());
// ACTIONS - auto generated
setPopupMenuData(new MenuData(CREATE_STRUCTURE_POPUP_MENU, null, "BasicData")); setPopupMenuData(new MenuData(CREATE_STRUCTURE_POPUP_MENU, null, "BasicData"));
setKeyBindingData(new KeyBindingData(KeyEvent.VK_OPEN_BRACKET, InputEvent.SHIFT_DOWN_MASK)); setKeyBindingData(new KeyBindingData(KeyEvent.VK_OPEN_BRACKET, InputEvent.SHIFT_DOWN_MASK));
@@ -28,7 +28,7 @@ import javax.swing.table.*;
import javax.swing.text.BadLocationException; import javax.swing.text.BadLocationException;
import javax.swing.text.Document; import javax.swing.text.Document;
import docking.DialogComponentProvider; import docking.ReusableDialogComponentProvider;
import docking.widgets.button.GRadioButton; import docking.widgets.button.GRadioButton;
import docking.widgets.table.*; import docking.widgets.table.*;
import generic.theme.GThemeDefaults.Colors; 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 NEW_STRUCTURE_STATUS_PREFIX = "Creating new structure: ";
private static final String EXISITING_STRUCTURE_STATUS_PREFIX = "Using existing structure: "; private static final String EXISITING_STRUCTURE_STATUS_PREFIX = "Using existing structure: ";
@@ -28,33 +28,32 @@ import ghidra.program.model.listing.Data;
import ghidra.program.model.listing.Program; import ghidra.program.model.listing.Program;
import ghidra.program.util.FieldNameFieldLocation; import ghidra.program.util.FieldNameFieldLocation;
import ghidra.program.util.ProgramLocation; import ghidra.program.util.ProgramLocation;
/** /**
* Base class for comment actions to edit and delete comments. * Base class for comment actions to edit and delete comments.
*/ */
class RenameDataFieldAction extends ListingContextAction { class RenameDataFieldAction extends ListingContextAction {
private DataPlugin plugin; private DataPlugin plugin;
private RenameDataFieldDialog dialog;
public RenameDataFieldAction(DataPlugin plugin) {
super("Rename Data Field", plugin.getName());
dialog = new RenameDataFieldDialog(plugin);
setPopupMenuData( public RenameDataFieldAction(DataPlugin plugin) {
new MenuData( super("Rename Data Field", plugin.getName());
new String[] {"Data", "Rename Field"},null,"BasicData" ) );
setKeyBindingData( new KeyBindingData( setPopupMenuData(
KeyEvent.VK_N, 0 ) ); new MenuData(
new String[] { "Data", "Rename Field" }, null, "BasicData"));
this.plugin = plugin; setKeyBindingData(new KeyBindingData(
setEnabled(true); KeyEvent.VK_N, 0));
}
@Override this.plugin = plugin;
setEnabled(true);
}
@Override
protected void actionPerformed(ListingActionContext context) { protected void actionPerformed(ListingActionContext context) {
ListingActionContext programActionContext = (ListingActionContext) context.getContextObject(); ListingActionContext programActionContext =
(ListingActionContext) context.getContextObject();
PluginTool tool = plugin.getTool(); PluginTool tool = plugin.getTool();
Program program = programActionContext.getProgram(); Program program = programActionContext.getProgram();
ProgramLocation loc = programActionContext.getLocation(); ProgramLocation loc = programActionContext.getLocation();
@@ -62,19 +61,22 @@ class RenameDataFieldAction extends ListingContextAction {
DataType type = data.getDataType(); DataType type = data.getDataType();
if (type instanceof Composite) { if (type instanceof Composite) {
Composite comp = (Composite)type; Composite comp = (Composite) type;
int[] compPath = loc.getComponentPath(); int[] compPath = loc.getComponentPath();
for (int i=0; i<compPath.length-1; i++) { for (int i = 0; i < compPath.length - 1; i++) {
DataTypeComponent subComp = comp.getComponent(compPath[i]); DataTypeComponent subComp = comp.getComponent(compPath[i]);
type = subComp.getDataType(); type = subComp.getDataType();
if (type instanceof Composite) if (type instanceof Composite) {
comp = (Composite)type; comp = (Composite) type;
else }
else {
return; return;
}
} }
Data instance = data.getComponent(compPath); Data instance = data.getComponent(compPath);
DataTypeComponent subComp = comp.getComponent(compPath[compPath.length-1]); DataTypeComponent subComp = comp.getComponent(compPath[compPath.length - 1]);
RenameDataFieldDialog dialog = new RenameDataFieldDialog(plugin);
dialog.setDataComponent(program, subComp, instance.getFieldName()); dialog.setDataComponent(program, subComp, instance.getFieldName());
tool.showDialog(dialog, tool.getComponentProvider(PluginConstants.CODE_BROWSER)); tool.showDialog(dialog, tool.getComponentProvider(PluginConstants.CODE_BROWSER));
} }
@@ -17,7 +17,6 @@ package ghidra.app.plugin.core.datamgr;
import java.awt.Component; import java.awt.Component;
import java.awt.datatransfer.Clipboard; import java.awt.datatransfer.Clipboard;
import java.awt.event.ActionListener;
import java.io.File; import java.io.File;
import java.io.IOException; import java.io.IOException;
import java.util.*; import java.util.*;
@@ -95,7 +94,6 @@ public class DataTypeManagerPlugin extends ProgramPlugin
private DataTypeManagerHandler dataTypeManagerHandler; private DataTypeManagerHandler dataTypeManagerHandler;
private DataTypesProvider provider; private DataTypesProvider provider;
private OpenVersionedFileDialog<DataTypeArchive> openDialog;
private Map<String, DockingAction> recentlyOpenedArchiveMap; private Map<String, DockingAction> recentlyOpenedArchiveMap;
private Map<String, DockingAction> installArchiveMap; private Map<String, DockingAction> installArchiveMap;
@@ -366,19 +364,10 @@ public class DataTypeManagerPlugin extends ProgramPlugin
newProvider.setIncludeDataTypeMembersInFilter(provider.includeDataMembersInSearch()); newProvider.setIncludeDataTypeMembersInFilter(provider.includeDataMembersInSearch());
newProvider.setFilteringArrays(provider.isFilteringArrays()); newProvider.setFilteringArrays(provider.isFilteringArrays());
newProvider.setFilteringPointers(provider.isFilteringPointers()); newProvider.setFilteringPointers(provider.isFilteringPointers());
newProvider.setTransient();
return newProvider; 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() { public Program getProgram() {
return currentProgram; return currentProgram;
} }
@@ -574,25 +563,24 @@ public class DataTypeManagerPlugin extends ProgramPlugin
} }
public void openProjectDataTypeArchive() { public void openProjectDataTypeArchive() {
if (openDialog == null) {
ActionListener listener = ev -> { OpenVersionedFileDialog<DataTypeArchive> dialog =
DomainFile domainFile = openDialog.getDomainFile(); new OpenVersionedFileDialog<>(tool, "Open Project Data Type Archive",
int version = openDialog.getVersion(); DataTypeArchive.class);
if (domainFile == null) { dialog.setHelpLocation(new HelpLocation(HelpTopics.PROGRAM, "Open_File_Dialog"));
openDialog.setStatusText("Please choose a Project Data Type Archive"); dialog.addOkActionListener(ev -> {
} DomainFile domainFile = dialog.getDomainFile();
else { int version = dialog.getVersion();
openDialog.close(); if (domainFile == null) {
openArchive(domainFile, version); dialog.setStatusText("Please choose a Project Data Type Archive");
} }
}; else {
openDialog = dialog.close();
new OpenVersionedFileDialog<>(tool, "Open Project Data Type Archive", openArchive(domainFile, version);
DataTypeArchive.class); }
openDialog.setHelpLocation(new HelpLocation(HelpTopics.PROGRAM, "Open_File_Dialog")); });
openDialog.addOkActionListener(listener);
} tool.showDialog(dialog);
tool.showDialog(openDialog);
} }
@Override @Override
@@ -42,7 +42,6 @@ public class DataTypeSyncDialog extends DialogComponentProvider implements DataT
private DataTypeComparePanel comparePanel; private DataTypeComparePanel comparePanel;
private final String operationName; private final String operationName;
private boolean cancelled;
private List<DataTypeSyncInfo> selectedInfos = Collections.emptyList(); private List<DataTypeSyncInfo> selectedInfos = Collections.emptyList();
public DataTypeSyncDialog(DataTypeManagerPlugin plugin, String clientName, String sourceName, public DataTypeSyncDialog(DataTypeManagerPlugin plugin, String clientName, String sourceName,
@@ -118,7 +117,6 @@ public class DataTypeSyncDialog extends DialogComponentProvider implements DataT
@Override @Override
protected void cancelCallback() { protected void cancelCallback() {
cancelled = true;
close(); close();
} }
@@ -114,6 +114,11 @@ public class DataTypesProvider extends ComponentProviderAdapter {
createLocalActions(); createLocalActions();
} }
@Override // overridden to open access
protected void setTransient() {
super.setTransient();
}
/** /**
* This creates all the actions for opening/creating data type archives. * This creates all the actions for opening/creating data type archives.
* It also creates the action for refreshing the built-in data types * 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 @Override // overridden to handle special logic in plugin
public void closeComponent() { public void closeComponent() {
plugin.closeProvider(this); super.closeComponent();
if (isTransient()) {
dispose();
}
} }
private void buildComponent() { private void buildComponent() {
@@ -51,6 +51,7 @@ public class CreateArchiveAction extends DockingAction {
Msg.trace(this, "Showing filechooser to get new archive name..."); Msg.trace(this, "Showing filechooser to get new archive name...");
File file = fileChooser.promptUserForFile("New_Archive"); File file = fileChooser.promptUserForFile("New_Archive");
fileChooser.dispose();
if (file == null) { if (file == null) {
Msg.trace(this, "No new archive filename chosen by user - not performing action"); Msg.trace(this, "No new archive filename chosen by user - not performing action");
return; return;
@@ -176,6 +176,8 @@ public class ExportToHeaderAction extends DockingAction {
new DataTypeWriterTask(gTree, programDataTypeMgr, dataTypeList, handler, file), new DataTypeWriterTask(gTree, programDataTypeMgr, dataTypeList, handler, file),
gTree); gTree);
} }
fileChooser.dispose();
} }
private class DataTypeWriterTask extends Task { private class DataTypeWriterTask extends Task {
@@ -209,8 +211,9 @@ public class ExportToHeaderAction extends DockingAction {
finally { finally {
writer.close(); writer.close();
} }
plugin.getTool().setStatusInfo( plugin.getTool()
"Successfully exported data type(s) to " + file.getAbsolutePath()); .setStatusInfo(
"Successfully exported data type(s) to " + file.getAbsolutePath());
} }
catch (CancelledException e) { catch (CancelledException e) {
// user cancelled; ignore // user cancelled; ignore
@@ -67,6 +67,7 @@ public class OpenArchiveAction extends DockingAction {
DataTypeManagerHandler manager = plugin.getDataTypeManagerHandler(); DataTypeManagerHandler manager = plugin.getDataTypeManagerHandler();
File file = fileChooser.getSelectedFile(); File file = fileChooser.getSelectedFile();
fileChooser.dispose();
if (file == null) { if (file == null) {
return; return;
} }
@@ -119,7 +119,7 @@ public class ArchiveUtils {
ArchiveFileChooser fileChooser = new ArchiveFileChooser(component); ArchiveFileChooser fileChooser = new ArchiveFileChooser(component);
String archiveName = archive.getName(); String archiveName = archive.getName();
File file = fileChooser.promptUserForFile(archiveName); File file = fileChooser.promptUserForFile(archiveName);
fileChooser.dispose();
if (file == null) { if (file == null) {
return null; return null;
} }
@@ -73,8 +73,6 @@ public class DataTypeManagerHandler {
private Set<String> knownOpenFileArchiveNames = new HashSet<>(); private Set<String> knownOpenFileArchiveNames = new HashSet<>();
private Map<UniversalID, InvalidFileArchive> invalidArchives = new HashMap<>(); private Map<UniversalID, InvalidFileArchive> invalidArchives = new HashMap<>();
private DataTreeDialog dataTreeSaveDialog;
private CreateDataTypeArchiveDataTreeDialog dataTreeCreateDialog;
private boolean treeDialogCancelled = false; private boolean treeDialogCancelled = false;
private DomainFileFilter createArchiveFileFilter; private DomainFileFilter createArchiveFileFilter;
@@ -1409,77 +1407,74 @@ public class DataTypeManagerHandler {
} }
private DataTreeDialog getSaveDialog() { private DataTreeDialog getSaveDialog() {
if (dataTreeSaveDialog == null) { DataTreeDialog dialog =
new DataTreeDialog(null, "Save As", DataTreeDialog.SAVE, createArchiveFileFilter);
ActionListener listener = event -> { ActionListener listener = event -> {
DomainFolder folder = dataTreeSaveDialog.getDomainFolder(); DomainFolder folder = dialog.getDomainFolder();
String newName = dataTreeSaveDialog.getNameText(); String newName = dialog.getNameText();
if (newName.length() == 0) { if (newName.length() == 0) {
dataTreeSaveDialog.setStatusText("Please enter a name"); dialog.setStatusText("Please enter a name");
return; return;
} }
else if (folder == null) { else if (folder == null) {
dataTreeSaveDialog.setStatusText("Please select a folder"); dialog.setStatusText("Please select a folder");
return; return;
} }
DomainFile file = folder.getFile(newName); DomainFile file = folder.getFile(newName);
if (file != null && file.isReadOnly()) { if (file != null && file.isReadOnly()) {
dataTreeSaveDialog.setStatusText("Read Only. Choose new name/folder"); dialog.setStatusText("Read Only. Choose new name/folder");
} }
else { else {
dataTreeSaveDialog.close(); dialog.close();
treeDialogCancelled = false; treeDialogCancelled = false;
} }
}; };
dataTreeSaveDialog =
new DataTreeDialog(null, "Save As", DataTreeDialog.SAVE, createArchiveFileFilter);
dataTreeSaveDialog.addOkActionListener(listener); dialog.addOkActionListener(listener);
dataTreeSaveDialog dialog.setHelpLocation(new HelpLocation(HelpTopics.PROGRAM, "Save_As_File"));
.setHelpLocation(new HelpLocation(HelpTopics.PROGRAM, "Save_As_File")); return dialog;
}
return dataTreeSaveDialog;
} }
private CreateDataTypeArchiveDataTreeDialog getCreateDialog() { private CreateDataTypeArchiveDataTreeDialog getCreateDialog() {
if (dataTreeCreateDialog == null) {
ActionListener listener = event -> { CreateDataTypeArchiveDataTreeDialog dialog =
DomainFolder folder = dataTreeCreateDialog.getDomainFolder(); new CreateDataTypeArchiveDataTreeDialog(null, "Create",
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",
DataTreeDialog.CREATE, createArchiveFileFilter); DataTreeDialog.CREATE, createArchiveFileFilter);
dataTreeCreateDialog.addOkActionListener(listener); ActionListener listener = event -> {
dataTreeCreateDialog.setHelpLocation( DomainFolder folder = dialog.getDomainFolder();
new HelpLocation(HelpTopics.DATA_MANAGER, "Create_Data_Type_Archive")); String newName = dialog.getNameText();
} if (newName.length() == 0) {
return dataTreeCreateDialog; 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) { public DataTypeManager getDataTypeManager(SourceArchive source) {
@@ -1520,14 +1515,14 @@ public class DataTypeManagerHandler {
return true; return true;
} }
catch (DuplicateNameException e) { catch (DuplicateNameException e) {
dataTreeCreateDialog.setStatusText("Duplicate Name: " + e.getMessage()); setStatusText("Duplicate Name: " + e.getMessage());
} }
catch (InvalidNameException e) { catch (InvalidNameException e) {
dataTreeCreateDialog.setStatusText("Invalid Name: " + e.getMessage()); setStatusText("Invalid Name: " + e.getMessage());
} }
catch (IOException e) { catch (IOException e) {
dataTreeCreateDialog.setStatusText("Unexpected IOException!"); setStatusText("Unexpected IOException!");
Msg.showError(null, dataTreeCreateDialog.getComponent(), "Unexpected Exception", Msg.showError(null, getComponent(), "Unexpected Exception",
e.getMessage(), e); e.getMessage(), e);
} }
@@ -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;
}
}
@@ -219,7 +219,6 @@ public class DataWindowPlugin extends ProgramPlugin implements DomainObjectListe
filterAction.addType(type.getDisplayName()); filterAction.addType(type.getDisplayName());
} }
filterAction.selectTypes(selectedList); filterAction.selectTypes(selectedList);
filterAction.repaint();
provider.reload(); provider.reload();
} }
} }
@@ -52,8 +52,6 @@ class FilterAction extends ToggleDockingAction {
private boolean viewMode = false; private boolean viewMode = false;
private boolean selectionMode = false; private boolean selectionMode = false;
private FilterDialog dialog;
private static class SortMapComparatorASC implements Comparator<String> { private static class SortMapComparatorASC implements Comparator<String> {
@Override @Override
@@ -82,10 +80,7 @@ class FilterAction extends ToggleDockingAction {
@Override @Override
public void actionPerformed(ActionContext context) { public void actionPerformed(ActionContext context) {
if (dialog == null) { FilterDialog dialog = new FilterDialog();
dialog = new FilterDialog();
}
dialog.setSelectionEnabled(plugin.getSelection() != null); dialog.setSelectionEnabled(plugin.getSelection() != null);
dialog.updateButtonEnabledState(); dialog.updateButtonEnabledState();
plugin.getTool().showDialog(dialog); plugin.getTool().showDialog(dialog);
@@ -93,19 +88,11 @@ class FilterAction extends ToggleDockingAction {
synchronized void clearTypes() { synchronized void clearTypes() {
typeEnabledMap.clear(); typeEnabledMap.clear();
if (dialog != null) {
dialog.clearTypes();
}
} }
synchronized void addType(String type) { synchronized void addType(String type) {
Boolean bool = new Boolean(!filterEnabled); Boolean bool = !filterEnabled;
typeEnabledMap.put(type, bool); typeEnabledMap.put(type, bool);
if (dialog != null) {
dialog.createCheckBox(type, type, bool.booleanValue());
}
} }
synchronized boolean typeEnabled(String type) { synchronized boolean typeEnabled(String type) {
@@ -137,16 +124,6 @@ class FilterAction extends ToggleDockingAction {
for (String element : list) { for (String element : list) {
typeEnabledMap.put(element, Boolean.TRUE); typeEnabledMap.put(element, Boolean.TRUE);
} }
if (dialog != null) {
dialog.selectTypes(list);
}
}
void repaint() {
if (dialog == null) {
return;
}
dialog.repaint();
} }
boolean getViewMode() { boolean getViewMode() {
@@ -170,7 +147,6 @@ class FilterAction extends ToggleDockingAction {
filterEnabled = false; filterEnabled = false;
viewMode = false; viewMode = false;
selectionMode = false; selectionMode = false;
dialog = null;
setEnabled(false); setEnabled(false);
clearTypes(); clearTypes();
} }
@@ -23,7 +23,7 @@ import javax.swing.*;
import javax.swing.event.DocumentEvent; import javax.swing.event.DocumentEvent;
import javax.swing.event.DocumentListener; import javax.swing.event.DocumentListener;
import docking.DialogComponentProvider; import docking.ReusableDialogComponentProvider;
import docking.action.DockingAction; import docking.action.DockingAction;
import docking.widgets.checkbox.GCheckBox; import docking.widgets.checkbox.GCheckBox;
import docking.widgets.label.GDLabel; import docking.widgets.label.GDLabel;
@@ -39,7 +39,7 @@ import ghidra.util.table.*;
import ghidra.util.table.actions.MakeProgramSelectionAction; import ghidra.util.table.actions.MakeProgramSelectionAction;
import ghidra.util.task.Task; 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 int DEFAULT_MINIMUM_TABLE_SIZE = 3;
private static final String DIALOG_NAME = "Search For Address Tables"; private static final String DIALOG_NAME = "Search For Address Tables";

Some files were not shown because too many files have changed in this diff Show More