Class Roster

java.lang.Object
jmri.jmrit.XmlFile
jmri.jmrit.roster.Roster
All Implemented Interfaces:
PropertyChangeListener, EventListener, PropertyChangeProvider, RosterGroupSelector

Roster manages and manipulates a roster of locomotives.

It works with the "roster-config" XML schema to load and store its information.

This is an in-memory representation of the roster xml file (see below for constants defining name and location). As such, this class is also responsible for the "dirty bit" handling to ensure it gets written. As a temporary reliability enhancement, all changes to this structure are now being written to a backup file, and a copy is made when the file is opened.

Multiple Roster objects don't make sense, so we use an "instance" member to navigate to a single one.

The only bound property is the list of RosterEntrys; a PropertyChangedEvent is fired every time that changes.

The entries are stored in an ArrayList, sorted alphabetically. That sort is done manually each time an entry is added.

The roster is stored in a "Roster Index", which can be read or written. Each individual entry (once stored) contains a filename which can be used to retrieve the locomotive information for that roster entry. Note that the RosterEntry information is duplicated in both the Roster (stored in the roster.xml file) and in the specific file for the entry.

Originally, JMRI managed just one global roster, held in a global Roster object. With the rise of more complicated layouts, code has been added to address multiple rosters, with the primary one now held in Roster.default(). We're moving references to Roster.default() out to the using code, so that eventually we can make those explicit references to other Roster objects as/when needed.

