001package jmri.jmrit.dispatcher; 002 003import java.io.File; 004import java.util.Set; 005import jmri.InstanceManager; 006import jmri.InstanceManagerAutoDefault; 007import jmri.ScaleManager; 008import jmri.configurexml.AbstractXmlAdapter.EnumIO; 009import jmri.configurexml.AbstractXmlAdapter.EnumIoNamesNumbers; 010import jmri.jmrit.dispatcher.DispatcherFrame.TrainsFrom; 011import jmri.jmrit.display.EditorManager; 012import jmri.jmrit.display.layoutEditor.LayoutEditor; 013import jmri.util.FileUtil; 014import org.jdom2.Document; 015import org.jdom2.Element; 016import org.slf4j.Logger; 017import org.slf4j.LoggerFactory; 018 019/** 020 * Handles reading and writing of Dispatcher options to disk as an XML file 021 * called "dispatcher-options.xml" in the user's preferences area. 022 * <p> 023 * This class manipulates the files conforming to the dispatcher-options DTD 024 * <p> 025 * The file is written when the user requests that options be saved. If the 026 * dispatcheroptions.xml file is present when Dispatcher is started, it is read 027 * and options set accordingly 028 * <p> 029 * This file is part of JMRI. 030 * <p> 031 * JMRI is open source software; you can redistribute it and/or modify it under 032 * the terms of version 2 of the GNU General Public License as published by the 033 * Free Software Foundation. See the "COPYING" file for a copy of this license. 034 * <p> 035 * JMRI is distributed in the hope that it will be useful, but WITHOUT ANY 036 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR 037 * A PARTICULAR PURPOSE. See the GNU General Public License for more details. 038 * 039 * @author Dave Duchamp Copyright (C) 2008 040 */ 041public class OptionsFile extends jmri.jmrit.XmlFile implements InstanceManagerAutoDefault { 042 043 public OptionsFile() { 044 super(); 045 } 046 047 static final EnumIO<DispatcherFrame.TrainsFrom> trainsFromEnumMap = new EnumIoNamesNumbers<>(DispatcherFrame.TrainsFrom.class); 048 049 // operational variables 050 protected DispatcherFrame dispatcher = null; 051 private static String defaultFileName = FileUtil.getUserFilesPath() + "dispatcheroptions.xml"; 052 053 public static void setDefaultFileName(String testLocation) { 054 defaultFileName = testLocation; 055 } 056 private Document doc = null; 057 private Element root = null; 058 059 /** 060 * Read Dispatcher Options from a file in the user's preferences directory. 061 * If the file containing Dispatcher Options does not exist, this routine returns quietly. 062 * <p>The lename attribute is deprecated at 5.1.3. The current value will be retained. 063 * 064 * @param f The dispatcher instance. 065 * @throws org.jdom2.JDOMException if dispatcher parameter logically incorrect 066 * @throws java.io.IOException if dispatcher parameter not found 067 */ 068 public void readDispatcherOptions(DispatcherFrame f) throws org.jdom2.JDOMException, java.io.IOException { 069 // check if file exists 070 if (checkFile(defaultFileName)) { 071 // file is present, 072 log.debug("Reading Dispatcher options from file {}", defaultFileName); 073 root = rootFromName(defaultFileName); 074 dispatcher = f; 075 if (root != null) { 076 // there is a file 077 Element options = root.getChild("options"); 078 if (options != null) { 079 // there are options defined, read and set Dispatcher options 080 if (options.getAttribute("lename") != null) { 081 // there is a layout editor name selected 082 String leName = options.getAttribute("lename").getValue(); 083 084 // get list of Layout Editor panels 085 // Note: While editor is deprecated, retain the value for backward compatibility. 086 Set<LayoutEditor> layoutEditorList = InstanceManager.getDefault(EditorManager.class).getAll(LayoutEditor.class); 087 if (layoutEditorList.isEmpty()) { 088 log.warn("Dispatcher options specify a Layout Editor panel that is not present."); 089 } else { 090 boolean found = false; 091 for (LayoutEditor editor : layoutEditorList) { 092 if (leName.equals(editor.getTitle())) { 093 found = true; 094 dispatcher.setLayoutEditor(editor); 095 } 096 } 097 if (!found) { 098 log.warn("Layout Editor panel - {} - not found.", leName); 099 } 100 } 101 } 102 if (options.getAttribute("usesignaltype") != null) { 103 switch (options.getAttribute("usesignaltype").getValue()) { 104 case "signalmast": 105 dispatcher.setSignalType(DispatcherFrame.SIGNALMAST); 106 break; 107 case "sectionsallocated": 108 dispatcher.setSignalType(DispatcherFrame.SECTIONSALLOCATED); 109 break; 110 default: 111 dispatcher.setSignalType(DispatcherFrame.SIGNALHEAD); 112 } 113 } 114 if (options.getAttribute("useconnectivity") != null) { 115 dispatcher.setUseConnectivity(true); 116 if (options.getAttribute("useconnectivity").getValue().equals("no")) { 117 dispatcher.setUseConnectivity(false); 118 } 119 } 120 if (options.getAttribute("trainsfrom") != null) { 121 dispatcher.setTrainsFrom(trainsFromEnumMap.inputFromAttribute(options.getAttribute("trainsfrom"))); 122 } else { 123 log.warn("Old Style dispatcheroptions file found - will be converted when saved"); 124 if (options.getAttribute("trainsfromroster") != null && 125 options.getAttribute("trainsfromroster").getValue().equals("yes")) { 126 dispatcher.setTrainsFrom(TrainsFrom.TRAINSFROMROSTER); 127 } else if (options.getAttribute("trainsfromtrains") != null && 128 options.getAttribute("trainsfromtrains").getValue().equals("no")) { 129 dispatcher.setTrainsFrom(TrainsFrom.TRAINSFROMOPS); 130 } else if (options.getAttribute("trainsfromuser") != null && 131 options.getAttribute("trainsfromuser").getValue().equals("no")) { 132 dispatcher.setTrainsFrom(TrainsFrom.TRAINSFROMUSER); 133 } 134 } 135 if (options.getAttribute("autoallocate") != null) { 136 dispatcher.setAutoAllocate(false); 137 if (options.getAttribute("autoallocate").getValue().equals("yes")) { 138 dispatcher.setAutoAllocate(true); 139 } 140 } 141 if (options.getAttribute("autorelease") != null) { 142 dispatcher.setAutoRelease(false); 143 if (options.getAttribute("autorelease").getValue().equals("yes")) { 144 dispatcher.setAutoRelease(true); 145 } 146 } 147 if (options.getAttribute("autoturnouts") != null) { 148 dispatcher.setAutoTurnouts(true); 149 if (options.getAttribute("autoturnouts").getValue().equals("no")) { 150 dispatcher.setAutoTurnouts(false); 151 } 152 } 153 if (options.getAttribute("trustknownturnouts") != null) { 154 dispatcher.setTrustKnownTurnouts(false); 155 if (options.getAttribute("trustknownturnouts").getValue().equals("yes")) { 156 dispatcher.setTrustKnownTurnouts(true); 157 } 158 } 159 if (options.getAttribute("minthrottleinterval") != null) { 160 String s = (options.getAttribute("minthrottleinterval")).getValue(); 161 dispatcher.setMinThrottleInterval(Integer.parseInt(s)); 162 } 163 if (options.getAttribute("fullramptime") != null) { 164 String s = (options.getAttribute("fullramptime")).getValue(); 165 dispatcher.setFullRampTime(Integer.parseInt(s)); 166 } 167 if (options.getAttribute("hasoccupancydetection") != null) { 168 dispatcher.setHasOccupancyDetection(true); 169 if (options.getAttribute("hasoccupancydetection").getValue().equals("no")) { 170 dispatcher.setHasOccupancyDetection(false); 171 } 172 } 173 if (options.getAttribute("sslcheckdirectionsensors") != null) { 174 dispatcher.setSetSSLDirectionalSensors(true); 175 if (options.getAttribute("sslcheckdirectionsensors").getValue().equals("no")) { 176 dispatcher.setSetSSLDirectionalSensors(false); 177 } 178 } 179 if (options.getAttribute("shortactivetrainnames") != null) { 180 dispatcher.setShortActiveTrainNames(true); 181 if (options.getAttribute("shortactivetrainnames").getValue().equals("no")) { 182 dispatcher.setShortActiveTrainNames(false); 183 } 184 } 185 if (options.getAttribute("shortnameinblock") != null) { 186 dispatcher.setShortNameInBlock(true); 187 if (options.getAttribute("shortnameinblock").getValue().equals("no")) { 188 dispatcher.setShortNameInBlock(false); 189 } 190 } 191 if (options.getAttribute("extracolorforallocated") != null) { 192 dispatcher.setExtraColorForAllocated(true); 193 if (options.getAttribute("extracolorforallocated").getValue().equals("no")) { 194 dispatcher.setExtraColorForAllocated(false); 195 } 196 } 197 if (options.getAttribute("nameinallocatedblock") != null) { 198 dispatcher.setNameInAllocatedBlock(true); 199 if (options.getAttribute("nameinallocatedblock").getValue().equals("no")) { 200 dispatcher.setNameInAllocatedBlock(false); 201 } 202 } 203 if (options.getAttribute("supportvsdecoder") != null) { 204 dispatcher.setSupportVSDecoder(true); 205 if (options.getAttribute("supportvsdecoder").getValue().equals("no")) { 206 dispatcher.setSupportVSDecoder(false); 207 } 208 } 209 if (options.getAttribute("layoutscale") != null) { 210 String s = (options.getAttribute("layoutscale")).getValue(); 211 dispatcher.setScale(ScaleManager.getScale(s)); 212 } 213 if (options.getAttribute("usescalemeters") != null) { 214 dispatcher.setUseScaleMeters(true); 215 if (options.getAttribute("usescalemeters").getValue().equals("no")) { 216 dispatcher.setUseScaleMeters(false); 217 } 218 } 219 if (options.getAttribute("userosterentryinblock") != null) { 220 dispatcher.setRosterEntryInBlock(false); 221 if (options.getAttribute("userosterentryinblock").getValue().equals("yes")) { 222 dispatcher.setRosterEntryInBlock(true); 223 } 224 } 225 if (options.getAttribute("stoppingspeedname") != null) { 226 dispatcher.setStoppingSpeedName((options.getAttribute("stoppingspeedname")).getValue()); 227 } 228 229 log.debug(" Options: {}, Detection={}, AutoAllocate={}, AutoTurnouts={}, SetSSLDirectionSensors={}", 230 (dispatcher.getSignalTypeString()), 231 (dispatcher.getAutoAllocate()?"yes":"no"), 232 (dispatcher.getAutoTurnouts()?"yes":"no"), 233 (dispatcher.getSetSSLDirectionalSensors()?"yes":"no")); 234 } 235 } 236 } else { 237 log.debug("No Dispatcher options file found at {}, using defaults", defaultFileName); 238 } 239 } 240 241 /** 242 * Write out Dispatcher options to a file in the user's preferences directory. 243 * <p>The lename attribute is deprecated at 5.1.3. The current value will be retained. 244 * @param f Dispatcher instance. 245 * @throws java.io.IOException Thrown if dispatcher option file not found 246 */ 247 public void writeDispatcherOptions(DispatcherFrame f) throws java.io.IOException { 248 log.debug("Saving Dispatcher options to file {}", defaultFileName); 249 dispatcher = f; 250 root = new Element("dispatcheroptions"); 251 doc = newDocument(root, dtdLocation + "dispatcher-options.dtd"); 252 // add XSLT processing instruction 253 // <?xml-stylesheet type="text/xsl" href="XSLT/block-values.xsl"?> 254 java.util.Map<String, String> m = new java.util.HashMap<>(); 255 m.put("type", "text/xsl"); 256 m.put("href", xsltLocation + "dispatcheroptions.xsl"); 257 org.jdom2.ProcessingInstruction p = new org.jdom2.ProcessingInstruction("xml-stylesheet", m); 258 doc.addContent(0, p); 259 260 // save Dispatcher Options in xml format 261 Element options = new Element("options"); 262 LayoutEditor le = dispatcher.getLayoutEditor(); 263 if (le != null) { 264 options.setAttribute("lename", le.getTitle()); 265 } 266 options.setAttribute("useconnectivity", "" + (dispatcher.getUseConnectivity() ? "yes" : "no")); 267 options.setAttribute("trainsfrom", trainsFromEnumMap.outputFromEnum(dispatcher.getTrainsFrom())); 268 options.setAttribute("autoallocate", "" + (dispatcher.getAutoAllocate() ? "yes" : "no")); 269 options.setAttribute("autorelease", "" + (dispatcher.getAutoRelease() ? "yes" : "no")); 270 options.setAttribute("autoturnouts", "" + (dispatcher.getAutoTurnouts() ? "yes" : "no")); 271 options.setAttribute("trustknownturnouts", "" + (dispatcher.getTrustKnownTurnouts() ? "yes" : "no")); 272 options.setAttribute("minthrottleinterval", "" + (dispatcher.getMinThrottleInterval())); 273 options.setAttribute("fullramptime", "" + (dispatcher.getFullRampTime())); 274 options.setAttribute("hasoccupancydetection", "" + (dispatcher.getHasOccupancyDetection() ? "yes" : "no")); 275 options.setAttribute("sslcheckdirectionsensors", "" + (dispatcher.getSetSSLDirectionalSensors() ? "yes" : "no")); 276 options.setAttribute("shortactivetrainnames", "" + (dispatcher.getShortActiveTrainNames() ? "yes" : "no")); 277 options.setAttribute("shortnameinblock", "" + (dispatcher.getShortNameInBlock() ? "yes" : "no")); 278 options.setAttribute("extracolorforallocated", "" + (dispatcher.getExtraColorForAllocated() ? "yes" : "no")); 279 options.setAttribute("nameinallocatedblock", "" + (dispatcher.getNameInAllocatedBlock() ? "yes" : "no")); 280 options.setAttribute("supportvsdecoder", "" + (dispatcher.getSupportVSDecoder() ? "yes" : "no")); 281 options.setAttribute("layoutscale", dispatcher.getScale().getScaleName()); 282 options.setAttribute("usescalemeters", "" + (dispatcher.getUseScaleMeters() ? "yes" : "no")); 283 options.setAttribute("userosterentryinblock", "" + (dispatcher.getRosterEntryInBlock() ? "yes" : "no")); 284 options.setAttribute("stoppingspeedname", dispatcher.getStoppingSpeedName()); 285 switch (dispatcher.getSignalType()) { 286 case DispatcherFrame.SIGNALMAST: 287 options.setAttribute("usesignaltype", "signalmast"); 288 break; 289 case DispatcherFrame.SECTIONSALLOCATED: 290 options.setAttribute("usesignaltype", "sectionsallocated"); 291 break; 292 default: 293 options.setAttribute("usesignaltype", "signalhead"); 294 } 295 root.addContent(options); 296 297 // write out the file 298 try { 299 if (!checkFile(defaultFileName)) { 300 // file does not exist, create it 301 File file = new File(defaultFileName); 302 if (!file.createNewFile()) // create new file and check result 303 { 304 log.error("createNewFile failed"); 305 } 306 } 307 // write content to file 308 writeXML(findFile(defaultFileName), doc); 309 } catch (java.io.IOException ioe) { 310 log.error("IO Exception {}", ioe.getMessage()); 311 throw (ioe); 312 } 313 } 314 315 private final static Logger log = LoggerFactory.getLogger(OptionsFile.class); 316}