diff --git a/Ghidra/Debug/Debugger-rmi-trace/src/main/java/ghidra/app/plugin/core/debug/gui/tracermi/launcher/AbstractTraceRmiLaunchOpinion.java b/Ghidra/Debug/Debugger-rmi-trace/src/main/java/ghidra/app/plugin/core/debug/gui/tracermi/launcher/AbstractTraceRmiLaunchOpinion.java index def81a2db9..e889ca5348 100644 --- a/Ghidra/Debug/Debugger-rmi-trace/src/main/java/ghidra/app/plugin/core/debug/gui/tracermi/launcher/AbstractTraceRmiLaunchOpinion.java +++ b/Ghidra/Debug/Debugger-rmi-trace/src/main/java/ghidra/app/plugin/core/debug/gui/tracermi/launcher/AbstractTraceRmiLaunchOpinion.java @@ -34,7 +34,8 @@ public abstract class AbstractTraceRmiLaunchOpinion implements TraceRmiLaunchOpi String pluginName = PluginUtils.getPluginNameFromClass(TraceRmiLauncherServicePlugin.class); options.registerOption(TraceRmiLauncherServicePlugin.OPTION_NAME_SCRIPT_PATHS, OptionType.STRING_TYPE, "", new HelpLocation(pluginName, "options"), - "Paths to search for user-created debugger launchers", new ScriptPathsPropertyEditor()); + "Paths to search for user-created debugger launchers", + () -> new ScriptPathsPropertyEditor()); } @Override diff --git a/Ghidra/Debug/ProposedUtils/src/main/java/ghidra/framework/options/AutoOptions.java b/Ghidra/Debug/ProposedUtils/src/main/java/ghidra/framework/options/AutoOptions.java index 498151adfe..20569ee7c8 100644 --- a/Ghidra/Debug/ProposedUtils/src/main/java/ghidra/framework/options/AutoOptions.java +++ b/Ghidra/Debug/ProposedUtils/src/main/java/ghidra/framework/options/AutoOptions.java @@ -27,6 +27,7 @@ import ghidra.framework.options.annotation.*; import ghidra.framework.plugintool.Plugin; import ghidra.framework.plugintool.PluginTool; import ghidra.util.HelpLocation; +import ghidra.util.SystemUtilities; public interface AutoOptions { @@ -148,7 +149,7 @@ public interface AutoOptions { String description = annotation.description(); Class extends PropertyEditor> editorClass = annotation.editor(); final PropertyEditor editor; - if (editorClass == PropertyEditor.class) { + if (editorClass == PropertyEditor.class || SystemUtilities.isInHeadlessMode()) { editor = null; } else { @@ -169,16 +170,16 @@ public interface AutoOptions { else if ( is font option ) { // Note: there is no font value to check against for fonts in the new Theme system. - // If annotation fonts are needed, then they should be bound by String id. Likely, - // annotation fonts are not needed now that have themes. We also probably no - // longer need annotation colors either. + // If annotation fonts are needed, then they should be bound by String id. Likely, + // annotation fonts are not needed now that have themes. We also probably no + // longer need annotation colors either. options.registerThemeFontBinding(description, fontId, help, description); } */ else { options.registerOption(key.name, type, defaultValue, help, description, - editor); + () -> editor); // TODO: Wish Ghidra would do this upon any option registration options.putObject(key.name, defaultValue, type); } diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/analysis/ApplyDataArchiveAnalyzer.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/analysis/ApplyDataArchiveAnalyzer.java index c8ee55cbb5..d41425b6df 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/analysis/ApplyDataArchiveAnalyzer.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/analysis/ApplyDataArchiveAnalyzer.java @@ -127,13 +127,13 @@ public class ApplyDataArchiveAnalyzer extends AbstractAnalyzer { options.registerOption(OPTION_NAME_ARCHIVE_CHOOSER, OptionType.STRING_TYPE, CHOOSER_AUTO_DETECT, null, OPTION_DESCRIPTION_ARCHIVE_CHOOSER, - new StringWithChoicesEditor(chooserList)); + () -> new StringWithChoicesEditor(chooserList)); options.registerOption(OPTION_NAME_GDT_FILEPATH, OptionType.FILE_TYPE, null, null, OPTION_DESCRIPTION_GDT_FILEPATH, - new FileChooserEditor(FileDataTypeManager.GDT_FILEFILTER)); + () -> new FileChooserEditor(FileDataTypeManager.GDT_FILEFILTER)); options.registerOption(OPTION_NAME_PROJECT_PATH, OptionType.STRING_TYPE, null, null, - OPTION_DESCRIPTION_PROJECT_PATH, new ProjectPathChooserEditor( + OPTION_DESCRIPTION_PROJECT_PATH, () -> new ProjectPathChooserEditor( "Choose Data Type Archive", DATATYPEARCHIVE_PROJECT_FILTER)); } diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/analysis/AutoAnalysisPlugin.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/analysis/AutoAnalysisPlugin.java index eb6d4a01fa..14b2e6b7a3 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/analysis/AutoAnalysisPlugin.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/analysis/AutoAnalysisPlugin.java @@ -256,7 +256,7 @@ public class AutoAnalysisPlugin extends Plugin implements AutoAnalysisManagerLis analysisMgr.addListener(this); Options options = program.getOptions(Program.ANALYSIS_PROPERTIES); - options.registerOptionsEditor(new AnalysisOptionsEditor(program)); + options.registerOptionsEditor(() -> new AnalysisOptionsEditor(program)); options.setOptionsHelpLocation( new HelpLocation("AutoAnalysisPlugin", "Auto_Analysis_Option")); } @@ -264,7 +264,8 @@ public class AutoAnalysisPlugin extends Plugin implements AutoAnalysisManagerLis private void programActivated(Program program) { program.getOptions(StoredAnalyzerTimes.OPTIONS_LIST) .registerOption(StoredAnalyzerTimes.OPTION_NAME, OptionType.CUSTOM_TYPE, null, null, - "Cumulative analysis task times", new StoredAnalyzerTimesPropertyEditor()); + "Cumulative analysis task times", + () -> new StoredAnalyzerTimesPropertyEditor()); } diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/analysis/rust/RustDemanglerAnalyzer.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/analysis/rust/RustDemanglerAnalyzer.java index 3255dd2369..534a781ff4 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/analysis/rust/RustDemanglerAnalyzer.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/analysis/rust/RustDemanglerAnalyzer.java @@ -15,8 +15,7 @@ */ package ghidra.app.plugin.core.analysis.rust; -import java.beans.PropertyChangeEvent; -import java.beans.PropertyChangeListener; +import java.beans.*; import java.util.Arrays; import docking.options.editor.BooleanEditor; @@ -90,24 +89,14 @@ public class RustDemanglerAnalyzer extends AbstractDemanglerAnalyzer { options.registerOption(OPTION_NAME_DEMANGLE_USE_KNOWN_PATTERNS, demangleOnlyKnownPatterns, help, OPTION_DESCRIPTION_USE_KNOWN_PATTERNS); - BooleanEditor deprecatedEditor = null; - FormatEditor formatEditor = null; - if (!SystemUtilities.isInHeadlessMode()) { - // Only add the custom options editor when not headless. The custom editor allows - // the list of choices presented to the user to change depending on the state of the - // useDeprecatedDemangler flag. - deprecatedEditor = new BooleanEditor(); - deprecatedEditor.setValue(Boolean.valueOf(useDeprecatedDemangler)); - formatEditor = new FormatEditor(demanglerFormat, deprecatedEditor); - deprecatedEditor.addPropertyChangeListener(formatEditor); - } + RustOptionsEditor optionsEditor = new RustOptionsEditor(); options.registerOption(OPTION_NAME_USE_DEPRECATED_DEMANGLER, OptionType.BOOLEAN_TYPE, useDeprecatedDemangler, help, OPTION_DESCRIPTION_DEPRECATED_DEMANGLER, - deprecatedEditor); + () -> optionsEditor.getDeprecatedNameEditor()); options.registerOption(OPTION_NAME_DEMANGLER_FORMAT, OptionType.ENUM_TYPE, demanglerFormat, - help, OPTION_DESCRIPTION_DEMANGLER_FORMAT, formatEditor); + help, OPTION_DESCRIPTION_DEMANGLER_FORMAT, () -> optionsEditor.getFormatEditor()); } @Override @@ -162,6 +151,45 @@ public class RustDemanglerAnalyzer extends AbstractDemanglerAnalyzer { super.apply(program, address, demangledVariable, options, log, monitor); } +//================================================================================================== +// Inner Classes +//================================================================================================== + + // We only use the editor when not headless, since GUI code in headless will throw an exception. + // Further, the options below have a relationship, so we need to build them together. + // The format editor's list of choices presented to the user will change depending on the state + // of the deprecated boolean editor. + private class RustOptionsEditor { + + private BooleanEditor deprecatedEditor; + private FormatEditor formatEditor; + + private void lazyInit() { + if (SystemUtilities.isInHeadlessMode()) { + return; // the editor should not be requested in headless mode + } + + if (deprecatedEditor != null) { + return; // already loaded + } + + deprecatedEditor = new BooleanEditor(); + deprecatedEditor.setValue(Boolean.valueOf(useDeprecatedDemangler)); + formatEditor = new FormatEditor(demanglerFormat, deprecatedEditor); + deprecatedEditor.addPropertyChangeListener(formatEditor); + } + + PropertyEditor getDeprecatedNameEditor() { + lazyInit(); + return deprecatedEditor; + } + + PropertyEditor getFormatEditor() { + lazyInit(); + return formatEditor; + } + } + private static class FormatEditor extends EnumEditor implements PropertyChangeListener { private final FormatSelector selector; diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/blockmodel/BlockModelServicePlugin.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/blockmodel/BlockModelServicePlugin.java index 9f10a4a2f2..88237e29d5 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/blockmodel/BlockModelServicePlugin.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/blockmodel/BlockModelServicePlugin.java @@ -37,11 +37,11 @@ import ghidra.util.datastruct.WeakDataStructureFactory; import ghidra.util.datastruct.WeakSet; import ghidra.util.exception.NotFoundException; -/** +/** * Provides a service for tracking the selected basic/subroutine block models for a tool. * Methods are provided for obtaining an instance of the active or arbitrary block model. - * A new model instance is always provided since the internal cache will quickly become - * stale based upon program changes. The current model implementations do not handle + * A new model instance is always provided since the internal cache will quickly become + * stale based upon program changes. The current model implementations do not handle * program changes which would invalidate the cached blocks stored within the model. * * A single basic/sub model list is maintained since it is possible that some uses @@ -111,9 +111,12 @@ public class BlockModelServicePlugin extends ProgramPlugin // Install model selection option in Tool panel options = tool.getOptions(ToolConstants.TOOL_OPTIONS); - editor = new StringWithChoicesEditor(availableModelNames); options.registerOption(SUB_OPTION, OptionType.STRING_TYPE, selectedSubroutineModelName, - null, "The default subroutine model used when creating call graphs.", editor); + null, "The default subroutine model used when creating call graphs.", + () -> { + editor = new StringWithChoicesEditor(availableModelNames); + return editor; + }); setPreferedModel(options); updateModelOptions(); options.addOptionsChangeListener(this); @@ -168,7 +171,9 @@ public class BlockModelServicePlugin extends ProgramPlugin modelUpdateInProgress = true; try { - editor.setChoices(availableModelNames); + if (editor != null) { + editor.setChoices(availableModelNames); + } options.setString(SUB_OPTION, selectedSubroutineModelName); } finally { diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/codebrowser/AbstractCodeBrowserPlugin.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/codebrowser/AbstractCodeBrowserPlugin.java index 9051c072c4..ad84a64bf2 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/codebrowser/AbstractCodeBrowserPlugin.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/codebrowser/AbstractCodeBrowserPlugin.java @@ -98,7 +98,7 @@ public abstract class AbstractCodeBrowserPlugin
ex ToolOptions displayOptions = tool.getOptions(GhidraOptions.CATEGORY_BROWSER_DISPLAY); ToolOptions fieldOptions = tool.getOptions(GhidraOptions.CATEGORY_BROWSER_FIELDS); - displayOptions.registerOptionsEditor(new ListingDisplayOptionsEditor(displayOptions)); + displayOptions.registerOptionsEditor(() -> new ListingDisplayOptionsEditor(displayOptions)); displayOptions.setOptionsHelpLocation( new HelpLocation(getName(), GhidraOptions.CATEGORY_BROWSER_DISPLAY)); fieldOptions.setOptionsHelpLocation( @@ -616,7 +616,7 @@ public abstract class AbstractCodeBrowserPlugin
ex
options.registerOption(ManualViewerCommandWrappedOption.MANUAL_VIEWER_OPTIONS,
OptionType.CUSTOM_TYPE,
ManualViewerCommandWrappedOption.getDefaultBrowserLoaderOptions(), helpLocation,
- "Options for running manual viewer", new ManualViewerCommandEditor());
+ "Options for running manual viewer", () -> new ManualViewerCommandEditor());
}
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 ff4bf7ffd7..f6c6d9a0b0 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
@@ -606,7 +606,7 @@ public class ProgramManagerPlugin extends Plugin implements ProgramManager, Opti
PropertyEditor editor = options.getPropertyEditor(filePropertyName);
if (editor == null && options.getType(filePropertyName) == OptionType.STRING_TYPE) {
options.registerOption(filePropertyName, OptionType.STRING_TYPE, null, null, null,
- new StringBasedFileEditor());
+ () -> new StringBasedFileEditor());
}
}
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/viewer/field/AddressFieldFactory.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/viewer/field/AddressFieldFactory.java
index 89b1d31480..9d29e56038 100644
--- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/viewer/field/AddressFieldFactory.java
+++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/viewer/field/AddressFieldFactory.java
@@ -15,7 +15,6 @@
*/
package ghidra.app.util.viewer.field;
-import java.beans.PropertyEditor;
import java.math.BigInteger;
import docking.widgets.fieldpanel.field.*;
@@ -47,7 +46,6 @@ public class AddressFieldFactory extends FieldFactory {
private boolean padZeros;
private int minHexDigits;
private boolean rightJustify;
- private PropertyEditor addressFieldOptionsEditor = new AddressFieldOptionsPropertyEditor();
/**
* Default Constructor
@@ -74,7 +72,7 @@ public class AddressFieldFactory extends FieldFactory {
fieldOptions.registerOption(ADDRESS_DISPLAY_OPTIONS_NAME, OptionType.CUSTOM_TYPE,
new AddressFieldOptionsWrappedOption(), helpLoc, "Adjusts the Address Field display",
- addressFieldOptionsEditor);
+ () -> new AddressFieldOptionsPropertyEditor());
CustomOption customOption =
fieldOptions.getCustomOption(ADDRESS_DISPLAY_OPTIONS_NAME, null);
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/viewer/field/ArrayValuesFieldFactory.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/viewer/field/ArrayValuesFieldFactory.java
index 3f83282ad9..a467b26514 100644
--- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/viewer/field/ArrayValuesFieldFactory.java
+++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/viewer/field/ArrayValuesFieldFactory.java
@@ -15,7 +15,6 @@
*/
package ghidra.app.util.viewer.field;
-import java.beans.PropertyEditor;
import java.math.BigInteger;
import docking.widgets.fieldpanel.field.*;
@@ -35,7 +34,6 @@ import ghidra.util.exception.AssertException;
public class ArrayValuesFieldFactory extends FieldFactory {
public static final String FIELD_NAME = "Array Values";
private int valuesPerLine;
- private PropertyEditor arrayOptionsEditor = new ArrayElementPropertyEditor();
public ArrayValuesFieldFactory() {
super(FIELD_NAME);
@@ -66,7 +64,7 @@ public class ArrayValuesFieldFactory extends FieldFactory {
// we need to install a custom editor that allows us to edit a group of related options
fieldOptions.registerOption(FormatManager.ARRAY_DISPLAY_OPTIONS, OptionType.CUSTOM_TYPE,
new ArrayElementWrappedOption(), null, FormatManager.ARRAY_DISPLAY_DESCRIPTION,
- arrayOptionsEditor);
+ () -> new ArrayElementPropertyEditor());
CustomOption wrappedOption = fieldOptions.getCustomOption(
FormatManager.ARRAY_DISPLAY_OPTIONS, new ArrayElementWrappedOption());
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/viewer/field/BrowserCodeUnitFormatOptions.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/viewer/field/BrowserCodeUnitFormatOptions.java
index 9b0993ece7..83e302d438 100644
--- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/viewer/field/BrowserCodeUnitFormatOptions.java
+++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/viewer/field/BrowserCodeUnitFormatOptions.java
@@ -58,8 +58,8 @@ public class BrowserCodeUnitFormatOptions extends CodeUnitFormatOptions
GhidraOptions.OPERAND_GROUP_TITLE + Options.DELIMITER + "Always Show Primary Reference";
/**
- * Option for whether to follow referenced pointers, for read or indirect reference types,
- * to show pointer's referenced symbol instead of symbol at pointer. When applied the
+ * Option for whether to follow referenced pointers, for read or indirect reference types,
+ * to show pointer's referenced symbol instead of symbol at pointer. When applied the
* resulting label will be preceded by ->.
*/
private final static String FOLLOW_POINTER_REFERENCE_MARKUP_OPTION =
@@ -98,7 +98,7 @@ public class BrowserCodeUnitFormatOptions extends CodeUnitFormatOptions
* This constructor must be used by the field factory since an OptionsService may
* not obtainable at the time they are constructed.
* @param fieldOptions field options
- * @param autoUpdate if true format will auto update if associated options are changed, in
+ * @param autoUpdate if true format will auto update if associated options are changed, in
* addition any listeners will be notified when this format is updated.
*/
BrowserCodeUnitFormatOptions(ToolOptions fieldOptions, boolean autoUpdate) {
@@ -110,7 +110,7 @@ public class BrowserCodeUnitFormatOptions extends CodeUnitFormatOptions
if (!exists) {
fieldOptions.registerOption(NAMESPACE_OPTIONS, OptionType.CUSTOM_TYPE,
new NamespaceWrappedOption(), null, NAMESPACE_OPTIONS_DESCRIPTIONS,
- new NamespacePropertyEditor());
+ () -> new NamespacePropertyEditor());
HelpLocation hl = new HelpLocation("CodeBrowserPlugin", "Operands_Field");
fieldOptions.getOptions(GhidraOptions.OPERAND_GROUP_TITLE).setOptionsHelpLocation(hl);
@@ -165,7 +165,7 @@ public class BrowserCodeUnitFormatOptions extends CodeUnitFormatOptions
private void updateFormat() {
fieldOptions.registerOption(NAMESPACE_OPTIONS, OptionType.CUSTOM_TYPE,
new NamespaceWrappedOption(), null, NAMESPACE_OPTIONS_DESCRIPTIONS,
- new NamespacePropertyEditor());
+ () -> new NamespacePropertyEditor());
CustomOption customOption =
fieldOptions.getCustomOption(NAMESPACE_OPTIONS, new NamespaceWrappedOption());
if (!(customOption instanceof NamespaceWrappedOption)) {
@@ -240,9 +240,9 @@ public class BrowserCodeUnitFormatOptions extends CodeUnitFormatOptions
}
/**
- * Get current state of the Follow Referenced Pointers option.
- * @return true if operand pointer read of indirect references will be followed and
- * non-dynamic pointer referenced symbol will be rendered in place of pointer label.
+ * Get current state of the Follow Referenced Pointers option.
+ * @return true if operand pointer read of indirect references will be followed and
+ * non-dynamic pointer referenced symbol will be rendered in place of pointer label.
*/
public boolean followReferencedPointers() {
return followReferencedPointers;
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/viewer/field/EolCommentFieldFactory.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/viewer/field/EolCommentFieldFactory.java
index b457ea1841..884f8a6c45 100644
--- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/viewer/field/EolCommentFieldFactory.java
+++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/viewer/field/EolCommentFieldFactory.java
@@ -16,7 +16,6 @@
package ghidra.app.util.viewer.field;
import java.awt.Color;
-import java.beans.PropertyEditor;
import java.math.BigInteger;
import java.util.ArrayList;
import java.util.List;
@@ -67,7 +66,6 @@ public class EolCommentFieldFactory extends FieldFactory {
private int refRepeatableCommentStyle;
private EolExtraCommentsOption extraCommentsOption = new EolExtraCommentsOption();
- private PropertyEditor extraCommmentsEditor = new EolExtraCommentsPropertyEditor();
// The codeUnitFormatOptions is used to monitor "follow pointer..." option to avoid duplication
// of data within auto-comment. We don't bother adding a listener to kick the model since this
@@ -126,7 +124,7 @@ public class EolCommentFieldFactory extends FieldFactory {
private void setupAutoCommentOptions(Options fieldOptions, HelpLocation hl) {
fieldOptions.registerOption(EXTRA_COMMENT_KEY, OptionType.CUSTOM_TYPE,
new EolExtraCommentsOption(), hl, "The group of auto comment options",
- extraCommmentsEditor);
+ () -> new EolExtraCommentsPropertyEditor());
CustomOption customOption = fieldOptions.getCustomOption(EXTRA_COMMENT_KEY, null);
if (!(customOption instanceof EolExtraCommentsOption)) {
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/viewer/field/FileOffsetFieldFactory.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/viewer/field/FileOffsetFieldFactory.java
index 07a2c376dd..5a7280f49b 100644
--- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/viewer/field/FileOffsetFieldFactory.java
+++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/viewer/field/FileOffsetFieldFactory.java
@@ -15,7 +15,6 @@
*/
package ghidra.app.util.viewer.field;
-import java.beans.PropertyEditor;
import java.math.BigInteger;
import docking.widgets.fieldpanel.field.*;
@@ -49,8 +48,6 @@ public class FileOffsetFieldFactory extends FieldFactory {
private boolean showFilename;
private boolean useHex;
- private PropertyEditor fileOffsetFieldOptionsEditor =
- new FileOffsetFieldOptionsPropertyEditor();
/**
* Default Constructor
@@ -77,7 +74,8 @@ public class FileOffsetFieldFactory extends FieldFactory {
fieldOptions.registerOption(FILE_OFFSET_DISPLAY_OPTIONS_NAME, OptionType.CUSTOM_TYPE,
new FileOffsetFieldOptionsWrappedOption(), helpLoc,
- "Adjusts the File Offset Field display", fileOffsetFieldOptionsEditor);
+ "Adjusts the File Offset Field display",
+ () -> new FileOffsetFieldOptionsPropertyEditor());
CustomOption customOption =
fieldOptions.getCustomOption(FILE_OFFSET_DISPLAY_OPTIONS_NAME, null);
@@ -97,7 +95,8 @@ public class FileOffsetFieldFactory extends FieldFactory {
@Override
public FieldFactory newInstance(FieldFormatModel formatModel,
- ListingHighlightProvider highlightProvider, ToolOptions options, ToolOptions fieldOptions) {
+ ListingHighlightProvider highlightProvider, ToolOptions options,
+ ToolOptions fieldOptions) {
return new FileOffsetFieldFactory(formatModel, highlightProvider, options, fieldOptions);
}
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/viewer/field/LabelFieldFactory.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/viewer/field/LabelFieldFactory.java
index 03a0155cd1..cd5d7b0ee3 100644
--- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/viewer/field/LabelFieldFactory.java
+++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/viewer/field/LabelFieldFactory.java
@@ -15,7 +15,6 @@
*/
package ghidra.app.util.viewer.field;
-import java.beans.PropertyEditor;
import java.math.BigInteger;
import java.util.*;
@@ -60,8 +59,6 @@ public class LabelFieldFactory extends FieldFactory {
private Icon ANCHOR_ICON =
new MultiIcon(EMPTY_ICON, new GIcon("icon.base.util.viewer.fieldfactory.label"));
- private PropertyEditor namespaceOptionsEditor = new NamespacePropertyEditor();
-
private boolean displayFunctionLabel;
private boolean displayLocalNamespace;
private boolean displayNonLocalNamespace;
@@ -107,7 +104,7 @@ public class LabelFieldFactory extends FieldFactory {
// we need to install a custom editor that allows us to edit a group of related options
fieldOptions.registerOption(NAMESPACE_OPTIONS, OptionType.CUSTOM_TYPE,
new NamespaceWrappedOption(), null, "Adjusts the Label Field namespace display",
- namespaceOptionsEditor);
+ () -> new NamespacePropertyEditor());
CustomOption wrappedOption =
fieldOptions.getCustomOption(NAMESPACE_OPTIONS, new NamespaceWrappedOption());
if (!(wrappedOption instanceof NamespaceWrappedOption)) {
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/viewer/field/XRefFieldFactory.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/viewer/field/XRefFieldFactory.java
index a7b127977c..06260f24ad 100644
--- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/viewer/field/XRefFieldFactory.java
+++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/viewer/field/XRefFieldFactory.java
@@ -17,7 +17,6 @@ package ghidra.app.util.viewer.field;
import java.awt.Color;
import java.awt.FontMetrics;
-import java.beans.PropertyEditor;
import java.math.BigInteger;
import java.util.*;
import java.util.Map.Entry;
@@ -75,8 +74,6 @@ public class XRefFieldFactory extends FieldFactory {
static final String GROUP_BY_FUNCTION_KEY =
GROUP_TITLE + Options.DELIMITER + "Group by Function";
- private PropertyEditor namespaceOptionsEditor = new NamespacePropertyEditor();
-
protected String delim = DELIMITER;
protected boolean displayBlockName;
protected boolean groupByFunction;
@@ -168,7 +165,7 @@ public class XRefFieldFactory extends FieldFactory {
// we need to install a custom editor that allows us to edit a group of related options
fieldOptions.registerOption(NAMESPACE_OPTIONS_KEY, OptionType.CUSTOM_TYPE,
new NamespaceWrappedOption(), new HelpLocation("CodeBrowserPlugin", "XREFs_Field"),
- "Adjusts the XREFs Field namespace display", namespaceOptionsEditor);
+ "Adjusts the XREFs Field namespace display", () -> new NamespacePropertyEditor());
CustomOption customOption = fieldOptions.getCustomOption(NAMESPACE_OPTIONS_KEY, null);
if (!(customOption instanceof NamespaceWrappedOption)) {
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/viewer/format/FormatManager.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/viewer/format/FormatManager.java
index 33c8111386..ff085e412a 100644
--- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/viewer/format/FormatManager.java
+++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/viewer/format/FormatManager.java
@@ -71,7 +71,7 @@ public class FormatManager implements OptionsChangeListener {
TemplateSimplifier templateSimplifier;
// NOTE: Unused custom format code was removed. The custom format code last existed in
- // commit #204e7892bf2f110ebb05ca4beee3fe5b397f88c9.
+ // commit #204e7892bf2f110ebb05ca4beee3fe5b397f88c9.
/**
* Constructs a new FormatManager.
@@ -100,7 +100,7 @@ public class FormatManager implements OptionsChangeListener {
private void getArrayDisplayOptions(Options options) {
options.registerOption(ARRAY_DISPLAY_OPTIONS, OptionType.CUSTOM_TYPE,
new ArrayElementWrappedOption(), null, ARRAY_DISPLAY_DESCRIPTION,
- new ArrayElementPropertyEditor());
+ () -> new ArrayElementPropertyEditor());
CustomOption option = options.getCustomOption(ARRAY_DISPLAY_OPTIONS, null);
if (option instanceof ArrayElementWrappedOption) {
ArrayElementWrappedOption arrayOption = (ArrayElementWrappedOption) option;
@@ -174,7 +174,7 @@ public class FormatManager implements OptionsChangeListener {
/**
* Returns the total number of model in the format manager.
- * @return the total number of model in the format manager
+ * @return the total number of model in the format manager
*/
public int getNumModels() {
return NUM_MODELS;
@@ -200,7 +200,7 @@ public class FormatManager implements OptionsChangeListener {
/**
* Returns the format model for the plate field.
- * @return the format model for the plate field
+ * @return the format model for the plate field
*/
public FieldFormatModel getPlateFormat() {
return models[FieldFormatModel.PLATE];
@@ -279,7 +279,7 @@ public class FormatManager implements OptionsChangeListener {
/**
* Returns the Options used for field specific properties.
- * @return the Options used for field specific properties
+ * @return the Options used for field specific properties
*/
public ToolOptions getFieldOptions() {
return fieldOptions;
@@ -847,7 +847,7 @@ public class FormatManager implements OptionsChangeListener {
}
/**
- * Gets all {@link ListingHighlightProvider}s installed on this FormatManager via the
+ * Gets all {@link ListingHighlightProvider}s installed on this FormatManager via the
* {@link #addHighlightProvider(ListingHighlightProvider)}.
*
* @return all {@link ListingHighlightProvider}s installed on this FormatManager.
@@ -930,12 +930,12 @@ public class FormatManager implements OptionsChangeListener {
public Highlight[] createHighlights(String text, ListingField field, int cursorTextOffset) {
//
- // Gather and use all other registered providers.
- //
+ // Gather and use all other registered providers.
+ //
// Note: we loop backwards here as a hacky method to make sure that the middle-mouse
- // highlighter runs last and is thus painted above other highlights. This
- // works because the middle-mouse highlighter is installed before any other
- // highlighters.
+ // highlighter runs last and is thus painted above other highlights. This
+ // works because the middle-mouse highlighter is installed before any other
+ // highlighters.
List
* Note, this method should not be used for
* colors and font as doing so will result in those colors and fonts becoming disconnected
- * to the current theme. Instead use
+ * to the current theme. Instead use
*
* {@link #registerThemeColorBinding(String, String, HelpLocation, String)} or
* {@link #registerThemeFontBinding(String, String, HelpLocation, String)}.
@@ -133,7 +136,7 @@ public interface Options {
*
* Note, this method should not be used for
* colors and font as doing so will result in those colors and fonts becoming disconnected
- * to the current theme. Instead use
+ * to the current theme. Instead use
* {@link #registerThemeColorBinding(String, String, HelpLocation, String)} or
* {@link #registerThemeFontBinding(String, String, HelpLocation, String)}.
*
@@ -153,9 +156,16 @@ public interface Options {
*
* Note, this method should not be used for
* colors and font as doing so will result in those colors and fonts becoming disconnected
- * to the current theme. Instead use
+ * to the current theme. Instead use
* {@link #registerThemeColorBinding(String, String, HelpLocation, String)} or
* {@link #registerThemeFontBinding(String, String, HelpLocation, String)}.
+ *
+ * Note: we use a supplier of a custom editor, instead of a custom editor, to avoid
+ * creating {@link PropertyEditor}s until needed. This allows us to use the same API in both
+ * GUI mode and headless mode. If GUI property editors are created in headless mode, exceptions
+ * may be thrown. This API will not use the supplier when in headless mode, this avoiding the
+ * creation of GUI components. For this to work correctly, clients using custom property
+ * editors must defer construction of the editor until the supplier is called.
*
* @param optionName the name of the option being registered.
* @param type the OptionType for this options.
@@ -163,12 +173,37 @@ public interface Options {
* value may be null.
* @param help the HelpLocation for this option.
* @param description a description of the option.
- * @param editor an optional custom editor for this property. Note if the option is a custom option,
- * then the property editor can't be null;
+ * @param editor an optional supplier of a custom editor for this property. Note if the option
+ * is a custom option, then the property editor can't be null;
* @throws IllegalStateException if the options is a custom option and the editor is null.
*/
public void registerOption(String optionName, OptionType type, Object defaultValue,
- HelpLocation help, String description, PropertyEditor editor);
+ HelpLocation help, String description, Supplier
+ * Note: we use a supplier of a custom editor, instead of a custom editor, to avoid
+ * creating {@link PropertyEditor}s until needed. This allows us to use the same API in both
+ * GUI mode and headless mode. If GUI property editors are created in headless mode, exceptions
+ * may be thrown. This API will not use the supplier when in headless mode, this avoiding the
+ * creation of GUI components. For this to work correctly, clients using custom property
+ * editors must defer construction of the editor until the supplier is called.
+ * @param editor a supplier for the custom editor panel to be used to edit the options or
+ * sub-group of options.
*/
- public void registerOptionsEditor(OptionsEditor editor);
+ public void registerOptionsEditor(Supplier