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("useturnoutconnectiondelay") != null) { 160 dispatcher.setUseTurnoutConnectionDelay(false); 161 if (options.getAttribute("useturnoutconnectiondelay").getValue().equals("yes")) { 162 dispatcher.setUseTurnoutConnectionDelay(true); 163 } 164 } 165 if (options.getAttribute("minthrottleinterval") != null) { 166 String s = (options.getAttribute("minthrottleinterval")).getValue(); 167 dispatcher.setMinThrottleInterval(Integer.parseInt(s)); 168 } 169 if (options.getAttribute("fullramptime") != null) { 170 String s = (options.getAttribute("fullramptime")).getValue(); 171 dispatcher.setFullRampTime(Integer.parseInt(s)); 172 } 173 if (options.getAttribute("hasoccupancydetection") != null) { 174 dispatcher.setHasOccupancyDetection(true); 175 if (options.getAttribute("hasoccupancydetection").getValue().equals("no")) { 176 dispatcher.setHasOccupancyDetection(false); 177 } 178 } 179 if (options.getAttribute("sslcheckdirectionsensors") != null) { 180 dispatcher.setSetSSLDirectionalSensors(true); 181 if (options.getAttribute("sslcheckdirectionsensors").getValue().equals("no")) { 182 dispatcher.setSetSSLDirectionalSensors(false); 183 } 184 } 185 if (options.getAttribute("shortactivetrainnames") != null) { 186 dispatcher.setShortActiveTrainNames(true); 187 if (options.getAttribute("shortactivetrainnames").getValue().equals("no")) { 188 dispatcher.setShortActiveTrainNames(false); 189 } 190 } 191 if (options.getAttribute("shortnameinblock") != null) { 192 dispatcher.setShortNameInBlock(true); 193 if (options.getAttribute("shortnameinblock").getValue().equals("no")) { 194 dispatcher.setShortNameInBlock(false); 195 } 196 } 197 if (options.getAttribute("extracolorforallocated") != null) { 198 dispatcher.setExtraColorForAllocated(true); 199 if (options.getAttribute("extracolorforallocated").getValue().equals("no")) { 200 dispatcher.setExtraColorForAllocated(false); 201 } 202 } 203 if (options.getAttribute("nameinallocatedblock") != null) { 204 dispatcher.setNameInAllocatedBlock(true); 205 if (options.getAttribute("nameinallocatedblock").getValue().equals("no")) { 206 dispatcher.setNameInAllocatedBlock(false); 207 } 208 } 209 if (options.getAttribute("supportvsdecoder") != null) { 210 dispatcher.setSupportVSDecoder(true); 211 if (options.getAttribute("supportvsdecoder").getValue().equals("no")) { 212 dispatcher.setSupportVSDecoder(false); 213 } 214 } 215 if (options.getAttribute("layoutscale") != null) { 216 String s = (options.getAttribute("layoutscale")).getValue(); 217 dispatcher.setScale(ScaleManager.getScale(s)); 218 } 219 if (options.getAttribute("usescalemeters") != null) { 220 dispatcher.setUseScaleMeters(true); 221 if (options.getAttribute("usescalemeters").getValue().equals("no")) { 222 dispatcher.setUseScaleMeters(false); 223 } 224 } 225 if (options.getAttribute("userosterentryinblock") != null) { 226 dispatcher.setRosterEntryInBlock(false); 227 if (options.getAttribute("userosterentryinblock").getValue().equals("yes")) { 228 dispatcher.setRosterEntryInBlock(true); 229 } 230 } 231 if (options.getAttribute("stoppingspeedname") != null) { 232 dispatcher.setStoppingSpeedName((options.getAttribute("stoppingspeedname")).getValue()); 233 } 234 235 log.debug(" Options: {}, Detection={}, AutoAllocate={}, AutoTurnouts={}, SetSSLDirectionSensors={}", 236 (dispatcher.getSignalTypeString()), 237 (dispatcher.getAutoAllocate()?"yes":"no"), 238 (dispatcher.getAutoTurnouts()?"yes":"no"), 239 (dispatcher.getSetSSLDirectionalSensors()?"yes":"no")); 240 } 241 } 242 } else { 243 log.debug("No Dispatcher options file found at {}, using defaults", defaultFileName); 244 } 245 } 246 247 /** 248 * Write out Dispatcher options to a file in the user's preferences directory. 249 * <p>The lename attribute is deprecated at 5.1.3. The current value will be retained. 250 * @param f Dispatcher instance. 251 * @throws java.io.IOException Thrown if dispatcher option file not found 252 */ 253 public void writeDispatcherOptions(DispatcherFrame f) throws java.io.IOException { 254 log.debug("Saving Dispatcher options to file {}", defaultFileName); 255 dispatcher = f; 256 root = new Element("dispatcheroptions"); 257 doc = newDocument(root, dtdLocation + "dispatcher-options.dtd"); 258 // add XSLT processing instruction 259 // <?xml-stylesheet type="text/xsl" href="XSLT/block-values.xsl"?> 260 java.util.Map<String, String> m = new java.util.HashMap<>(); 261 m.put("type", "text/xsl"); 262 m.put("href", xsltLocation + "dispatcheroptions.xsl"); 263 org.jdom2.ProcessingInstruction p = new org.jdom2.ProcessingInstruction("xml-stylesheet", m); 264 doc.addContent(0, p); 265 266 // save Dispatcher Options in xml format 267 Element options = new Element("options"); 268 LayoutEditor le = dispatcher.getLayoutEditor(); 269 if (le != null) { 270 options.setAttribute("lename", le.getTitle()); 271 } 272 options.setAttribute("useconnectivity", "" + (dispatcher.getUseConnectivity() ? "yes" : "no")); 273 options.setAttribute("trainsfrom", trainsFromEnumMap.outputFromEnum(dispatcher.getTrainsFrom())); 274 options.setAttribute("autoallocate", "" + (dispatcher.getAutoAllocate() ? "yes" : "no")); 275 options.setAttribute("autorelease", "" + (dispatcher.getAutoRelease() ? "yes" : "no")); 276 options.setAttribute("autoturnouts", "" + (dispatcher.getAutoTurnouts() ? "yes" : "no")); 277 options.setAttribute("trustknownturnouts", "" + (dispatcher.getTrustKnownTurnouts() ? "yes" : "no")); 278 options.setAttribute("useturnoutconnectiondelay", "" + (dispatcher.getUseTurnoutConnectionDelay() ? "yes" : "no")); 279 options.setAttribute("minthrottleinterval", "" + (dispatcher.getMinThrottleInterval())); 280 options.setAttribute("fullramptime", "" + (dispatcher.getFullRampTime())); 281 options.setAttribute("hasoccupancydetection", "" + (dispatcher.getHasOccupancyDetection() ? "yes" : "no")); 282 options.setAttribute("sslcheckdirectionsensors", "" + (dispatcher.getSetSSLDirectionalSensors() ? "yes" : "no")); 283 options.setAttribute("shortactivetrainnames", "" + (dispatcher.getShortActiveTrainNames() ? "yes" : "no")); 284 options.setAttribute("shortnameinblock", "" + (dispatcher.getShortNameInBlock() ? "yes" : "no")); 285 options.setAttribute("extracolorforallocated", "" + (dispatcher.getExtraColorForAllocated() ? "yes" : "no")); 286 options.setAttribute("nameinallocatedblock", "" + (dispatcher.getNameInAllocatedBlock() ? "yes" : "no")); 287 options.setAttribute("supportvsdecoder", "" + (dispatcher.getSupportVSDecoder() ? "yes" : "no")); 288 options.setAttribute("layoutscale", dispatcher.getScale().getScaleName()); 289 options.setAttribute("usescalemeters", "" + (dispatcher.getUseScaleMeters() ? "yes" : "no")); 290 options.setAttribute("userosterentryinblock", "" + (dispatcher.getRosterEntryInBlock() ? "yes" : "no")); 291 options.setAttribute("stoppingspeedname", dispatcher.getStoppingSpeedName()); 292 switch (dispatcher.getSignalType()) { 293 case DispatcherFrame.SIGNALMAST: 294 options.setAttribute("usesignaltype", "signalmast"); 295 break; 296 case DispatcherFrame.SECTIONSALLOCATED: 297 options.setAttribute("usesignaltype", "sectionsallocated"); 298 break; 299 default: 300 options.setAttribute("usesignaltype", "signalhead"); 301 } 302 root.addContent(options); 303 304 // write out the file 305 try { 306 if (!checkFile(defaultFileName)) { 307 // file does not exist, create it 308 File file = new File(defaultFileName); 309 if (!file.createNewFile()) // create new file and check result 310 { 311 log.error("createNewFile failed"); 312 } 313 } 314 // write content to file 315 writeXML(findFile(defaultFileName), doc); 316 } catch (java.io.IOException ioe) { 317 log.error("IO Exception {}", ioe.getMessage()); 318 throw (ioe); 319 } 320 } 321 322 private final static Logger log = LoggerFactory.getLogger(OptionsFile.class); 323}