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