001package jmri.jmrit.dispatcher; 002 003import java.io.File; 004import java.util.ArrayList; 005import java.util.Arrays; 006import java.util.List; 007import java.util.regex.Matcher; 008import java.util.regex.Pattern; 009import jmri.util.FileUtil; 010import jmri.util.XmlFilenameFilter; 011import org.jdom2.Document; 012import org.jdom2.Element; 013import org.slf4j.Logger; 014import org.slf4j.LoggerFactory; 015 016import jmri.InstanceManager; 017import jmri.configurexml.AbstractXmlAdapter.EnumIO; 018import jmri.configurexml.AbstractXmlAdapter.EnumIoNamesNumbers; 019import jmri.jmrit.dispatcher.ActiveTrain.TrainDetection; 020 021/** 022 * Handles reading and writing of TrainInfo files to disk as an XML file to/from 023 * the dispatcher/traininfo/ directory in the user's preferences area 024 * <p> 025 * This class manipulates the files conforming to the dispatcher-traininfo DTD 026 * <p> 027 * The file is written when the user requests that train information be saved. A 028 * TrainInfo file is read when the user request it in the Activate New Train 029 * window 030 * 031 * <p> 032 * This file is part of JMRI. 033 * <p> 034 * JMRI is open source software; you can redistribute it and/or modify it under 035 * the terms of version 2 of the GNU General Public License as published by the 036 * Free Software Foundation. See the "COPYING" file for a copy of this license. 037 * <p> 038 * JMRI is distributed in the hope that it will be useful, but WITHOUT ANY 039 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR 040 * A PARTICULAR PURPOSE. See the GNU General Public License for more details. 041 * 042 * @author Dave Duchamp Copyright (C) 2009 043 */ 044public class TrainInfoFile extends jmri.jmrit.XmlFile { 045 046 public TrainInfoFile() { 047 super(); 048 } 049 // operational variables 050 private String fileLocation = FileUtil.getUserFilesPath() 051 + "dispatcher" + File.separator + "traininfo" + File.separator; 052 053 public void setFileLocation(String testLocation) { 054 fileLocation = testLocation; 055 } 056 private Document doc = null; 057 private Element root = null; 058 059 static final EnumIO<ActiveTrain.TrainDetection> trainsdectionFromEnumMap = new EnumIoNamesNumbers<>(ActiveTrain.TrainDetection.class); 060 static final EnumIO<ActiveTrain.TrainLengthUnits> trainlengthFromEnumMap = new EnumIoNamesNumbers<>(ActiveTrain.TrainLengthUnits.class); 061 062 /* 063 * Reads Dispatcher TrainInfo from a file in the user's preferences directory 064 * If the file containing Dispatcher TrainInfo does not exist this routine returns quietly. 065 * "name" is assumed to have the .xml or .XML extension already included 066 */ 067 public TrainInfo readTrainInfo(String name) throws org.jdom2.JDOMException, java.io.IOException { 068 log.debug("entered readTrainInfo for {}", name); 069 TrainInfo tInfo = null; 070 int version = 1; 071 // check if file exists 072 if (checkFile(fileLocation + name)) { 073 // file is present. 074 tInfo = new TrainInfo(); 075 root = rootFromName(fileLocation + name); 076 if (root != null) { 077 // there is a file 078 Element traininfo = root.getChild("traininfo"); 079 if (traininfo != null) { 080 // get version so we dont look for missing fields 081 if (traininfo.getAttribute("version") != null ) { 082 try { 083 version = traininfo.getAttribute("version").getIntValue(); 084 } 085 catch(Exception ex) { 086 log.error("Traininfo file version number not an integer: assuming version 1"); 087 version = 1; 088 } 089 } else { 090 version = 1; 091 } 092 tInfo.setVersion(version); 093 // there are train info options defined, read them 094 if (traininfo.getAttribute("transitname") != null) { 095 // there is a transit name selected 096 tInfo.setTransitName(traininfo.getAttribute("transitname").getValue()); 097 } else { 098 log.error("Transit name missing when reading TrainInfoFile {}", name); 099 } 100 if (version < 6) { 101 if (traininfo.getAttribute("trainname") != null) { 102 tInfo.setTrainName(traininfo.getAttribute("trainname").getValue()); 103 tInfo.setRosterId(traininfo.getAttribute("trainname").getValue()); 104 tInfo.setTrainUserName(traininfo.getAttribute("trainname").getValue()); 105 } else { 106 log.error("Train name missing when reading TrainInfoFile {}", name); 107 } 108 } else { 109 if (traininfo.getAttribute("trainname") != null) { 110 tInfo.setRosterId(traininfo.getAttribute("trainname").getValue()); 111 } 112 if (traininfo.getAttribute("rosterid") != null) { 113 tInfo.setRosterId(traininfo.getAttribute("rosterid").getValue()); 114 } 115 if (traininfo.getAttribute("trainusername") != null) { 116 tInfo.setTrainUserName(traininfo.getAttribute("trainusername").getValue()); 117 } 118 } 119 if (traininfo.getAttribute("dccaddress") != null) { 120 tInfo.setDccAddress(traininfo.getAttribute("dccaddress").getValue()); 121 } else { 122 log.error("DCC Address missing when reading TrainInfoFile {}", name); 123 } 124 if (traininfo.getAttribute("trainintransit") != null) { 125 tInfo.setTrainInTransit(true); 126 if (traininfo.getAttribute("trainintransit").getValue().equals("no")) { 127 tInfo.setTrainInTransit(false); 128 } 129 } else { 130 log.error("Train in Transit check box missing when reading TrainInfoFile {}", name); 131 } 132 if (traininfo.getAttribute("startblockname") != null) { 133 // there is a transit name selected 134 tInfo.setStartBlockName(traininfo.getAttribute("startblockname").getValue()); 135 } else { 136 log.error("Start block name missing when reading TrainInfoFile {}", name); 137 } 138 if (traininfo.getAttribute("endblockname") != null) { 139 // there is a transit name selected 140 tInfo.setDestinationBlockName(traininfo.getAttribute("endblockname").getValue()); 141 } else { 142 log.error("Destination block name missing when reading TrainInfoFile {}", name); 143 } 144 145 if (traininfo.getAttribute("trainfromroster") != null) { 146 tInfo.setTrainFromRoster(true); 147 if (traininfo.getAttribute("trainfromroster").getValue().equals("no")) { 148 tInfo.setTrainFromRoster(false); 149 } 150 } 151 if (traininfo.getAttribute("trainfromtrains") != null) { 152 tInfo.setTrainFromTrains(true); 153 if (traininfo.getAttribute("trainfromtrains").getValue().equals("no")) { 154 tInfo.setTrainFromTrains(false); 155 } 156 } 157 if (traininfo.getAttribute("trainfromuser") != null) { 158 tInfo.setTrainFromUser(true); 159 if (traininfo.getAttribute("trainfromuser").getValue().equals("no")) { 160 tInfo.setTrainFromUser(false); 161 } 162 } 163 if (traininfo.getAttribute("trainfromsetlater") != null) { 164 tInfo.setTrainFromSetLater(true); 165 if (traininfo.getAttribute("trainfromsetlater").getValue().equals("no")) { 166 tInfo.setTrainFromSetLater(false); 167 } 168 } 169 if (traininfo.getAttribute("priority") != null) { 170 tInfo.setPriority(Integer.parseInt(traininfo.getAttribute("priority").getValue())); 171 } else { 172 log.error("Priority missing when reading TrainInfoFile {}", name); 173 } 174 if (traininfo.getAttribute("allocatealltheway") != null) { 175 if (traininfo.getAttribute("allocatealltheway").getValue().equals("yes")) { 176 tInfo.setAllocateAllTheWay(true); 177 } 178 } 179 if (traininfo.getAttribute("allocationmethod") != null) { 180 tInfo.setAllocationMethod(traininfo.getAttribute("allocationmethod").getIntValue()); 181 } 182 if (traininfo.getAttribute("nexttrain") != null) { 183 tInfo.setNextTrain(traininfo.getAttribute("nexttrain").getValue()); 184 } 185 if (traininfo.getAttribute("resetwhendone") != null) { 186 if (traininfo.getAttribute("resetwhendone").getValue().equals("yes")) { 187 tInfo.setResetWhenDone(true); 188 } 189 if (traininfo.getAttribute("delayedrestart") != null) { 190 // for older files that didnot have seperate restart details for to and fro 191 // we default that data to this data. 192 switch (traininfo.getAttribute("delayedrestart").getValue()) { 193 case "no": 194 tInfo.setDelayedRestart(ActiveTrain.NODELAY); 195 tInfo.setReverseDelayedRestart(ActiveTrain.NODELAY); 196 break; 197 case "sensor": 198 tInfo.setDelayedRestart(ActiveTrain.SENSORDELAY); 199 tInfo.setReverseDelayedRestart(ActiveTrain.SENSORDELAY); 200 if (traininfo.getAttribute("delayedrestartsensor") != null) { 201 tInfo.setRestartSensorName(traininfo.getAttribute("delayedrestartsensor").getValue()); 202 tInfo.setReverseRestartSensorName(traininfo.getAttribute("delayedrestartsensor").getValue()); 203 } 204 if (traininfo.getAttribute("resetrestartsensor") != null) { 205 tInfo.setResetRestartSensor(traininfo.getAttribute("resetrestartsensor").getValue().equals("yes")); 206 tInfo.setReverseResetRestartSensor(traininfo.getAttribute("resetrestartsensor").getValue().equals("yes")); 207 } 208 break; 209 case "timed": 210 tInfo.setDelayedRestart(ActiveTrain.TIMEDDELAY); 211 tInfo.setReverseDelayedRestart(ActiveTrain.TIMEDDELAY); 212 if (traininfo.getAttribute("delayedrestarttime") != null) { 213 tInfo.setRestartDelayMin((int) traininfo.getAttribute("delayedrestarttime").getLongValue()); 214 tInfo.setReverseRestartDelayMin((int) traininfo.getAttribute("delayedrestarttime").getLongValue()); 215 } break; 216 default: 217 break; 218 } 219 } 220 } 221 if (traininfo.getAttribute("reverseatend") != null) { 222 tInfo.setReverseAtEnd(true); 223 if (traininfo.getAttribute("reverseatend").getValue().equals("no")) { 224 tInfo.setReverseAtEnd(false); 225 } 226 if (version > 3) { 227 // fro delays are independent from to delays 228 if (traininfo.getAttribute("reversedelayedrestart") != null) { 229 switch (traininfo.getAttribute("reversedelayedrestart").getValue()) { 230 case "no": 231 tInfo.setReverseDelayedRestart(ActiveTrain.NODELAY); 232 break; 233 case "sensor": 234 tInfo.setReverseDelayedRestart(ActiveTrain.SENSORDELAY); 235 if (traininfo.getAttribute("reversedelayedrestartsensor") != null) { 236 tInfo.setReverseRestartSensorName( 237 traininfo.getAttribute("reversedelayedrestartsensor").getValue()); 238 } 239 if (traininfo.getAttribute("reverseresetrestartsensor") != null) { 240 tInfo.setReverseResetRestartSensor( 241 traininfo.getAttribute("reverseresetrestartsensor").getValue() 242 .equals("yes")); 243 } 244 break; 245 case "timed": 246 tInfo.setReverseDelayedRestart(ActiveTrain.TIMEDDELAY); 247 if (traininfo.getAttribute("reversedelayedrestarttime") != null) { 248 tInfo.setReverseRestartDelayMin((int) traininfo 249 .getAttribute("reversedelayedrestarttime").getLongValue()); 250 } 251 break; 252 default: 253 break; 254 } 255 } 256 } 257 } 258 if (traininfo.getAttribute("delayedstart") != null) { 259 switch (traininfo.getAttribute("delayedstart").getValue()) { 260 case "no": 261 tInfo.setDelayedStart(ActiveTrain.NODELAY); 262 break; 263 case "sensor": 264 tInfo.setDelayedStart(ActiveTrain.SENSORDELAY); 265 break; 266 default: 267 //This covers the old versions of the file with "yes" 268 tInfo.setDelayedStart(ActiveTrain.TIMEDDELAY); 269 break; 270 } 271 } 272 if (traininfo.getAttribute("departuretimehr") != null) { 273 tInfo.setDepartureTimeHr(Integer.parseInt(traininfo.getAttribute("departuretimehr").getValue())); 274 } 275 if (traininfo.getAttribute("departuretimemin") != null) { 276 tInfo.setDepartureTimeMin(Integer.parseInt(traininfo.getAttribute("departuretimemin").getValue())); 277 } 278 if (traininfo.getAttribute("delayedSensor") != null) { 279 tInfo.setDelaySensorName(traininfo.getAttribute("delayedSensor").getValue()); 280 } 281 if (traininfo.getAttribute("resetstartsensor") != null) { 282 tInfo.setResetStartSensor(traininfo.getAttribute("resetstartsensor").getValue().equals("yes")); 283 } 284 if (traininfo.getAttribute("traintype") != null) { 285 tInfo.setTrainType(traininfo.getAttribute("traintype").getValue()); 286 } 287 if (traininfo.getAttribute("autorun") != null) { 288 tInfo.setAutoRun(true); 289 if (traininfo.getAttribute("autorun").getValue().equals("no")) { 290 tInfo.setAutoRun(false); 291 } 292 } 293 if (traininfo.getAttribute("loadatstartup") != null) { 294 tInfo.setLoadAtStartup(true); 295 if (traininfo.getAttribute("loadatstartup").getValue().equals("no")) { 296 tInfo.setLoadAtStartup(false); 297 } 298 } 299 // here retrieve items related only to automatically run trains if present 300 if (traininfo.getAttribute("speedfactor") != null) { 301 tInfo.setSpeedFactor(Float.parseFloat(traininfo.getAttribute("speedfactor").getValue())); 302 } 303 if (traininfo.getAttribute("maxspeed") != null) { 304 tInfo.setMaxSpeed(Float.parseFloat(traininfo.getAttribute("maxspeed").getValue())); 305 } 306 if (traininfo.getAttribute("minreliableoperatingspeed") != null) { 307 tInfo.setMinReliableOperatingSpeed(Float.parseFloat(traininfo.getAttribute("minreliableoperatingspeed").getValue())); 308 } 309 if (traininfo.getAttribute("ramprate") != null) { 310 tInfo.setRampRate(traininfo.getAttribute("ramprate").getValue()); 311 } 312 tInfo.setTrainDetection(TrainDetection.TRAINDETECTION_WHOLETRAIN); 313 if (version > 4) { 314 if (traininfo.getAttribute("traindetection") != null) { 315 tInfo.setTrainDetection(trainsdectionFromEnumMap.inputFromAttribute(traininfo.getAttribute("traindetection"))); 316 } 317 } 318 else { 319 if (traininfo.getAttribute("resistancewheels").getValue().equals("no")) { 320 tInfo.setTrainDetection(TrainDetection.TRAINDETECTION_HEADONLY); 321 } 322 } 323 if (traininfo.getAttribute("runinreverse") != null) { 324 tInfo.setRunInReverse(true); 325 if (traininfo.getAttribute("runinreverse").getValue().equals("no")) { 326 tInfo.setRunInReverse(false); 327 } 328 } 329 if (traininfo.getAttribute("sounddecoder") != null) { 330 tInfo.setSoundDecoder(true); 331 if (traininfo.getAttribute("sounddecoder").getValue().equals("no")) { 332 tInfo.setSoundDecoder(false); 333 } 334 } 335 if (version > 5) { 336 if (traininfo.getAttribute("trainlengthunits") != null) { 337 tInfo.setTrainLengthUnits(trainlengthFromEnumMap.inputFromAttribute(traininfo.getAttribute("trainlengthunits"))); 338 } 339 } 340 if (traininfo.getAttribute("maxtrainlengthMeters") != null) { 341 tInfo.setMaxTrainLengthScaleMeters(Float.parseFloat(traininfo.getAttribute("maxtrainlengthscalemeters").getValue())); 342 } else { 343 if (traininfo.getAttribute("maxtrainlength") != null) { 344 if (InstanceManager.getDefault(DispatcherFrame.class).getUseScaleMeters()) { 345 tInfo.setMaxTrainLengthScaleMeters(Float.parseFloat(traininfo.getAttribute("maxtrainlength").getValue())); 346 } else { 347 tInfo.setMaxTrainLengthScaleFeet(Float.parseFloat(traininfo.getAttribute("maxtrainlength").getValue())); 348 } 349 } 350 } 351 if (traininfo.getAttribute("terminatewhendone") != null) { 352 tInfo.setTerminateWhenDone(false); 353 if (traininfo.getAttribute("terminatewhendone").getValue().equals("yes")) { 354 tInfo.setTerminateWhenDone(true); 355 } 356 } 357 if (traininfo.getAttribute("usespeedprofile") != null) { 358 tInfo.setUseSpeedProfile(false); 359 if (traininfo.getAttribute("usespeedprofile").getValue().equals("yes")) { 360 tInfo.setUseSpeedProfile(true); 361 } 362 } 363 if (traininfo.getAttribute("stopbyspeedprofile") != null) { 364 tInfo.setStopBySpeedProfile(false); 365 if (traininfo.getAttribute("stopbyspeedprofile").getValue().equals("yes")) { 366 tInfo.setStopBySpeedProfile(true); 367 } 368 } 369 if (traininfo.getAttribute("stopbyspeedprofileadjust") != null) { 370 tInfo.setStopBySpeedProfileAdjust(traininfo.getAttribute("stopbyspeedprofileadjust").getFloatValue()); 371 } 372 if (traininfo.getAttribute("waittime") != null) { 373 tInfo.setWaitTime(traininfo.getAttribute("waittime").getFloatValue()); 374 } 375 if (traininfo.getAttribute("blockname") != null) { 376 tInfo.setBlockName(traininfo.getAttribute("blockname").getValue()); 377 } 378 379 if (version == 1) { 380 String parseArray[]; 381 // If you only have a systemname then its everything before the dash 382 tInfo.setStartBlockId(tInfo.getStartBlockName().split("-")[0]); 383 // If you have a systemname and username you want everything before the open bracket 384 tInfo.setStartBlockId(tInfo.getStartBlockId().split("\\(")[0]); 385 // to guard against a dash in the names, we need the last part, not just [1] 386 parseArray = tInfo.getStartBlockName().split("-"); 387 tInfo.setStartBlockSeq(-1); // default value 388 if (parseArray.length > 0) { 389 try { 390 tInfo.setStartBlockSeq(Integer.parseInt(parseArray[parseArray.length -1])); 391 } 392 catch (Exception Ex) { 393 log.error("Invalid StartBlockSequence{}",parseArray[parseArray.length -1]); 394 } 395 } 396 // repeat for destination 397 tInfo.setDestinationBlockId(tInfo.getDestinationBlockName().split("-")[0]); 398 tInfo.setDestinationBlockId(tInfo.getDestinationBlockId().split("\\(")[0]); 399 parseArray = tInfo.getDestinationBlockName().split("-"); 400 tInfo.setDestinationBlockSeq(-1); 401 if (parseArray.length > 0) { 402 try { 403 tInfo.setDestinationBlockSeq(Integer.parseInt(parseArray[parseArray.length -1])); 404 } 405 catch (Exception Ex) { 406 log.error("Invalid StartBlockSequence{}",parseArray[parseArray.length -1]); 407 } 408 } 409 // Transit we need the whole thing or the bit before the first open bracket 410 tInfo.setTransitId(tInfo.getTransitName().split("\\(")[0]); 411 log.debug("v1: t = {}, bs = {}, be = {}", tInfo.getTransitName(), tInfo.getStartBlockName(), tInfo.getDestinationBlockName()); 412 } 413 if ( version > 1 ) { 414 if (traininfo.getAttribute("transitid") != null) { 415 // there is a transit name selected 416 tInfo.setTransitId(traininfo.getAttribute("transitid").getValue()); 417 } else { 418 log.error("Transit id missing when reading TrainInfoFile {}", name); 419 } 420 if (traininfo.getAttribute("startblockid") != null) { 421 // there is a transit name selected 422 tInfo.setStartBlockId(traininfo.getAttribute("startblockid").getValue()); 423 } else { 424 log.error("Start block Id missing when reading TrainInfoFile {}", name); 425 } 426 if (traininfo.getAttribute("endblockid") != null) { 427 // there is a transit name selected 428 tInfo.setDestinationBlockId(traininfo.getAttribute("endblockid").getValue()); 429 } else { 430 log.error("Destination block Id missing when reading TrainInfoFile {}", name); 431 } 432 if (traininfo.getAttribute("startblockseq") != null) { 433 // there is a transit name selected 434 try { 435 tInfo.setStartBlockSeq(traininfo.getAttribute("startblockseq").getIntValue()); 436 } 437 catch (Exception ex) { 438 log.error("Start block sequence invalid when reading TrainInfoFile"); 439 } 440 } else { 441 log.error("Start block sequence missing when reading TrainInfoFile {}", name); 442 } 443 if (traininfo.getAttribute("endblockseq") != null) { 444 // there is a transit name selected 445 try { 446 tInfo.setDestinationBlockSeq(traininfo.getAttribute("endblockseq").getIntValue()); 447 } 448 catch (Exception ex) { 449 log.error("Destination block sequence invalid when reading TrainInfoFile {}", name); 450 } 451 } else { 452 log.error("Destination block sequence missing when reading TrainInfoFile {}", name); 453 } 454 } 455 if ( version == 1 || version == 2) { 456 // Change transit and block names from sysName(userName) to displayName 457 tInfo.setTransitName(convertName(tInfo.getTransitName())); 458 tInfo.setStartBlockName(convertName(tInfo.getStartBlockName())); 459 tInfo.setDestinationBlockName(convertName(tInfo.getDestinationBlockName())); 460 } 461 } 462 } 463 } 464 return tInfo; 465 } 466 467 public String convertName(String name) { 468 // transit: sys(user), block: sys(user)-n 469 String newName = name; 470 471 Pattern p = Pattern.compile(".+\\((.+)\\)(-\\d+)*"); 472 Matcher m = p.matcher(name); 473 if (m.matches()) { 474 log.debug("regex: name = '{}', group 1 = '{}', group 2 = '{}'", name, m.group(1), m.group(2)); 475 if (m.group(1) != null) { 476 newName = m.group(1).trim(); 477 if (m.group(2) != null) { 478 newName = newName + m.group(2).trim(); 479 } 480 } 481 } 482 483 log.debug("convertName: old = '{}', new = '{}'", name, newName); 484 return newName; 485 } 486 487 /* 488 * Writes out Dispatcher options to a file in the user's preferences directory 489 */ 490 public void writeTrainInfo(TrainInfo tf, String name) throws java.io.IOException { 491 log.debug("entered writeTrainInfo"); 492 root = new Element("traininfofile"); 493 doc = newDocument(root, dtdLocation + "dispatcher-traininfo.dtd"); 494 // add XSLT processing instruction 495 // <?xml-stylesheet type="text/xsl" href="XSLT/block-values.xsl"?> 496 java.util.Map<String, String> m = new java.util.HashMap<>(); 497 m.put("type", "text/xsl"); 498 m.put("href", xsltLocation + "dispatcher-traininfo.xsl"); 499 org.jdom2.ProcessingInstruction p = new org.jdom2.ProcessingInstruction("xml-stylesheet", m); 500 doc.addContent(0, p); 501 502 // save Dispatcher TrainInfo in xml format 503 Element traininfo = new Element("traininfo"); 504 // write version number 505 traininfo.setAttribute("version", "7"); 506 traininfo.setAttribute("transitname", tf.getTransitName()); 507 traininfo.setAttribute("transitid", tf.getTransitId()); 508 traininfo.setAttribute("trainname", tf.getTrainName()); 509 traininfo.setAttribute("trainusername", tf.getTrainUserName()); 510 traininfo.setAttribute("rosterid", tf.getRosterId()); 511 traininfo.setAttribute("dccaddress", tf.getDccAddress()); 512 traininfo.setAttribute("trainintransit", "" + (tf.getTrainInTransit() ? "yes" : "no")); 513 traininfo.setAttribute("startblockname", tf.getStartBlockName()); 514 traininfo.setAttribute("startblockid", tf.getStartBlockId()); 515 traininfo.setAttribute("startblockseq", Integer.toString(tf.getStartBlockSeq())); 516 traininfo.setAttribute("endblockname", tf.getDestinationBlockName()); 517 traininfo.setAttribute("endblockid", tf.getDestinationBlockId()); 518 traininfo.setAttribute("endblockseq", Integer.toString(tf.getDestinationBlockSeq())); 519 traininfo.setAttribute("trainfromroster", "" + (tf.getTrainFromRoster() ? "yes" : "no")); 520 traininfo.setAttribute("trainfromtrains", "" + (tf.getTrainFromTrains() ? "yes" : "no")); 521 traininfo.setAttribute("trainfromuser", "" + (tf.getTrainFromUser() ? "yes" : "no")); 522 traininfo.setAttribute("trainfromsetlater", "" + (tf.getTrainFromSetLater() ? "yes" : "no")); 523 traininfo.setAttribute("priority", Integer.toString(tf.getPriority())); 524 traininfo.setAttribute("traindetection", trainsdectionFromEnumMap.outputFromEnum(tf.getTrainDetection())); 525 traininfo.setAttribute("resetwhendone", "" + (tf.getResetWhenDone() ? "yes" : "no")); 526 switch (tf.getDelayedRestart()) { 527 case ActiveTrain.SENSORDELAY: 528 traininfo.setAttribute("delayedrestart", "sensor"); 529 traininfo.setAttribute("delayedrestartsensor", tf.getRestartSensorName()); 530 traininfo.setAttribute("resetrestartsensor", "" + (tf.getResetRestartSensor() ? "yes" : "no")); 531 break; 532 case ActiveTrain.TIMEDDELAY: 533 traininfo.setAttribute("delayedrestart", "timed"); 534 traininfo.setAttribute("delayedrestarttime", Integer.toString(tf.getRestartDelayMin())); 535 break; 536 default: 537 traininfo.setAttribute("delayedrestart", "no"); 538 break; 539 } 540 541 traininfo.setAttribute("reverseatend", "" + (tf.getReverseAtEnd() ? "yes" : "no")); 542 switch (tf.getReverseDelayedRestart()) { 543 case ActiveTrain.SENSORDELAY: 544 traininfo.setAttribute("reversedelayedrestart", "sensor"); 545 traininfo.setAttribute("reversedelayedrestartsensor", tf.getReverseRestartSensorName()); 546 traininfo.setAttribute("reverseresetrestartsensor", "" + (tf.getReverseResetRestartSensor() ? "yes" : "no")); 547 break; 548 case ActiveTrain.TIMEDDELAY: 549 traininfo.setAttribute("reversedelayedrestart", "timed"); 550 traininfo.setAttribute("reversedelayedrestarttime", Integer.toString(tf.getReverseRestartDelayMin())); 551 break; 552 default: 553 traininfo.setAttribute("reversedelayedrestart", "no"); 554 break; 555 } 556 if (tf.getDelayedStart() == ActiveTrain.TIMEDDELAY) { 557 traininfo.setAttribute("delayedstart", "timed"); 558 } else if (tf.getDelayedStart() == ActiveTrain.SENSORDELAY) { 559 traininfo.setAttribute("delayedstart", "sensor"); 560 if (tf.getDelaySensorName() != null) { 561 traininfo.setAttribute("delayedSensor", tf.getDelaySensorName()); 562 traininfo.setAttribute("resetstartsensor", "" + (tf.getResetStartSensor() ? "yes" : "no")); 563 } 564 } 565 566 traininfo.setAttribute("terminatewhendone", (tf.getTerminateWhenDone() ? "yes" : "no")); 567 traininfo.setAttribute("departuretimehr", Integer.toString(tf.getDepartureTimeHr())); 568 traininfo.setAttribute("departuretimemin", Integer.toString(tf.getDepartureTimeMin())); 569 traininfo.setAttribute("traintype", tf.getTrainType()); 570 traininfo.setAttribute("autorun", "" + (tf.getAutoRun() ? "yes" : "no")); 571 traininfo.setAttribute("loadatstartup", "" + (tf.getLoadAtStartup() ? "yes" : "no")); 572 traininfo.setAttribute("allocatealltheway", "" + (tf.getAllocateAllTheWay() ? "yes" : "no")); 573 traininfo.setAttribute("allocationmethod", Integer.toString(tf.getAllocationMethod())); 574 traininfo.setAttribute("nexttrain", tf.getNextTrain()); 575 // here save items related to automatically running active trains 576 traininfo.setAttribute("speedfactor", Float.toString(tf.getSpeedFactor())); 577 traininfo.setAttribute("maxspeed", Float.toString(tf.getMaxSpeed())); 578 traininfo.setAttribute("minreliableoperatingspeed", Float.toString(tf.getMinReliableOperatingSpeed())); 579 traininfo.setAttribute("ramprate", tf.getRampRate()); 580 traininfo.setAttribute("runinreverse", "" + (tf.getRunInReverse() ? "yes" : "no")); 581 traininfo.setAttribute("sounddecoder", "" + (tf.getSoundDecoder() ? "yes" : "no")); 582 traininfo.setAttribute("maxtrainlengthscalemeters", Float.toString(tf.getMaxTrainLengthScaleMeters())); 583 traininfo.setAttribute("trainlengthunits", trainlengthFromEnumMap.outputFromEnum(tf.getTrainLengthUnits())); 584 traininfo.setAttribute("usespeedprofile", "" + (tf.getUseSpeedProfile() ? "yes" : "no")); 585 traininfo.setAttribute("stopbyspeedprofile", "" + (tf.getStopBySpeedProfile() ? "yes" : "no")); 586 traininfo.setAttribute("stopbyspeedprofileadjust", Float.toString(tf.getStopBySpeedProfileAdjust())); 587 traininfo.setAttribute("waittime", Float.toString(tf.getWaitTime())); 588 traininfo.setAttribute("blockname", tf.getBlockName()); 589 590 root.addContent(traininfo); 591 592 // write out the file 593 try { 594 if (!checkFile(fileLocation + name)) { 595 // file does not exist, create it 596 File file = new File(fileLocation + name); 597 if (!file.createNewFile()) // create file and check result 598 { 599 log.error("createNewFile failed"); 600 } 601 } 602 // write content to file 603 writeXML(findFile(fileLocation + name), doc); 604 } catch (java.io.IOException ioe) { 605 log.error("IO Exception writing", ioe); 606 throw (ioe); 607 } 608 } 609 610 /** 611 * Get the names of all current TrainInfo files. Returns names as an array 612 * of Strings. Returns an empty array if no files are present. Note: Fill 613 * names still end with .xml or .XML. (Modeled after a method in 614 * RecreateRosterAction.java by Bob Jacobsen) 615 * 616 * @return names as an array or an empty array if none present 617 */ 618 public String[] getTrainInfoFileNames() { 619 // ensure preferences will be found for read 620 FileUtil.createDirectory(fileLocation); 621 // create an array of file names from roster dir in preferences, count entries 622 List<String> names = new ArrayList<>(); 623 log.debug("directory of TrainInfoFiles is {}", fileLocation); 624 File fp = new File(fileLocation); 625 if (fp.exists()) { 626 String[] xmlList = fp.list(new XmlFilenameFilter()); 627 if (xmlList!=null) { 628 names.addAll(Arrays.asList(xmlList)); 629 } 630 } 631 // Sort the resulting array 632 names.sort((s1, s2) -> { 633 return s1.compareTo(s2); 634 }); 635 return names.toArray(new String[names.size()]); 636 } 637 638 /** 639 * Delete a specified TrainInfo file. 640 * 641 * @param name the file to delete 642 */ 643 public void deleteTrainInfoFile(String name) { 644 // locate the file and delete it if it exists 645 File f = new File(fileLocation + name); 646 if (!f.delete()) { // delete file and check success 647 log.error("failed to delete TrainInfo file - {}", name); 648 } 649 } 650 651 private final static Logger log = LoggerFactory.getLogger(TrainInfoFile.class); 652}