/** * Remove a RosterEntry object from the in-memory Roster. This does not delete the file for the * RosterEntry! * * @param e Entry to remove */ public void removeEntry(RosterEntry e) { log.debug("Remove entry {}", e); _list.remove(e); e.removePropertyChangeListener(this); setDirty(true); firePropertyChange(REMOVE, e, null); }
/** * Add a RosterEntry object to the in-memory Roster. * * @param e Entry to add */ public void addEntry(RosterEntry e) { if (log.isDebugEnabled()) { log.debug("Add entry " + e); } int i = _list.size() - 1; // Last valid index while (i >= 0) { if (e.getId().compareToIgnoreCase(_list.get(i).getId()) > 0) { break; // I can never remember whether I want break or continue here } i--; } _list.add(i + 1, e); e.addPropertyChangeListener(this); this.addRosterGroups(e.getGroups(this)); setDirty(true); firePropertyChange(ADD, null, e); }
/** * 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. * * @param file an op */ void writeFile(File file) throws java.io.IOException { // create root element Element root = new Element("roster-config"); // NOI18N root.setAttribute( "noNamespaceSchemaLocation", // NOI18N "http://jmri.org/xml/schema/roster" + schemaVersion + ".xsd", // NOI18N org.jdom2.Namespace.getNamespace( "xsi", // NOI18N "http://www.w3.org/2001/XMLSchema-instance")); // NOI18N Document doc = newDocument(root); // add XSLT processing instruction // <?xml-stylesheet type="text/xsl" href="XSLT/roster.xsl"?> java.util.Map<String, String> m = new java.util.HashMap<>(); m.put("type", "text/xsl"); // NOI18N m.put("href", xsltLocation + "roster2array.xsl"); // NOI18N ProcessingInstruction p = new ProcessingInstruction("xml-stylesheet", m); // NOI18N doc.addContent(0, p); String newLocoString = SymbolicProgBundle.getMessage("LabelNewDecoder"); // Check the Comment and Decoder Comment fields for line breaks and // convert them to a processor directive for storage in XML // Note: this is also done in the LocoFile.java class to do // the same thing in the indidvidual locomotive roster files // Note: these changes have to be undone after writing the file // since the memory version of the roster is being changed to the // file version for writing for (int i = 0; i < numEntries(); i++) { // Extract the RosterEntry at this index and inspect the Comment and // Decoder Comment fields to change any \n characters to <?p?> processor // directives so they can be stored in the xml file and converted // back when the file is read. RosterEntry r = _list.get(i); if (!r.getId().equals(newLocoString)) { String tempComment = r.getComment(); String xmlComment = ""; // transfer tempComment to xmlComment one character at a time, except // when \n is found. In that case, insert <?p?> for (int k = 0; k < tempComment.length(); k++) { if (tempComment.startsWith("\n", k)) { // NOI18N xmlComment = xmlComment + "<?p?>"; // NOI18N } else { xmlComment = xmlComment + tempComment.substring(k, k + 1); } } r.setComment(xmlComment); // Now do the same thing for the decoderComment field String tempDecoderComment = r.getDecoderComment(); String xmlDecoderComment = ""; for (int k = 0; k < tempDecoderComment.length(); k++) { if (tempDecoderComment.startsWith("\n", k)) { // NOI18N xmlDecoderComment = xmlDecoderComment + "<?p?>"; // NOI18N } else { xmlDecoderComment = xmlDecoderComment + tempDecoderComment.substring(k, k + 1); } } r.setDecoderComment(xmlDecoderComment); } else { log.debug("skip unsaved roster entry with default name " + r.getId()); } } // All Comments and Decoder Comment line feeds have been changed to processor directives // add top-level elements Element values = new Element("roster"); // NOI18N root.addContent(values); // add entries for (int i = 0; i < numEntries(); i++) { if (!_list.get(i).getId().equals(newLocoString)) { values.addContent(_list.get(i).store()); } else { log.debug("skip unsaved roster entry with default name " + _list.get(i).getId()); } } if (!this.rosterGroups.isEmpty()) { Element rosterGroup = new Element("rosterGroup"); // NOI18N rosterGroups .keySet() .stream() .forEach( (name) -> { Element group = new Element("group"); // NOI18N if (!name.equals(Roster.ALLENTRIES)) { group.addContent(name); rosterGroup.addContent(group); } }); root.addContent(rosterGroup); } writeXML(file, doc); // Now that the roster has been rewritten in file form we need to // restore the RosterEntry object to its normal \n state for the // Comment and Decoder comment fields, otherwise it can cause problems in // other parts of the program (e.g. in copying a roster) for (int i = 0; i < numEntries(); i++) { RosterEntry r = _list.get(i); if (!r.getId().equals(newLocoString)) { String xmlComment = r.getComment(); String tempComment = ""; for (int k = 0; k < xmlComment.length(); k++) { if (xmlComment.startsWith("<?p?>", k)) { // NOI18N tempComment = tempComment + "\n"; // NOI18N k = k + 4; } else { tempComment = tempComment + xmlComment.substring(k, k + 1); } } r.setComment(tempComment); String xmlDecoderComment = r.getDecoderComment(); String tempDecoderComment = ""; // NOI18N for (int k = 0; k < xmlDecoderComment.length(); k++) { if (xmlDecoderComment.startsWith("<?p?>", k)) { // NOI18N tempDecoderComment = tempDecoderComment + "\n"; // NOI18N k = k + 4; } else { tempDecoderComment = tempDecoderComment + xmlDecoderComment.substring(k, k + 1); } } r.setDecoderComment(tempDecoderComment); } else { log.debug("skip unsaved roster entry with default name " + r.getId()); } } // done - roster now stored, so can't be dirty setDirty(false); firePropertyChange(SAVED, false, true); }