Class AbstractProperty
- Direct Known Subclasses:
BooleanProperty,ButtonProperty,CollapsiblePanelProperty,ColorProperty,ComboProperty,DecimalProperty,DirectoryProperty,EnumProperty,FileProperty,FontProperty,HtmlLabelProperty,ImagePanelConfig,IntegerProperty,KeyStrokeProperty,LabelProperty,ListProperty,ListSubsetProperty,LogConsoleTheme,LogoProperty,LongTextProperty,LookAndFeelProperty,MarginsProperty,PanelProperty,PasswordProperty,ShortTextProperty,SliderProperty,WaveformConfig
The goal here is to make managing application preferences easy and consistent across apps. Instead of each application having code to load and save preferences, as well as provide a UI for the user to view and change them, the classes in this package allow applications to just define the preferences by type and name, and then you can use PropertiesManager to handle the loading and saving of them, and PropertiesDialog to handle the UI for them. The burden on the application itself is MUCH lighter.
The naming of preferences is important for organizing preferences into user-visible groups. Every property has a fully-qualified dot-separated name that is used by this package to determine what category a property belongs to. Refer to the constructor for example usages.
Note: I use the terms "property" and "preference" pretty much interchangeably throughout these docs. In hindsight maybe I should have called these "Preferences".
- Since:
- 2024-12-30
- Author:
- scorbo2
-
Field Summary
FieldsModifier and TypeFieldDescriptionprotected Stringstatic final StringIf a property is not explicitly given a category, it will be placed in a default category called "General".static final StringIf a property is not explicitly given a name, it will show up as "(unnamed property)".protected final Stringprotected Stringprotected booleanprotected booleanprotected booleanprotected booleanprotected Marginsprotected Stringprotected Stringprotected String -
Constructor Summary
ConstructorsConstructorDescriptionAbstractProperty(String name, String label) Each property has a fully qualified name that can optionally specify a top-level category and up to one subcategory. -
Method Summary
Modifier and TypeMethodDescriptionaddAllExtraAttributes(Map<String, Object> newAttributes) Adds the map of extra attributes to our existing list.addBottomPadding(int bottom) Will add the specified amount of bottom padding to the generated FormField's margins.Register to receive a change notification when a generated FormField's value is changed by the user.Register to receive a notification when this AbstractProperty instance generates a FormField.addInnerPadding(int inner) Will add the specified amount of inner padding (internal spacing) to the generated FormField's margins.addLeftPadding(int left) Will add the specified amount of left padding to the generated FormField's margins.addPadding(int left, int top, int right, int bottom, int inner) Add the specified padding values to the generated FormField's margins.addRightPadding(int right) Will add the specified amount of right padding to the generated FormField's margins.addTopPadding(int top) Will add the specified amount of top padding to the generated FormField's margins.voidclearExtraAttribute(String name) Removes the value for the named extra attribute.voidRemoves all extra attributes and their associated values from this AbstractProperty.booleanprotected voidfireFormFieldChangedEvent(FormPanel formPanel, FormField field, ActionEvent changeEvent) protected voidfireFormFieldGeneratedEvent(FormField formField) final FormFieldDelegates to generateFormField(null).final FormFieldgenerateFormField(FormPanel formPanel) Generates a FormField instance for this AbstractProperty, depending on our type.protected abstract FormFieldDescendant classes must implement this method to generate a FormField associated with this property.Returns the category name for this property.getExtraAttribute(String name) Returns a named extra attribute's value, if it exists.Returns the fully qualified name of this property as it was passed to the constructor.Returns the optional help text for this property, if any is set, otherwise a blank string.Returns a copy of the margin padding that will be applied to the generated FormField.Returns the human-readable label for this property.Returns the property name without category or subcategory.Returns the subcategory name for this property, if one is defined.inthashCode()booleanMost properties will generate FormField instances that allow user input, so the default value of "true" can be left alone.booleanReports whether this property is currently enabled.booleanReports whether this property is meant to be exposed in the UI.booleanReports whether this property will be editable when shown in the PropertiesDialog.booleanReports whether this property will be visible when added to the PropertiesDialog.abstract voidloadFromFormField(FormField field) Populates this Property's value(s) from the given form field, assuming the field is of the correct type.abstract voidloadFromProps(Properties props) Loads the value(s) for this property from the given Properties instance, overwriting any current value.voidvoidvoidvoidabstract voidsaveToProps(Properties props) Saves the current value(s) of this property to the given Properties instance.setAllExtraAttributes(Map<String, Object> newAttributes) Clears any extra attributes currently held by this AbstractProperty and then accepts the given list of attributes.setEnabled(boolean enable) Setting a property to disabled will prevent this property from appearing in the PropertiesDialog.setExposed(boolean expose) Sets whether this property is to be exposed in the UI.setExtraAttribute(String name, Object value) Set an arbitrary extra attribute to this property.setHelpText(String helpText) Sets optional help text for this property.setInitiallyEditable(boolean initiallyEditable) Set whether this property is to be editable by default when shown on a PropertiesDialog.setInitiallyVisible(boolean initiallyVisible) Sets whether this property is to be visible by default when shown on a PropertiesDialog.setPropertyLabel(String label) Sets or updates the human-readable label for this property.
-
Field Details
-
DEFAULT_CATEGORY
If a property is not explicitly given a category, it will be placed in a default category called "General".- See Also:
-
DEFAULT_PROPERTY_NAME
If a property is not explicitly given a name, it will show up as "(unnamed property)".- See Also:
-
fullyQualifiedName
-
helpText
-
categoryName
-
subCategoryName
-
propertyName
-
propertyLabel
-
isExposed
protected boolean isExposed -
isEnabled
protected boolean isEnabled -
isInitiallyEditable
protected boolean isInitiallyEditable -
isInitiallyVisible
protected boolean isInitiallyVisible -
extraAttributes
-
marginPadding
-
-
Constructor Details
-
AbstractProperty
Each property has a fully qualified name that can optionally specify a top-level category and up to one subcategory. The name should be dot separated to make use of category and subcategory. The format is as follows:[category.[subcategory.]]propertyName
If category name is not specified, a default name of "General" will be used. If subcategory is not specified, a default name of "General" will be used Some examples:
- UI.windowState - creates a property called "windowState" belonging to an implied subcategory of "General" within the "UI" category.
- UI.window.state - creates a property called "state" in the subcategory of "window" within the top-level category of "UI".
- windowState - creates a property called "windowState" in an implied top-level category of "General" with an implied subcategory of "General"
- UI.window.state.isMaximized - creates a property called "state.isMaximized" within the "window" subcategory in the "UI" top-level category. Note that further dots after the second one are basically ignored and are considered part of the property name. So, you can't have sub-sub-categories.
- Parameters:
name- A fully qualified name as described above. If null, will be "(unnamed field)".label- A human-readable label for this field. Largely ignored by this code.
-
-
Method Details
-
getFullyQualifiedName
Returns the fully qualified name of this property as it was passed to the constructor. See also getCategoryName(), getSubCategoryName(), and getPropertyName() to retrieve the individual components of the name separately.- Returns:
- The fully qualified name of this property as it was passed to the constructor.
-
getCategoryName
Returns the category name for this property. If none was supplied to the constructor, then this will return the default category name of "General".- Returns:
- The property's category name.
-
getSubCategoryName
Returns the subcategory name for this property, if one is defined.- Returns:
- The property's subcategory name, or null if there is no subcategory for this property.
-
getPropertyName
Returns the property name without category or subcategory. Most of the time, you probably want to call getFullyQualifiedName() instead of this. For example, for a property named "UI.window.state", this method will return "state".- Returns:
- The bare field name of this property.
-
getPropertyLabel
Returns the human-readable label for this property.- Returns:
- A human-readable label.
-
setPropertyLabel
Sets or updates the human-readable label for this property.- Parameters:
label- The new label value.
-
setExposed
Sets whether this property is to be exposed in the UI. Generally this is set once when the property is created and does not change, as opposed to isEnabled, which can vary at runtime. A field is only visible in the UI if (isExposed && isEnabled).Question: why would I want to mark a property as not exposed? - There may be internal preferences that your app uses that are never shown to the user directly. This might include stuff like storing window state (maximized, screen location, width, height, etc) that would make no sense to show in an application preferences dialog. You can use this method to "hide" a property in the PropertiesDialog while still being able to save and load it via PropertiesManager.
- Parameters:
expose- True to expose this field in PropertiesDialog.
-
isExposed
public boolean isExposed()Reports whether this property is meant to be exposed in the UI. Marking a property as not exposed is useful for storing additional internal information that is not meant to be fiddled with by the user directly (but can still be manipulated by the application).- Returns:
- true if this field is to be shown in the PropertiesDialog (default true)
-
setEnabled
Setting a property to disabled will prevent this property from appearing in the PropertiesDialog. It can therefore no longer be directly manipulated by the user. The difference between setEnabled(false) and setExposed(false) is that enabled/disabled are intended to be short term and dynamic, while exposed/not exposed are intended to be permanent attributes of that property. Basically isExposed=false means the property will never appear in the UI, whereas isEnabled=false means the property will temporarily ot appear in the UI (until enabled).- Parameters:
enable- Whether to enable or disable this property.
-
isEnabled
public boolean isEnabled()Reports whether this property is currently enabled. If false, the property should be hidden temporarily in the UI (but may still contain a valid value).- Returns:
- Whether this property is currently enabled.
-
isInitiallyEditable
public boolean isInitiallyEditable()Reports whether this property will be editable when shown in the PropertiesDialog.Question: Why would I want a property to be read only? - a common use case with forms is to make certain controls visible/editable only if certain conditions are met elsewhere on the form. You can use isInitiallyEditable to set the initial state of this property when it is added to the PropertiesDialog (it can still be changed at runtime as a result of action handlers on other form fields).
Another use case is for displaying programmatically configurable properties that can be set by the code but not by the user. It may still be desirable to show these properties on the PropertiesDialog and their current value, without allowing the user to change them. Unlike using a static label for this purpose, these properties will still save and load their values to and from properties.
-
setInitiallyEditable
Set whether this property is to be editable by default when shown on a PropertiesDialog. Note that this reflects the initial state of the property on the PropertiesDialog. This can be changed at runtime by action handlers on other form fields (for example, field B is only editable if field A contains a specific value). -
isInitiallyVisible
public boolean isInitiallyVisible()Reports whether this property will be visible when added to the PropertiesDialog.Question: Why would I want a property to be invisible? - a common use case with forms is to make certain controls visible/editable only if certain conditions are met elsewhere on the form. You can use isInitiallyVisible to set the initial state of this property when it is added to the PropertiesDialog (it can still be changed at runtime as a result of action handlers on other form fields).
-
setInitiallyVisible
Sets whether this property is to be visible by default when shown on a PropertiesDialog. Note that this reflects the initial state of the property on the PropertiesDialog. This can be changed at runtime by action handlers on other form fields (for example, field B is only visible if field A contains a specific value). -
getHelpText
Returns the optional help text for this property, if any is set, otherwise a blank string.- Returns:
- The help text for this property, or empty string if not set.
-
setHelpText
Sets optional help text for this property. This will be used when generating the form field for this property, to give the user an informational icon on the generated form. Multi-line tooltips are supported by wrapping the contents in an <html> tag and using <br> to separate lines.- Parameters:
helpText- The new help text, or null to unset it.
-
setExtraAttribute
Set an arbitrary extra attribute to this property. The given value is not validated nor used within this class. It's just extra data that can be attached by the caller. Any extra attributes set here will be passed on as-is to any generated FormField. However, they are NOT persisted by saveToProps.- Parameters:
name- The unique name of the value to set. Will overwrite any previous value by that name.value- The value to set.
-
getExtraAttribute
Returns a named extra attribute's value, if it exists.- Parameters:
name- The unique name of the value in question.- Returns:
- The value associated with that name, or null if no such value.
-
clearExtraAttributes
public void clearExtraAttributes()Removes all extra attributes and their associated values from this AbstractProperty. -
clearExtraAttribute
Removes the value for the named extra attribute.- Parameters:
name- The unique name of the attribute in question.
-
setAllExtraAttributes
Clears any extra attributes currently held by this AbstractProperty and then accepts the given list of attributes. Any extra attributes set here will be passed on as-is to any generated FormField. However, they are NOT persisted by saveToProps.- Parameters:
newAttributes- A map of String name to some arbitrary Object value.
-
addAllExtraAttributes
Adds the map of extra attributes to our existing list. Any name conflicts will result in the existing values being overwritten by the new values. Any extra attributes set here will be passed on as-is to any generated FormField. However, they are NOT persisted by saveToProps.- Parameters:
newAttributes- A map of String name to some arbitrary Object value.
-
addLeftPadding
Will add the specified amount of left padding to the generated FormField's margins. This ADDS to the default margin value, it does not replace it. -
addRightPadding
Will add the specified amount of right padding to the generated FormField's margins. This ADDS to the default margin value, it does not replace it. -
addTopPadding
Will add the specified amount of top padding to the generated FormField's margins. This ADDS to the default margin value, it does not replace it. -
addBottomPadding
Will add the specified amount of bottom padding to the generated FormField's margins. This ADDS to the default margin value, it does not replace it. -
addInnerPadding
Will add the specified amount of inner padding (internal spacing) to the generated FormField's margins. This ADDS to the default margin value, it does not replace it. -
addPadding
Add the specified padding values to the generated FormField's margins. This ADDS to the default margin values, it does not replace them. -
getMarginPadding
Returns a copy of the margin padding that will be applied to the generated FormField. This method is for inspection only - to modify the values, use addPadding() or one of the other convenience methods instead. -
isAllowsUserInput
public boolean isAllowsUserInput()Most properties will generate FormField instances that allow user input, so the default value of "true" can be left alone. If your AbstractProperty implementation generates FormField instances that do not allow user input (for example, a static label), then you can override this method to return false. This is currently used only by the unit tests, to decide whether to test valid/invalid user inputs.- Returns:
- true if the FormField generated by this property allows user input, false if it is read-only.
-
saveToProps
Saves the current value(s) of this property to the given Properties instance.- Parameters:
props- Any Properties instance which will receive the value(s) of this property.
-
loadFromProps
Loads the value(s) for this property from the given Properties instance, overwriting any current value. The current value of this property will be used as a default value in the event that this property does not exist in the given Properties instance.- Parameters:
props- Any Properties instance which contains value(s) for this property.
-
generateFormFieldImpl
Descendant classes must implement this method to generate a FormField associated with this property. The generateFormField() method in this class will call this abstract method to create the FormField, which will then be augmented with our fully qualified name, read-only state, help text, and extra attributes.- Returns:
- A FormField associated with this property.
-
generateFormField
Generates a FormField instance for this AbstractProperty, depending on our type. The returned FormField will be populated based on the current value of this property. There's no guarantee that it will pass form validation, though, as the default value of the property is out of our control and may or may not actually be valid.Descendant classes should implement generateFormFieldImpl() and not this method.
NOTE: you should generally never need to invoke this method directly. It is invoked as needed by the PropertiesManager. Of course, if you are manually building your own FormPanel, you can use this directly. However, note that a new FormField instance will be created each time you invoke this method. So, any listener you add to the generated FormField, or any change you make to it, will effectively be lost the next time you invoke this method. Also, when your FormPanel has been validated and you wish to propagate the FormField's value(s) back into this property, you must manually invoke loadFromFormField(), passing in the FormField you got from generateFormField(). If you are going through PropertiesManager, all of this is done for you.
- Parameters:
formPanel- The containing FormPanel for the generated FormField, if known (null is fine).- Returns:
- A FormField representing this AbstractProperty.
-
generateFormField
Delegates to generateFormField(null). -
loadFromFormField
Populates this Property's value(s) from the given form field, assuming the field is of the correct type.- Parameters:
field- The FormField containing a value for this property.
-
hashCode
public int hashCode() -
equals
-
addFormFieldChangeListener
Register to receive a change notification when a generated FormField's value is changed by the user. This hook provides context about where the change happened (that is, which FormPanel contains the FormField in question, and of course the FormField itself). -
removeFormFieldChangeListener
-
removeAllFormFieldChangeListeners
public void removeAllFormFieldChangeListeners() -
fireFormFieldChangedEvent
protected void fireFormFieldChangedEvent(FormPanel formPanel, FormField field, ActionEvent changeEvent) -
addFormFieldGenerationListener
Register to receive a notification when this AbstractProperty instance generates a FormField. You can use this hook to tweak the generated FormField, if needed, before it is added to whatever FormPanel requested the field. -
removeFormFieldGenerationListener
-
removeAllFormFieldGenerationListeners
public void removeAllFormFieldGenerationListeners() -
fireFormFieldGeneratedEvent
-