Class PropertiesManager

java.lang.Object
ca.corbett.extras.properties.PropertiesManager

public class PropertiesManager extends Object
Provides a highly configurable wrapper around a set of related properties, along with ways to manage them and present them to the user for viewing and modification. The intention is that all applications go through an instance of this class so that application preferences are handled in a consistent way, but this can be used for managing properties of any type in a generic and configurable way. See also generateDialog() and generateUnrenderedFormPanel() for ways to present a UI to view or edit application properties.
Since:
2024-12-30
Author:
scorbo2
  • Field Details

    • logger

      protected static final Logger logger
    • propertiesInstance

      protected final Properties propertiesInstance
    • properties

      protected final List<AbstractProperty> properties
    • name

      protected final String name
  • Constructor Details

    • PropertiesManager

      public PropertiesManager(File propsFile, List<AbstractProperty> props, String name)
      Creates a PropertiesManager instance backed onto the given File object, and a list of AbstractProperty objects that we will manage.
      Parameters:
      propsFile - The properties file. Does not need to exist - will be created on save()
      props - A List of AbstractProperty instances to be managed by this class.
      name - A name for this property collection. Comment header for the props file.
    • PropertiesManager

      public PropertiesManager(Properties propsInstance, List<AbstractProperty> props, String name)
      Creates a PropertiesManager instance backed onto the given Properties object (which may be a FileBasedProperties instance for disk persistence, or a Properties instance for in-memory), and a list of AbstractProperty objects that we will manage.
      Parameters:
      propsInstance - Any instance of Properties. Will be used for storing and retrieving.
      props - A List of AbstractProperty instances to be managed by this class.
      name - A name for this property collection. Comment header for the propsInstance file.
  • Method Details

    • getName

      public String getName()
      Returns the name of this PropertiesManager. This String is used as a comment header when writing properties files (assuming our Properties instance is a FileBasedProperties).
      Returns:
      The name of this PropertiesManager.
    • getCategories

      public List<String> getCategories()
      Returns a list of all property categories of all non-hidden properties in this PropertiesManager, in the order they were given to the constructor. We don't sort them alphabetically so that applications can define their own preferred order.
      Returns:
      A list of one or more property categories.
    • getSubcategories

      public List<String> getSubcategories(String category)
      Returns a list of all subcategories contained within the named property category. If the specified category does not exist, the list will be empty.
      Parameters:
      category - The name of the category to check.
      Returns:
      A list of zero or more subcategories for the named category.
    • getPropertiesInstance

      public Properties getPropertiesInstance()
      Returns the underlying Properties instance that this manager manages. This can be a shorthand for getting access to specific properties. For example, instead of:
         IntegerProperty someInt = (IntegerProperty)propsManager.getProperty("a.b.c");
         if (someInt != null) {
           return someInt.getValue();
         }
         return someDefaultValue;
       
      You can instead do:
         return propsManager.getPropertiesInstance().getInteger("a.b.c", someDefaultValue);
       
      Returns:
      the Properties instance that this manager manages.
    • getProperties

      public List<AbstractProperty> getProperties(String category, String subCategory)
      Returns a list of all non-hidden PropertyFields in the given category and subcategory. The list may be empty if either the category or subcategory do not exist.
      Parameters:
      category - The name of the property category to check.
      subCategory - The name of the subcategory to check.
      Returns:
      A list of all AbstractProperty objects in that category/subcategory.
    • getProperty

      public AbstractProperty getProperty(String fullyQualifiedName)
      Returns a specific AbstractProperty by its fully qualified name, if it exists.
      Parameters:
      fullyQualifiedName - The identifier of the property in question.
      Returns:
      The property object, or null if not found.
    • load

      public void load() throws Exception
      Loads the value of each of our properties from the Properties instance we were supplied in our constructor, overwriting any current values. The current values of our properties are used as default values in the event that the property in question is not present in the Properties instance.
      Throws:
      Exception - If our Properties instance is file based, we might get an IOException.
    • save

      public void save()
      Saves the value of each of our properties to the Properties instance we were supplied in the constructor, overwriting any previously saved values.The output list will be alphabetically sorted by fully qualified property name, making for a (hopefully) easy to read properties file.
    • updateFromDialog

      public void updateFromDialog(PropertiesDialog dialog)
      Copies all property values from the given PropertiesDialog (assuming the dialog was validated and closed via the OK button) and updates our properties with those values. This will also invoke save() automatically, so if our Properties instance is file based, the updated values are persisted to disk.
      Parameters:
      dialog - The PropertiesDialog in question.
    • setAlwaysShowSubcategoryLabels

      public void setAlwaysShowSubcategoryLabels(boolean value)
      Controls whether subcategory labels should always be shown, even if there is only one subcategory in a given category. The default behavior is to hide subcategory labels if there is only one subcategory.

      If there is more than one subcategory in a category, then the subcategory labels will be shown regardless of the value of this property.

      Parameters:
      value - Force subcategory labels to always show even if there's only one.
    • isAlwaysShowSubcategoryLabels

      public boolean isAlwaysShowSubcategoryLabels()
      If true, subcategory header labels will be generated even if there's only one subcategory in a given category. By default, this is false, meaning that subcategory header labels will be hidden if there's only one.
      Returns:
      Whether subcategory header labels are always generated.
    • generateDialog

      public PropertiesDialog generateDialog(Window owner, String dialogTitle)
      Generates a PropertiesDialog for the current properties list with default dialog values. That is, a left-aligned dialog with an 8 pixel left margin.
      Parameters:
      owner - The owner Window for the dialog.
      dialogTitle - The title of the dialog.
      Returns:
      A PropertiesDialog instance, populated and ready to be shown.
    • generateDialog

      public PropertiesDialog generateDialog(Window owner, String dialogTitle, Alignment alignment, int leftMargin)
      Generates a PropertiesDialog containing all the non-hidden properties managed by this PropertiesManager. Note that this method is shorthand for:
           panelList = generateUnrenderedFormPanels(alignment, leftMargin);
           return new PropertiesDialog(this, owner, dialogTitle, panelList);
       
      You have the option of calling generateUnrenderedFormPanels() yourself to get the list of FormPanels that are not yet rendered. The advantage of doing it that way is that you can add custom logic to form fields on those panels to do things like showing/hiding or enabling/disabling form fields based on the values contained in other fields. Your code would look something like this:
           panelList = propsManager.generateUnrenderedFormPanels(alignment, leftMargin);
      
           // Add some custom logic to the form:
           ComboField field1 = (ComboField)PropertiesManager.findFormField("my.field.one");
           FormField field2 = PropertiesManager.findFormField("my.field.two");
           field1.addValueChangedAction(new AbstractAction() {
                public void actionPerformed(ActionEvent e) {
                    field2.setEnabled("Some special value".equals(field1.getSelectedItem()));
                }
           });
           field2.setEnabled(false); // set initial value
      
           new PropertiesDialog(propsManager, owner, dialogTitle, panelList).setVisible(true);
       

      If you invoke this generateDialog() method to generate the dialog for you, instead of using the above approach, you will lose the ability to add those action handlers before the form panels are rendered. That might be a problem if you need to set certain fields to invisible or disabled before the dialog is shown based on current form values.

      Parameters:
      owner - The owner Window for the dialog.
      dialogTitle - The title of the dialog.
      alignment - How the form panel(s) on the generated dialog should align themselves.
      leftMargin - If form panels are left aligned, you can apply a pixel margin to the form's left side.
      Returns:
      A PropertiesDialog instance, populated and ready to be shown.
    • generateUnrenderedFormPanels

      public List<FormPanel> generateUnrenderedFormPanels()
    • generateUnrenderedFormPanels

      public List<FormPanel> generateUnrenderedFormPanels(Alignment alignment)
    • generateUnrenderedFormPanels

      public List<FormPanel> generateUnrenderedFormPanels(Alignment alignment, int leftMargin)
    • generateUnrenderedFormPanels

      public static List<FormPanel> generateUnrenderedFormPanels(List<AbstractProperty> props)
    • generateUnrenderedFormPanel

      public static List<FormPanel> generateUnrenderedFormPanel(List<AbstractProperty> props, boolean alwaysShowSubcategoryLabels)
    • generateUnrenderedFormPanels

      public static List<FormPanel> generateUnrenderedFormPanels(List<AbstractProperty> props, Alignment alignment)
    • generateUnrenderedFormPanels

      public static List<FormPanel> generateUnrenderedFormPanels(List<AbstractProperty> props, Alignment alignment, boolean alwaysShowSubcategoryLabels)
    • generateUnrenderedFormPanels

      public static List<FormPanel> generateUnrenderedFormPanels(List<AbstractProperty> props, Alignment alignment, int leftMargin, boolean alwaysShowSubcategoryLabels)
    • findFormField

      public static FormField findFormField(String fieldName, List<FormPanel> unrenderedFormPanels)
      A convenience method to find a specific named form field in a list of unrendered form panels. If the field is not found, null is returned. If you can't figure out why the field you're sure is there is returning null, check if it is marked as hidden or disabled. Such fields are not included in the generated form panels.
      Parameters:
      fieldName - The fully qualified name of the field to look for.
      unrenderedFormPanels - A List of unrendered FormPanels, presumably from generateUnrenderedFormPanels()
      Returns:
      The FormField in question, or null if not found.
    • getCategories

      protected static List<String> getCategories(List<AbstractProperty> props)
      Extracts and returns a list of all top-level property categories for all non-hidden properties in the given list, in the order that they are discovered within that list. We don't sort the category list so that applications can define their own preferred order.
      Parameters:
      props - A list of properties to scan.
      Returns:
      A List of unique top-level category names for all non-hidden properties that were found.
    • getSubcategories

      protected static List<String> getSubcategories(String category, List<AbstractProperty> props)
      Scans the given property list and returns a list of all subcategories within the named category have at least one non-hidden property. If the specified category does not exist, the list will be empty.
      Parameters:
      category - The name of the category to check.
      props - The list of properties to scan. Hidden or disabled properties will be ignored.
      Returns:
      A list of zero or more subcategories for the named category.
    • getProperties

      protected static List<AbstractProperty> getProperties(List<AbstractProperty> props, String category, String subCategory)
      Scans the given properties list and returns a list of all non-hidden properties that belong to the given category and subcategory.
      Parameters:
      props - The list of properties to scan
      category - The toplevel category to check
      subCategory - The subcategory to check
      Returns:
      A List of zero or more AbstractProperties that match the search parameters.