See Also:
  • Field Details

  • Constructor Details

    • Roster

      public Roster()
      Create a roster with default contents.
    • Roster

      public Roster(String rosterFilename)
  • Method Details

    • getDefault

      public static Roster getDefault()
      Get the roster for the profile returned by ProfileManager.getActiveProfile().
      Returns:
      the roster for the active profile
    • getRoster

      @Nonnull public static Roster getRoster(@CheckForNull Profile profile)
      Get the roster for the specified profile.
      Parameters:
      profile - the Profile to get the roster for
      Returns:
      the roster for the profile
    • addEntry

      public void addEntry(RosterEntry e)
      Add a RosterEntry object to the in-memory Roster.

      This method notifies the UI of changes so should not be used when adding or reloading many roster entries at once.

      Parameters:
      e - Entry to add
    • removeEntry

      public void removeEntry(RosterEntry e)
      Remove a RosterEntry object from the in-memory Roster. This does not delete the file for the RosterEntry!
      Parameters:
      e - Entry to remove
    • numEntries

      public int numEntries()
      Returns:
      number of entries in the roster
    • numGroupEntries

      public int numGroupEntries(String group)
      Parameters:
      group - The group being queried or null for all entries in the roster.
      Returns:
      The Number of roster entries in the specified group or 0 if the group does not exist.
    • numNoGroupEntries

    • entryFromTitle

      Return RosterEntry from a "title" string, ala selection in matchingComboBox.
      Parameters:
      title - The title for the RosterEntry.
      Returns:
      The matching RosterEntry or null
    • getEntryForId

      Return RosterEntry from an "id" string.
      Parameters:
      id - The id for the RosterEntry.
      Returns:
      The matching RosterEntry or null
    • getEntriesByDccAddress

      Return a list of RosterEntry items which have a particular DCC address.
      Parameters:
      a - The address.
      Returns:
      a List of matching entries, empty if there are no matches.
    • getEntry

      @Nonnull public RosterEntry getEntry(int i)
      Return a specific entry by index
      Parameters:
      i - The RosterEntry at position i in the roster.
      Returns:
      The matching RosterEntry
    • getAllEntries

      Get all roster entries.
      Returns:
      a list of roster entries; the list is empty if the roster is empty
    • getGroupEntry

      public RosterEntry getGroupEntry(String group, int i)
      Get the Nth RosterEntry in the group
      Parameters:
      group - The group being queried.
      i - The index within the group of the requested entry.
      Returns:
      The specified entry in the group or null if i is larger than the group, or the group does not exist.
    • getNoGroupEntry

    • getNoGroupList

    • getGroupIndex

      public int getGroupIndex(String group, RosterEntry re)
    • fileFromTitle

      public String fileFromTitle(String title)
      Return filename from a "title" string, ala selection in matchingComboBox.
      Parameters:
      title - The title for the entry.
      Returns:
      The filename for the RosterEntry matching title, or null if no such RosterEntry exists.
    • getEntriesWithAttributeKey

    • getEntriesWithAttributeKeyValue

    • getAllAttributeKeys

    • getEntriesInGroup

    • matchingList

      @Nonnull public List<RosterEntry> matchingList(String roadName, String roadNumber, String dccAddress, String mfg, String decoderModel, String decoderFamily, String id)
      Get a List of RosterEntry objects in Roster matching 7 basic selectors. The list will be empty if there are no matches.

      This method calls getEntriesMatchingCriteria(java.lang.String, java.lang.String, java.lang.String, java.lang.String, java.lang.String, java.lang.String, java.lang.String, java.lang.String) with a null group.

      Parameters:
      roadName - road name of entry or null for any road name
      roadNumber - road number of entry of null for any number
      dccAddress - address of entry or null for any address
      mfg - manufacturer of entry or null for any manufacturer
      decoderModel - decoder model of entry or null for any model
      decoderFamily - decoder family of entry or null for any family
      id - id (unique name) of entry or null for any id
      Returns:
      List of matching RosterEntries or an empty List
      See Also:
    • getEntriesMatchingCriteria

      @Nonnull public List<RosterEntry> getEntriesMatchingCriteria(String roadName, String roadNumber, String dccAddress, String mfg, String decoderModel, String decoderFamily, String id, String group, String developerID, String manufacturerID, String productID)
      Get a List of RosterEntry objects in Roster matching 11 selectors. The list will be empty if there are no matches.
      Parameters:
      roadName - road name of entry or null for any road name
      roadNumber - road number of entry of null for any number
      dccAddress - address of entry or null for any address
      mfg - manufacturer of entry or null for any manufacturer
      decoderModel - decoder model of entry or null for any model
      decoderFamily - decoder family of entry or null for any family
      id - id of entry or null for any id
      group - group entry is member of or null for any group
      developerID - developerID of entry, or null for any developerID
      manufacturerID - manufacturerID of entry, or null for any manufacturerID
      productID - productID of entry, or null for any productID
      Returns:
      List of matching RosterEntries or an empty List
    • getEntriesMatchingCriteria

      @Nonnull public List<RosterEntry> getEntriesMatchingCriteria(String roadName, String roadNumber, String dccAddress, String mfg, String decoderModel, String decoderFamily, String id, String group)
      Get a List of RosterEntry objects in Roster matching 8 selectors. The list will be empty if there are no matches.
      Parameters:
      roadName - road name of entry or null for any road name
      roadNumber - road number of entry of null for any number
      dccAddress - address of entry or null for any address
      mfg - manufacturer of entry or null for any manufacturer
      decoderModel - decoder model of entry or null for any model
      decoderFamily - decoder family of entry or null for any family
      id - id of entry or null for any id
      group - group entry is member of or null for any group
      Returns:
      List of matching RosterEntries or an empty List
    • getEntriesMatchingCriteria

      @Nonnull public List<RosterEntry> getEntriesMatchingCriteria(String dccAddress, String decoderModel, String decoderFamily, String productID, String progMode)
      Get a List of RosterEntry objects in Roster matching 5 selectors. The list will be empty if there are no matches.

      This pattern is used for LocoNet LNCV.

      Parameters:
      dccAddress - address of entry or null for any address
      decoderModel - decoder model of entry or null for any model
      decoderFamily - decoder family of entry or null for any family
      productID - decoder productID or null for any productID
      progMode - decoder programming mode
      Returns:
      List of matching RosterEntries or an empty List
    • checkEntry

      public boolean checkEntry(int i, String roadName, String roadNumber, String dccAddress, String mfg, String decoderModel, String decoderFamily, String id, String group)
      Check if an entry is consistent with up to 9 specific properties.

      A null String argument always matches. Strings are used for convenience in GUI building.

      Parameters:
      i - index for the RosterEntry in the Roster
      roadName - road name of entry or null for any road name
      roadNumber - road number of entry of null for any number
      dccAddress - address of entry or null for any address
      mfg - manufacturer of entry or null for any manufacturer
      decoderModel - decoder model of entry or null for any model
      decoderFamily - decoder family of entry or null for any family
      id - id of entry or null for any id
      group - group entry is member of or null for any group
      Returns:
      true if the entry matches
    • checkEntry

      public boolean checkEntry(List<RosterEntry> list, int i, String roadName, String roadNumber, String dccAddress, String mfg, String decoderModel, String decoderFamily, String id, String group)
      Check if an item from a list of Roster Entry items is consistent with up to 10 specific properties.

      A null String argument always matches. Strings are used for convenience in GUI building.

      Parameters:
      list - the list of RosterEntry items being searched
      i - the index of the roster entry in the list
      roadName - road name of entry or null for any road name
      roadNumber - road number of entry of null for any number
      dccAddress - address of entry or null for any address
      mfg - manufacturer of entry or null for any manufacturer
      decoderModel - decoder model of entry or null for any model
      decoderFamily - decoder family of entry or null for any family
      id - id of entry or null for any id
      group - group entry is member of or null for any group
      Returns:
      True if the entry matches
    • checkEntry

      public boolean checkEntry(RosterEntry r, String roadName, String roadNumber, String dccAddress, String mfg, String decoderModel, String decoderFamily, String id, String group, String developerID, String manufacturerID, String productID)
      Check if an entry is consistent with up to 12 specific (LNSV2/LNCV) properties.

      A null String argument always matches. Strings are used for convenience in GUI building.

      Parameters:
      r - the roster entry being checked
      roadName - road name of entry or null for any road name
      roadNumber - road number of entry of null for any number
      dccAddress - address of entry or null for any address
      mfg - manufacturer of entry or null for any manufacturer
      decoderModel - decoder model of entry or null for any model
      decoderFamily - decoder family of entry or null for any family
      id - id of entry or null for any id
      group - group entry is member of or null for any group
      developerID - developerID of entry, or null for any developerID
      manufacturerID - manufacturerID of entry, or null for any manufacturerID
      productID - productID of entry, or null for any productID
      Returns:
      True if the entry matches
    • checkEntry

      public boolean checkEntry(RosterEntry r, String dccAddress, String decoderModel, String decoderFamily, String productID, String progMode)
      Check if an entry is consistent with up to 5 specific LNCV properties.

      A null String argument always matches. Strings are used for convenience in GUI building.

      Parameters:
      r - the roster entry being checked
      dccAddress - address of entry or null for any address
      decoderModel - decoder model of entry or null for any model
      decoderFamily - decoder family of entry or null for any family
      productID - productId of entry or null for any productID
      progMode - programming mode
      Returns:
      True if the entry matches
    • writeFile

      Write the entire roster to a file.

      Creates a new file with the given name, and then calls writeFile (File) to perform the actual work.

      Parameters:
      name - Filename for new file, including path info as needed.
      Throws:
      FileNotFoundException - if file does not exist
      IOException - if unable to write file
    • writeFile

      void writeFile(File file) throws IOException
      Write the entire roster to a file object. This does not do backup; that has to be done separately. See writeRosterFile() for a public function that finds the default location, does a backup and then calls this.
      Parameters:
      file - the file to write to
      Throws:
      IOException - if unable to write file
    • makeValidFilename

      public static String makeValidFilename(String entry)
      Name a valid roster entry filename from an entry name.
      • Replaces all problematic characters with "_".
      • Append .xml suffix
      Does not check for duplicates.
      Parameters:
      entry - the getId() entry name from the RosterEntry
      Returns:
      Filename for RosterEntry
      Throws:
      IllegalArgumentException - if called with null or empty entry name
      Since:
      2.1.5
      See Also:
    • readFile

      void readFile(String name) throws org.jdom2.JDOMException, IOException
      Read the contents of a roster XML file into this object.

      Note that this does not clear any existing entries.

      Parameters:
      name - filename of roster file
      Throws:
      org.jdom2.JDOMException - if file is invalid XML
      IOException - if unable to read file
    • setDirty

      void setDirty(boolean b)
    • isDirty

      boolean isDirty()
    • dispose

      public void dispose()
    • writeRoster

      public void writeRoster()
      Store the roster in the default place, including making a backup if needed.

      Uses writeFile(String), a protected method that can write to a specific location.

    • reindex

      public void reindex()
      Rebuild the Roster index and store it.
    • reloadRosterFile

      public void reloadRosterFile()
      Update the in-memory Roster to be consistent with the current roster file. This removes any existing roster entries!
    • setRosterIndexFileName

      public void setRosterIndexFileName(String fileName)
    • getRosterIndexFileName

    • getRosterIndexPath

    • getRosterFilesLocation

    • setRosterLocation

      public void setRosterLocation(String f)
      Set the default location for the Roster file, and all individual locomotive files.
      Parameters:
      f - Absolute pathname to use. A null or "" argument flags a return to the original default in the user's files directory. This parameter must be a potentially valid path on the system.
    • getRosterLocation

      Absolute path to roster file location.

      Default is in the user's files directory, but can be set to anything.

      Returns:
      location of the Roster file
      See Also:
    • addPropertyChangeListener

      Description copied from interface: PropertyChangeProvider
      Add a PropertyChangeListener to the listener list.
      Specified by:
      addPropertyChangeListener in interface PropertyChangeProvider
      Specified by:
      addPropertyChangeListener in interface RosterGroupSelector
      Parameters:
      l - The PropertyChangeListener to be added
    • addPropertyChangeListener

      public void addPropertyChangeListener(String propertyName, PropertyChangeListener listener)
      Description copied from interface: PropertyChangeProvider
      Add a PropertyChangeListener for a specific property.
      Specified by:
      addPropertyChangeListener in interface PropertyChangeProvider
      Specified by:
      addPropertyChangeListener in interface RosterGroupSelector
      Parameters:
      propertyName - The name of the property to listen on.
      listener - The PropertyChangeListener to be added
    • firePropertyChange

      protected void firePropertyChange(String p, Object old, Object n)
    • removePropertyChangeListener

      Description copied from interface: PropertyChangeProvider
      Remove the specified listener from this object.
      Specified by:
      removePropertyChangeListener in interface PropertyChangeProvider
      Specified by:
      removePropertyChangeListener in interface RosterGroupSelector
      Parameters:
      l - The PropertyChangeListener to remove.
    • removePropertyChangeListener

      public void removePropertyChangeListener(String propertyName, PropertyChangeListener listener)
      Description copied from interface: PropertyChangeProvider
      Remove the specified listener of the specified property from this object.
      Specified by:
      removePropertyChangeListener in interface PropertyChangeProvider
      Specified by:
      removePropertyChangeListener in interface RosterGroupSelector
      Parameters:
      propertyName - The name of the property to stop listening to.
      listener - The PropertyChangeListener to remove.
    • getPropertyChangeListeners

      Description copied from interface: PropertyChangeProvider
      Get all PropertyChangeListeners currently attached to this object.
      Specified by:
      getPropertyChangeListeners in interface PropertyChangeProvider
      Returns:
      An array of PropertyChangeListeners.
    • getPropertyChangeListeners

      Description copied from interface: PropertyChangeProvider
      Get all PropertyChangeListeners currently listening to changes to the specified property.
      Specified by:
      getPropertyChangeListeners in interface PropertyChangeProvider
      Parameters:
      propertyName - the name of the property of interest
      Returns:
      an array of PropertyChangeListeners
    • entryIdChanged

      public void entryIdChanged(RosterEntry r)
      Notify that the ID of an entry has changed. This doesn't actually change the roster contents, but triggers a reordering of the roster contents.
      Parameters:
      r - the entry with a changed Id
    • getRosterGroupName

      public static String getRosterGroupName(String rosterGroup)
    • getRosterGroupProperty

      public static String getRosterGroupProperty(String name)
      Get the string for a RosterGroup property in a RosterEntry
      Parameters:
      name - The name of the rosterGroup
      Returns:
      The full property string
    • addRosterGroup

      public void addRosterGroup(RosterGroup rg)
      Add a roster group, notifying all listeners of the change.

      This method fires the property change notification "RosterGroupAdded".

      Parameters:
      rg - The group to be added
    • addRosterGroup

      public void addRosterGroup(String rg)
      Add a roster group, notifying all listeners of the change.

      This method creates a RosterGroup. Use addRosterGroup(jmri.jmrit.roster.rostergroup.RosterGroup) if you need to add a subclass of RosterGroup. This method fires the property change notification "RosterGroupAdded".

      Parameters:
      rg - The name of the group to be added
    • addRosterGroups

      public void addRosterGroups(List<RosterGroup> groups)
      Add a list of RosterGroup. RosterGroups that are already known to the Roster are ignored.
      Parameters:
      groups - RosterGroups to add to the roster. RosterGroups already in the roster will not be added again.
    • removeRosterGroup

      public void removeRosterGroup(RosterGroup rg)
    • delRosterGroupList

      public void delRosterGroupList(String rg)
      Delete a roster group, notifying all listeners of the change.

      This method fires the property change notification ""RosterGroupRemoved"".

      Parameters:
      rg - The group to be deleted
    • copyRosterGroupList

      public void copyRosterGroupList(String oldName, String newName)
      Copy a roster group, adding every entry in the roster group to the new group.

      If a roster group with the target name already exists, this method silently fails to rename the roster group. The GUI method CopyRosterGroupAction.performAction() catches this error and informs the user. This method fires the property change ""RosterGroupAdded"".

      Parameters:
      oldName - Name of the roster group to be copied
      newName - Name of the new roster group
      See Also:
    • rosterGroupRenamed

      public void rosterGroupRenamed(String oldName, String newName)
    • renameRosterGroupList

      public void renameRosterGroupList(String oldName, String newName)
      Rename a roster group, while keeping every entry in the roster group.

      If a roster group with the target name already exists, this method silently fails to rename the roster group. The GUI method RenameRosterGroupAction.performAction() catches this error and informs the user. This method fires the property change ""RosterGroupRenamed"".

      Parameters:
      oldName - Name of the roster group to be renamed
      newName - New name for the roster group
      See Also:
    • getRosterGroupList

      Get a list of the user defined roster group names.

      Strings are immutable, so deleting an item from the copy should not affect the system-wide list of roster groups.

      Returns:
      A list of the roster group names.
    • allEntries

      public static String allEntries(Locale locale)
      Get the identifier for all entries in the roster.
      Parameters:
      locale - The desired locale
      Returns:
      "All Entries" in the specified locale
    • getSelectedRosterGroup

      Get the default roster group.

      This method ensures adherence to the RosterGroupSelector protocol

      Specified by:
      getSelectedRosterGroup in interface RosterGroupSelector
      Returns:
      The entire roster
    • getDefaultRosterGroup

      Returns:
      the defaultRosterGroup
    • setDefaultRosterGroup

      public void setDefaultRosterGroup(String defaultRosterGroup)
      Parameters:
      defaultRosterGroup - the defaultRosterGroup to set
    • getAllFileNames

      static String[] getAllFileNames()
      Get an array of all the RosterEntry-containing files in the target directory.
      Returns:
      a string array of file names for entries in this roster
    • getRosterGroups

      Get the groups known to the roster itself. Note that changes to the returned Map will not be reflected in the Roster.
      Returns:
      the rosterGroups
    • remapRosterGroup

      public void remapRosterGroup(RosterGroup group, String newKey)
      Changes the key used to look up a RosterGroup by name. This is a helper method that does not fire a notification to any propertyChangeListeners.

      To rename a RosterGroup, use RosterGroup.setName(java.lang.String).

      Parameters:
      group - The group being associated with newKey and will be disassociated with the key matching RosterGroup.getName().
      newKey - The new key by which group can be found in the map of RosterGroups. This should match the intended new name of group.
    • propertyChange

      Specified by:
      propertyChange in interface PropertyChangeListener