001package jmri.jmrit.operations.trains; 002 003import java.io.*; 004import java.nio.charset.StandardCharsets; 005import java.text.MessageFormat; 006import java.util.ArrayList; 007import java.util.List; 008 009import org.slf4j.Logger; 010import org.slf4j.LoggerFactory; 011 012import jmri.InstanceManager; 013import jmri.jmrit.operations.locations.Location; 014import jmri.jmrit.operations.locations.Track; 015import jmri.jmrit.operations.rollingstock.cars.*; 016import jmri.jmrit.operations.rollingstock.engines.Engine; 017import jmri.jmrit.operations.routes.Route; 018import jmri.jmrit.operations.routes.RouteLocation; 019import jmri.jmrit.operations.setup.Control; 020import jmri.jmrit.operations.setup.Setup; 021import jmri.jmrit.operations.trains.schedules.TrainSchedule; 022import jmri.jmrit.operations.trains.schedules.TrainScheduleManager; 023import jmri.util.FileUtil; 024 025/** 026 * Builds a switch list for a location on the railroad 027 * 028 * @author Daniel Boudreau (C) Copyright 2008, 2011, 2012, 2013, 2015, 2024 029 */ 030public class TrainSwitchLists extends TrainCommon { 031 032 TrainManager trainManager = InstanceManager.getDefault(TrainManager.class); 033 private static final char FORM_FEED = '\f'; 034 private static final boolean IS_PRINT_HEADER = true; 035 036 String messageFormatText = ""; // the text being formated in case there's an exception 037 038 /** 039 * Builds a switch list for a location showing the work by train arrival 040 * time. If not running in real time, new train work is appended to the end 041 * of the file. User has the ability to modify the text of the messages 042 * which can cause an IllegalArgumentException. Some messages have more 043 * arguments than the default message allowing the user to customize the 044 * message to their liking. There also an option to list all of the car work 045 * by track name. This option is only available in real time and is shown 046 * after the switch list by train. 047 * 048 * @param location The Location needing a switch list 049 */ 050 public void buildSwitchList(Location location) { 051 052 boolean append = false; // add text to end of file when true 053 boolean checkFormFeed = true; // used to determine if FF needed between trains 054 055 // Append switch list data if not operating in real time 056 if (!Setup.isSwitchListRealTime()) { 057 if (!location.getStatus().equals(Location.MODIFIED) && !Setup.isSwitchListAllTrainsEnabled()) { 058 return; // nothing to add 059 } 060 append = location.getSwitchListState() == Location.SW_APPEND; 061 location.setSwitchListState(Location.SW_APPEND); 062 } 063 064 log.debug("Append: {} for location ({})", append, location.getName()); 065 066 // create switch list file 067 File file = InstanceManager.getDefault(TrainManagerXml.class).createSwitchListFile(location.getName()); 068 069 PrintWriter fileOut = null; 070 try { 071 fileOut = new PrintWriter(new BufferedWriter( 072 new OutputStreamWriter(new FileOutputStream(file, append), StandardCharsets.UTF_8)), true); 073 } catch (IOException e) { 074 log.error("Can not open switchlist file: {}", e.getLocalizedMessage()); 075 return; 076 } 077 try { 078 // build header 079 if (!append) { 080 newLine(fileOut, Setup.getRailroadName()); 081 newLine(fileOut); 082 newLine(fileOut, MessageFormat.format(messageFormatText = TrainSwitchListText.getStringSwitchListFor(), 083 new Object[]{location.getSplitName()})); 084 if (!location.getSwitchListCommentWithColor().isEmpty()) { 085 newLine(fileOut, location.getSwitchListCommentWithColor()); 086 } 087 } else { 088 newLine(fileOut); 089 } 090 091 // get a list of built trains sorted by arrival time 092 List<Train> trains = trainManager.getTrainsArrivingThisLocationList(location); 093 for (Train train : trains) { 094 if (!Setup.isSwitchListRealTime() && train.getSwitchListStatus().equals(Train.PRINTED)) { 095 continue; // already printed this train 096 } 097 Route route = train.getRoute(); 098 // TODO throw exception? only built trains should be in the list, so no route is 099 // an error 100 if (route == null) { 101 continue; // no route for this train 102 } // determine if train works this location 103 boolean works = isThereWorkAtLocation(train, location); 104 if (!works && !Setup.isSwitchListAllTrainsEnabled()) { 105 log.debug("No work for train ({}) at location ({})", train.getName(), location.getName()); 106 continue; 107 } 108 // we're now going to add to the switch list 109 if (checkFormFeed) { 110 if (append && !Setup.getSwitchListPageFormat().equals(Setup.PAGE_NORMAL)) { 111 fileOut.write(FORM_FEED); 112 } 113 if (Setup.isPrintValidEnabled()) { 114 newLine(fileOut, getValid()); 115 } 116 } else if (!Setup.getSwitchListPageFormat().equals(Setup.PAGE_NORMAL)) { 117 fileOut.write(FORM_FEED); 118 } 119 checkFormFeed = false; // done with FF for this train 120 // some cars booleans and the number of times this location get's serviced 121 _pickupCars = false; // when true there was a car pick up 122 _dropCars = false; // when true there was a car set out 123 int stops = 1; 124 boolean trainDone = false; 125 // get engine and car lists 126 List<Engine> engineList = engineManager.getByTrainBlockingList(train); 127 List<Car> carList = carManager.getByTrainDestinationList(train); 128 List<RouteLocation> routeList = route.getLocationsBySequenceList(); 129 RouteLocation rlPrevious = null; 130 // does the train stop once or more at this location? 131 for (RouteLocation rl : routeList) { 132 if (!rl.getSplitName().equals(location.getSplitName())) { 133 rlPrevious = rl; 134 continue; 135 } 136 if (train.getExpectedArrivalTime(rl).equals(Train.ALREADY_SERVICED)) { 137 trainDone = true; 138 } 139 // first time at this location? 140 if (stops == 1) { 141 firstTimeMessages(fileOut, train, rl); 142 stops++; 143 } else { 144 // multiple visits to this location 145 // Print visit number only if previous location isn't the same 146 if (rlPrevious == null || 147 !rl.getSplitName().equals(rlPrevious.getSplitName())) { 148 multipleVisitMessages(fileOut, train, rl, rlPrevious, stops); 149 stops++; 150 } else { 151 // don't bump stop count, same location 152 // Does the train reverse direction? 153 reverseDirectionMessage(fileOut, train, rl, rlPrevious); 154 } 155 } 156 157 // save current location in case there's back to back location with the same name 158 rlPrevious = rl; 159 160 // add route comment 161 if (Setup.isSwitchListRouteLocationCommentEnabled() && !rl.getComment().trim().isEmpty()) { 162 newLine(fileOut, rl.getCommentWithColor()); 163 } 164 165 printTrackComments(fileOut, rl, carList, !IS_MANIFEST); 166 167 if (isThereWorkAtLocation(carList, engineList, rl)) { 168 // now print out the work for this location 169 if (Setup.getManifestFormat().equals(Setup.STANDARD_FORMAT)) { 170 pickupEngines(fileOut, engineList, rl, !IS_MANIFEST); 171 // if switcher show loco drop at end of list 172 if (train.isLocalSwitcher()) { 173 blockCarsByTrack(fileOut, train, carList, rl, IS_PRINT_HEADER, !IS_MANIFEST); 174 dropEngines(fileOut, engineList, rl, !IS_MANIFEST); 175 } else { 176 dropEngines(fileOut, engineList, rl, !IS_MANIFEST); 177 blockCarsByTrack(fileOut, train, carList, rl, IS_PRINT_HEADER, !IS_MANIFEST); 178 } 179 } else if (Setup.getManifestFormat().equals(Setup.TWO_COLUMN_FORMAT)) { 180 blockLocosTwoColumn(fileOut, engineList, rl, !IS_MANIFEST); 181 blockCarsTwoColumn(fileOut, train, carList, rl, IS_PRINT_HEADER, !IS_MANIFEST); 182 } else { 183 blockLocosTwoColumn(fileOut, engineList, rl, !IS_MANIFEST); 184 blockCarsByTrackNameTwoColumn(fileOut, train, carList, rl, IS_PRINT_HEADER, !IS_MANIFEST); 185 } 186 // print horizontal line if there was work and enabled 187 if (Setup.isPrintHeadersEnabled() || !Setup.getManifestFormat().equals(Setup.STANDARD_FORMAT)) { 188 printHorizontalLine(fileOut, !IS_MANIFEST); 189 } 190 } 191 192 // done with work, now print summary for this location if we're done 193 if (rl != train.getTrainTerminatesRouteLocation()) { 194 RouteLocation nextRl = train.getRoute().getNextRouteLocation(rl); 195 if (rl.getSplitName().equals(nextRl.getSplitName())) { 196 continue; // the current location name is the "same" as the next 197 } 198 // print departure text if not a switcher 199 if (!train.isLocalSwitcher() && !trainDone) { 200 departureMessages(fileOut, train, rl); 201 } 202 } 203 } 204 // report if no pick ups or set outs or train has left 205 trainSummaryMessages(fileOut, train, location, trainDone, stops); 206 } 207 208 // now report car movement by tracks at location 209 reportByTrack(fileOut, location); 210 211 } catch (IllegalArgumentException e) { 212 newLine(fileOut, Bundle.getMessage("ErrorIllegalArgument", 213 Bundle.getMessage("TitleSwitchListText"), e.getLocalizedMessage())); 214 newLine(fileOut, messageFormatText); 215 log.error("Illegal argument", e); 216 } 217 218 // Are there any cars that need to be found? 219 addCarsLocationUnknown(fileOut, !IS_MANIFEST); 220 fileOut.flush(); 221 fileOut.close(); 222 location.setStatus(Location.UPDATED); 223 } 224 225 private String getValid() { 226 String valid = MessageFormat.format(messageFormatText = TrainManifestText.getStringValid(), 227 new Object[]{getDate(true)}); 228 if (Setup.isPrintTrainScheduleNameEnabled()) { 229 TrainSchedule sch = InstanceManager.getDefault(TrainScheduleManager.class).getActiveSchedule(); 230 if (sch != null) { 231 valid = valid + " (" + sch.getName() + ")"; 232 } 233 } 234 return valid; 235 } 236 237 /* 238 * Messages for the switch list when the train first arrives 239 */ 240 private void firstTimeMessages(PrintWriter fileOut, Train train, RouteLocation rl) { 241 String expectedArrivalTime = train.getExpectedArrivalTime(rl); 242 newLine(fileOut); 243 newLine(fileOut, 244 MessageFormat.format(messageFormatText = TrainSwitchListText.getStringScheduledWork(), 245 new Object[]{train.getName(), train.getDescription()})); 246 if (train.isTrainEnRoute()) { 247 if (!expectedArrivalTime.equals(Train.ALREADY_SERVICED)) { 248 // Departed {0}, expect to arrive in {1}, arrives {2}bound 249 newLine(fileOut, 250 MessageFormat.format( 251 messageFormatText = TrainSwitchListText.getStringDepartedExpected(), 252 new Object[]{splitString(train.getTrainDepartsName()), 253 expectedArrivalTime, rl.getTrainDirectionString(), 254 train.getCurrentLocationName()})); 255 } 256 } else if (!train.isLocalSwitcher()) { 257 // train hasn't departed 258 if (rl == train.getTrainDepartsRouteLocation()) { 259 // Departs {0} {1}bound at {2} 260 newLine(fileOut, MessageFormat.format( 261 messageFormatText = TrainSwitchListText.getStringDepartsAt(), 262 new Object[]{splitString(train.getTrainDepartsName()), 263 rl.getTrainDirectionString(), 264 train.getFormatedDepartureTime()})); 265 } else if (Setup.isUseSwitchListDepartureTimeEnabled() && 266 rl != train.getTrainTerminatesRouteLocation()) { 267 // Departs {0} at {1} expected arrival {2}, arrives {3}bound 268 newLine(fileOut, MessageFormat.format( 269 messageFormatText = TrainSwitchListText.getStringDepartsAtExpectedArrival(), 270 new Object[]{splitString(rl.getName()), 271 train.getExpectedDepartureTime(rl), expectedArrivalTime, 272 rl.getTrainDirectionString()})); 273 } else { 274 // Departs {0} at {1} expected arrival {2}, arrives {3}bound 275 newLine(fileOut, MessageFormat.format( 276 messageFormatText = TrainSwitchListText.getStringDepartsAtExpectedArrival(), 277 new Object[]{splitString(train.getTrainDepartsName()), 278 train.getFormatedDepartureTime(), expectedArrivalTime, 279 rl.getTrainDirectionString()})); 280 } 281 } 282 } 283 284 /* 285 * Messages when a train services the location two or more times 286 */ 287 private void multipleVisitMessages(PrintWriter fileOut, Train train, RouteLocation rl, RouteLocation rlPrevious, 288 int stops) { 289 String expectedArrivalTime = train.getExpectedArrivalTime(rl); 290 if (rlPrevious == null || 291 !rl.getSplitName().equals(rlPrevious.getSplitName())) { 292 if (Setup.getSwitchListPageFormat().equals(Setup.PAGE_PER_VISIT)) { 293 fileOut.write(FORM_FEED); 294 } 295 newLine(fileOut); 296 if (train.isTrainEnRoute()) { 297 if (expectedArrivalTime.equals(Train.ALREADY_SERVICED)) { 298 // Visit number {0} for train ({1}) 299 newLine(fileOut, 300 MessageFormat.format( 301 messageFormatText = TrainSwitchListText.getStringVisitNumberDone(), 302 new Object[]{stops, train.getName(), train.getDescription()})); 303 } else if (rl != train.getTrainTerminatesRouteLocation()) { 304 // Visit number {0} for train ({1}) expect to arrive in {2}, arrives {3}bound 305 newLine(fileOut, MessageFormat.format( 306 messageFormatText = TrainSwitchListText.getStringVisitNumberDeparted(), 307 new Object[]{stops, train.getName(), expectedArrivalTime, 308 rl.getTrainDirectionString(), train.getDescription()})); 309 } else { 310 // Visit number {0} for train ({1}) expect to arrive in {2}, terminates {3} 311 newLine(fileOut, 312 MessageFormat.format( 313 messageFormatText = TrainSwitchListText 314 .getStringVisitNumberTerminatesDeparted(), 315 new Object[]{stops, train.getName(), expectedArrivalTime, 316 rl.getSplitName(), train.getDescription()})); 317 } 318 } else { 319 // train hasn't departed 320 if (rl != train.getTrainTerminatesRouteLocation()) { 321 // Visit number {0} for train ({1}) expected arrival {2}, arrives {3}bound 322 newLine(fileOut, 323 MessageFormat.format( 324 messageFormatText = TrainSwitchListText.getStringVisitNumber(), 325 new Object[]{stops, train.getName(), expectedArrivalTime, 326 rl.getTrainDirectionString(), train.getDescription()})); 327 if (Setup.isUseSwitchListDepartureTimeEnabled()) { 328 // Departs {0} {1}bound at {2} 329 newLine(fileOut, MessageFormat.format( 330 messageFormatText = TrainSwitchListText.getStringDepartsAt(), 331 new Object[]{splitString(rl.getName()), 332 rl.getTrainDirectionString(), 333 train.getExpectedDepartureTime(rl)})); 334 } 335 } else { 336 // Visit number {0} for train ({1}) expected arrival {2}, terminates {3} 337 newLine(fileOut, MessageFormat.format( 338 messageFormatText = TrainSwitchListText.getStringVisitNumberTerminates(), 339 new Object[]{stops, train.getName(), expectedArrivalTime, 340 rl.getSplitName(), train.getDescription()})); 341 } 342 } 343 } 344 } 345 346 private void reverseDirectionMessage(PrintWriter fileOut, Train train, RouteLocation rl, RouteLocation rlPrevious) { 347 // Does the train reverse direction? 348 if (rl.getTrainDirection() != rlPrevious.getTrainDirection() && 349 !TrainSwitchListText.getStringTrainDirectionChange().isEmpty()) { 350 // Train ({0}) direction change, departs {1}bound 351 newLine(fileOut, 352 MessageFormat.format( 353 messageFormatText = TrainSwitchListText.getStringTrainDirectionChange(), 354 new Object[]{train.getName(), rl.getTrainDirectionString(), 355 train.getDescription(), train.getTrainTerminatesName()})); 356 } 357 } 358 359 /* 360 * Train departure messages at the end of the switch list 361 */ 362 private void departureMessages(PrintWriter fileOut, Train train, RouteLocation rl) { 363 String trainDeparts = ""; 364 if (Setup.isPrintLoadsAndEmptiesEnabled()) { 365 int emptyCars = train.getNumberEmptyCarsInTrain(rl); 366 // Train departs {0} {1}bound with {2} loads, {3} empties, {4} {5}, {6} tons 367 trainDeparts = MessageFormat.format(TrainSwitchListText.getStringTrainDepartsLoads(), 368 new Object[]{rl.getSplitName(), 369 rl.getTrainDirectionString(), 370 train.getNumberCarsInTrain(rl) - emptyCars, emptyCars, 371 train.getTrainLength(rl), Setup.getLengthUnit().toLowerCase(), 372 train.getTrainWeight(rl), train.getTrainTerminatesName(), 373 train.getName()}); 374 } else { 375 // Train departs {0} {1}bound with {2} cars, {3} {4}, {5} tons 376 trainDeparts = MessageFormat.format(TrainSwitchListText.getStringTrainDepartsCars(), 377 new Object[]{rl.getSplitName(), 378 rl.getTrainDirectionString(), train.getNumberCarsInTrain(rl), 379 train.getTrainLength(rl), Setup.getLengthUnit().toLowerCase(), 380 train.getTrainWeight(rl), train.getTrainTerminatesName(), 381 train.getName()}); 382 } 383 newLine(fileOut, trainDeparts); 384 } 385 386 private void trainSummaryMessages(PrintWriter fileOut, Train train, Location location, boolean trainDone, 387 int stops) { 388 if (trainDone && !_pickupCars && !_dropCars) { 389 // Default message: Train ({0}) has serviced this location 390 newLine(fileOut, MessageFormat.format(messageFormatText = TrainSwitchListText.getStringTrainDone(), 391 new Object[]{train.getName(), train.getDescription(), location.getSplitName()})); 392 } else { 393 if (stops > 1 && !_pickupCars) { 394 // Default message: No car pick ups for train ({0}) at this location 395 newLine(fileOut, 396 MessageFormat.format(messageFormatText = TrainSwitchListText.getStringNoCarPickUps(), 397 new Object[]{train.getName(), train.getDescription(), 398 location.getSplitName()})); 399 } 400 if (stops > 1 && !_dropCars) { 401 // Default message: No car set outs for train ({0}) at this location 402 newLine(fileOut, 403 MessageFormat.format(messageFormatText = TrainSwitchListText.getStringNoCarDrops(), 404 new Object[]{train.getName(), train.getDescription(), 405 location.getSplitName()})); 406 } 407 } 408 } 409 410 private void reportByTrack(PrintWriter fileOut, Location location) { 411 if (Setup.isPrintTrackSummaryEnabled() && Setup.isSwitchListRealTime()) { 412 clearUtilityCarTypes(); // list utility cars by quantity 413 if (Setup.getSwitchListPageFormat().equals(Setup.PAGE_NORMAL)) { 414 newLine(fileOut); 415 newLine(fileOut); 416 } else { 417 fileOut.write(FORM_FEED); 418 } 419 newLine(fileOut, 420 MessageFormat.format(messageFormatText = TrainSwitchListText.getStringSwitchListByTrack(), 421 new Object[]{location.getSplitName()})); 422 423 // we only need the cars delivered to or at this location 424 List<Car> rsList = carManager.getByTrainList(); 425 List<Car> carList = new ArrayList<>(); 426 for (Car rs : rsList) { 427 if ((rs.getLocation() != null && 428 rs.getLocation().getSplitName().equals(location.getSplitName())) || 429 (rs.getDestination() != null && 430 rs.getSplitDestinationName().equals(location.getSplitName()))) 431 carList.add(rs); 432 } 433 434 List<String> trackNames = new ArrayList<>(); // locations and tracks can have "similar" names, only list 435 // track names once 436 for (Location loc : locationManager.getLocationsByNameList()) { 437 if (!loc.getSplitName().equals(location.getSplitName())) 438 continue; 439 for (Track track : loc.getTracksByBlockingOrderList(null)) { 440 String trackName = track.getSplitName(); 441 if (trackNames.contains(trackName)) 442 continue; 443 trackNames.add(trackName); 444 445 String trainName = ""; // for printing train message once 446 newLine(fileOut); 447 newLine(fileOut, trackName); // print out just the track name 448 // now show the cars pickup and holds for this track 449 for (Car car : carList) { 450 if (!car.getSplitTrackName().equals(trackName)) { 451 continue; 452 } 453 // is the car scheduled for pickup? 454 if (car.getRouteLocation() != null) { 455 if (car.getRouteLocation().getLocation().getSplitName() 456 .equals(location.getSplitName())) { 457 // cars are sorted by train name, print train message once 458 if (!trainName.equals(car.getTrainName())) { 459 trainName = car.getTrainName(); 460 newLine(fileOut, MessageFormat.format( 461 messageFormatText = TrainSwitchListText.getStringScheduledWork(), 462 new Object[]{car.getTrainName(), car.getTrain().getDescription()})); 463 printPickupCarHeader(fileOut, !IS_MANIFEST, !IS_TWO_COLUMN_TRACK); 464 } 465 if (car.isUtility()) { 466 pickupUtilityCars(fileOut, carList, car, false, !IS_MANIFEST); 467 } else { 468 pickUpCar(fileOut, car, !IS_MANIFEST); 469 } 470 } 471 // car holds 472 } else if (car.isUtility()) { 473 String s = pickupUtilityCars(carList, car, !IS_MANIFEST, !IS_TWO_COLUMN_TRACK); 474 if (s != null) { 475 newLine(fileOut, TrainSwitchListText.getStringHoldCar().split("\\{")[0] + s.trim()); // NOI18N 476 } 477 } else { 478 newLine(fileOut, 479 MessageFormat.format(messageFormatText = TrainSwitchListText.getStringHoldCar(), 480 new Object[]{ 481 padAndTruncateIfNeeded(car.getRoadName(), 482 InstanceManager.getDefault(CarRoads.class) 483 .getMaxNameLength()), 484 padAndTruncateIfNeeded( 485 TrainCommon.splitString(car.getNumber()), 486 Control.max_len_string_print_road_number), 487 padAndTruncateIfNeeded( 488 car.getTypeName().split(TrainCommon.HYPHEN)[0], 489 InstanceManager.getDefault(CarTypes.class) 490 .getMaxNameLength()), 491 padAndTruncateIfNeeded( 492 car.getLength() + Setup.getLengthUnitAbv(), 493 Control.max_len_string_length_name), 494 padAndTruncateIfNeeded(car.getLoadName(), 495 InstanceManager.getDefault(CarLoads.class) 496 .getMaxNameLength()), 497 padAndTruncateIfNeeded(trackName, 498 locationManager.getMaxTrackNameLength()), 499 padAndTruncateIfNeeded(car.getColor(), InstanceManager 500 .getDefault(CarColors.class).getMaxNameLength())})); 501 } 502 } 503 // now do set outs at this location 504 for (Car car : carList) { 505 if (!car.getSplitDestinationTrackName().equals(trackName)) { 506 continue; 507 } 508 if (car.getRouteDestination() != null && 509 car.getRouteDestination().getLocation().getSplitName() 510 .equals(location.getSplitName())) { 511 // cars are sorted by train name, print train message once 512 if (!trainName.equals(car.getTrainName())) { 513 trainName = car.getTrainName(); 514 newLine(fileOut, MessageFormat.format( 515 messageFormatText = TrainSwitchListText.getStringScheduledWork(), 516 new Object[]{car.getTrainName(), car.getTrain().getDescription()})); 517 printDropCarHeader(fileOut, !IS_MANIFEST, !IS_TWO_COLUMN_TRACK); 518 } 519 if (car.isUtility()) { 520 setoutUtilityCars(fileOut, carList, car, false, !IS_MANIFEST); 521 } else { 522 dropCar(fileOut, car, !IS_MANIFEST); 523 } 524 } 525 } 526 } 527 } 528 } 529 } 530 531 public void printSwitchList(Location location, boolean isPreview) { 532 File switchListFile = InstanceManager.getDefault(TrainManagerXml.class).getSwitchListFile(location.getName()); 533 if (!switchListFile.exists()) { 534 log.warn("Switch list file missing for location ({})", location.getName()); 535 return; 536 } 537 if (isPreview && Setup.isManifestEditorEnabled()) { 538 TrainUtilities.openDesktop(switchListFile); 539 } else { 540 TrainPrintUtilities.printReport(switchListFile, location.getName(), isPreview, Setup.getFontName(), false, 541 FileUtil.getExternalFilename(Setup.getManifestLogoURL()), location.getDefaultPrinterName(), 542 Setup.getSwitchListOrientation(), Setup.getManifestFontSize(), Setup.isPrintPageHeaderEnabled()); 543 } 544 if (!isPreview) { 545 location.setStatus(Location.PRINTED); 546 location.setSwitchListState(Location.SW_PRINTED); 547 } 548 } 549 550 protected void newLine(PrintWriter file, String string) { 551 if (!string.isEmpty()) { 552 newLine(file, string, !IS_MANIFEST); 553 } 554 } 555 556 private final static Logger log = LoggerFactory.getLogger(TrainSwitchLists.class); 557}