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