001package jmri.jmrit.operations.rollingstock.cars; 002 003import java.awt.Dimension; 004import java.awt.GridBagLayout; 005import java.util.List; 006import java.util.ResourceBundle; 007 008import javax.swing.*; 009 010import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; 011import jmri.InstanceManager; 012import jmri.jmrit.operations.OperationsXml; 013import jmri.jmrit.operations.locations.*; 014import jmri.jmrit.operations.locations.divisions.*; 015import jmri.jmrit.operations.rollingstock.*; 016import jmri.jmrit.operations.rollingstock.cars.tools.*; 017import jmri.jmrit.operations.router.Router; 018import jmri.jmrit.operations.setup.Control; 019import jmri.jmrit.operations.setup.Setup; 020import jmri.jmrit.operations.trains.Train; 021import jmri.jmrit.operations.trains.tools.TrainByCarTypeFrame; 022import jmri.util.swing.JmriJOptionPane; 023 024/** 025 * Frame for user to place car on the layout 026 * 027 * @author Dan Boudreau Copyright (C) 2008, 2010, 2011, 2013, 2014, 2021 028 */ 029public class CarSetFrame extends RollingStockSetFrame<Car> { 030 031 protected static final ResourceBundle rb = ResourceBundle 032 .getBundle("jmri.jmrit.operations.rollingstock.cars.JmritOperationsCarsBundle"); 033 private static final String IGNORE = "Ignore"; 034 private static final String KERNEL = "Kernel"; 035 private static final String TIP_IGNORE = "TipIgnore"; 036 037 CarManager carManager = InstanceManager.getDefault(CarManager.class); 038 CarLoads carLoads = InstanceManager.getDefault(CarLoads.class); 039 040 public Car _car; 041 042 // combo boxes 043 protected JComboBox<Division> divisionComboBox = InstanceManager.getDefault(DivisionManager.class).getComboBox(); 044 protected JComboBox<Location> destReturnWhenEmptyBox = InstanceManager.getDefault(LocationManager.class) 045 .getComboBox(); 046 protected JComboBox<Track> trackReturnWhenEmptyBox = new JComboBox<>(); 047 protected JComboBox<String> loadReturnWhenEmptyBox = carLoads.getComboBox(null); 048 protected JComboBox<Location> destReturnWhenLoadedBox = InstanceManager.getDefault(LocationManager.class) 049 .getComboBox(); 050 protected JComboBox<Track> trackReturnWhenLoadedBox = new JComboBox<>(); 051 protected JComboBox<String> loadReturnWhenLoadedBox = carLoads.getComboBox(null); 052 JComboBox<String> loadComboBox = carLoads.getComboBox(null); 053 JComboBox<String> kernelComboBox = InstanceManager.getDefault(KernelManager.class).getComboBox(); 054 055 // buttons 056 JButton editDivisionButton = new JButton(Bundle.getMessage("ButtonEdit")); 057 protected JButton editLoadButton = new JButton(Bundle.getMessage("ButtonEdit")); 058 JButton editKernelButton = new JButton(Bundle.getMessage("ButtonEdit")); 059 060 // check boxes 061 public JCheckBox ignoreDivisionCheckBox = new JCheckBox(Bundle.getMessage(IGNORE)); 062 public JCheckBox ignoreRWECheckBox = new JCheckBox(Bundle.getMessage(IGNORE)); 063 protected JCheckBox autoReturnWhenEmptyTrackCheckBox = new JCheckBox(Bundle.getMessage("Auto")); 064 public JCheckBox ignoreRWLCheckBox = new JCheckBox(Bundle.getMessage(IGNORE)); 065 protected JCheckBox autoReturnWhenLoadedTrackCheckBox = new JCheckBox(Bundle.getMessage("Auto")); 066 public JCheckBox ignoreLoadCheckBox = new JCheckBox(Bundle.getMessage(IGNORE)); 067 public JCheckBox ignoreKernelCheckBox = new JCheckBox(Bundle.getMessage(IGNORE)); 068 069 // Auto checkbox state 070 private static boolean autoReturnWhenEmptyTrackCheckBoxSelected = false; 071 private static boolean autoReturnWhenLoadedTrackCheckBoxSelected = false; 072 073 private static boolean enableDestination = false; 074 075 private String _help = "package.jmri.jmrit.operations.Operations_CarsSet"; 076 077 public CarSetFrame() { 078 super(Bundle.getMessage("TitleCarSet")); 079 } 080 081 public void initComponents(String help) { 082 _help = help; 083 initComponents(); 084 } 085 086 @Override 087 public void initComponents() { 088 super.initComponents(); 089 090 // build menu 091 JMenuBar menuBar = new JMenuBar(); 092 JMenu toolMenu = new JMenu(Bundle.getMessage("MenuTools")); 093 toolMenu.add(new EnableDestinationAction(this)); 094 toolMenu.add(new CarRoutingReportAction(this, true)); // preview 095 toolMenu.add(new CarRoutingReportAction(this, false)); // print 096 menuBar.add(toolMenu); 097 setJMenuBar(menuBar); 098 addHelpMenu(_help, true); // NOI18N 099 100 // initial caps for some languages i.e. German 101 editLoadButton.setToolTipText( 102 Bundle.getMessage("TipAddDeleteReplace", Bundle.getMessage("load"))); 103 editKernelButton.setToolTipText(Bundle.getMessage("TipAddDeleteReplace", 104 Bundle.getMessage(KERNEL).toLowerCase())); 105 106 // optional panel load, return when empty, return when loaded, division, and 107 // kernel 108 paneOptional.setBorder(BorderFactory.createTitledBorder(Bundle.getMessage("BorderLayoutOptional"))); 109 pOptional.setLayout(new BoxLayout(pOptional, BoxLayout.Y_AXIS)); 110 111 // add load fields 112 JPanel pLoad = new JPanel(); 113 pLoad.setLayout(new GridBagLayout()); 114 pLoad.setBorder(BorderFactory.createTitledBorder(Bundle.getMessage("Load"))); 115 addItemLeft(pLoad, ignoreLoadCheckBox, 1, 0); 116 loadComboBox.setName("loadComboBox"); 117 addItem(pLoad, loadComboBox, 2, 0); 118 addItem(pLoad, editLoadButton, 3, 0); 119 pOptional.add(pLoad); 120 121 // row 5 122 JPanel pReturnWhenEmpty = new JPanel(); 123 pReturnWhenEmpty.setLayout(new GridBagLayout()); 124 pReturnWhenEmpty.setBorder(BorderFactory.createTitledBorder(Bundle.getMessage("BorderLayoutReturnWhenEmpty"))); 125 addItem(pReturnWhenEmpty, new JLabel(Bundle.getMessage("Location")), 1, 0); 126 addItem(pReturnWhenEmpty, new JLabel(Bundle.getMessage("Track")), 2, 0); 127 addItem(pReturnWhenEmpty, new JLabel(Bundle.getMessage("Load")), 3, 0); 128 addItemLeft(pReturnWhenEmpty, ignoreRWECheckBox, 0, 1); 129 addItem(pReturnWhenEmpty, destReturnWhenEmptyBox, 1, 1); 130 addItem(pReturnWhenEmpty, trackReturnWhenEmptyBox, 2, 1); 131 addItem(pReturnWhenEmpty, loadReturnWhenEmptyBox, 3, 1); 132 addItem(pReturnWhenEmpty, autoReturnWhenEmptyTrackCheckBox, 4, 1); 133 pOptional.add(pReturnWhenEmpty); 134 135 // row 6 136 JPanel pReturnWhenLoaded = new JPanel(); 137 pReturnWhenLoaded.setLayout(new GridBagLayout()); 138 pReturnWhenLoaded 139 .setBorder(BorderFactory.createTitledBorder(Bundle.getMessage("BorderLayoutReturnWhenLoaded"))); 140 addItem(pReturnWhenLoaded, new JLabel(Bundle.getMessage("Location")), 1, 0); 141 addItem(pReturnWhenLoaded, new JLabel(Bundle.getMessage("Track")), 2, 0); 142 addItem(pReturnWhenLoaded, new JLabel(Bundle.getMessage("Load")), 3, 0); 143 addItemLeft(pReturnWhenLoaded, ignoreRWLCheckBox, 0, 1); 144 addItem(pReturnWhenLoaded, destReturnWhenLoadedBox, 1, 1); 145 addItem(pReturnWhenLoaded, trackReturnWhenLoadedBox, 2, 1); 146 addItem(pReturnWhenLoaded, loadReturnWhenLoadedBox, 3, 1); 147 addItem(pReturnWhenLoaded, autoReturnWhenLoadedTrackCheckBox, 4, 1); 148 pOptional.add(pReturnWhenLoaded); 149 150 // division field 151 JPanel pDivision = new JPanel(); 152 pDivision.setLayout(new GridBagLayout()); 153 pDivision.setBorder(BorderFactory.createTitledBorder(Bundle.getMessage("HomeDivision"))); 154 addItemLeft(pDivision, ignoreDivisionCheckBox, 1, 0); 155 addItem(pDivision, divisionComboBox, 2, 0); 156 addItem(pDivision, editDivisionButton, 3, 0); 157 pOptional.add(pDivision); 158 159 // add kernel fields 160 JPanel pKernel = new JPanel(); 161 pKernel.setLayout(new GridBagLayout()); 162 pKernel.setBorder(BorderFactory.createTitledBorder(Bundle.getMessage(KERNEL))); 163 addItemLeft(pKernel, ignoreKernelCheckBox, 1, 0); 164 kernelComboBox.setName("kernelComboBox"); // NOI18N for UI Test 165 addItem(pKernel, kernelComboBox, 2, 0); 166 addItem(pKernel, editKernelButton, 3, 0); 167 pOptional.add(pKernel); 168 169 // don't show ignore checkboxes 170 ignoreDivisionCheckBox.setVisible(false); 171 ignoreRWECheckBox.setVisible(false); 172 ignoreRWLCheckBox.setVisible(false); 173 ignoreLoadCheckBox.setVisible(false); 174 ignoreKernelCheckBox.setVisible(false); 175 176 autoReturnWhenEmptyTrackCheckBox.setSelected(autoReturnWhenEmptyTrackCheckBoxSelected); 177 autoReturnWhenLoadedTrackCheckBox.setSelected(autoReturnWhenLoadedTrackCheckBoxSelected); 178 179 // setup combobox 180 addComboBoxAction(destReturnWhenEmptyBox); 181 addComboBoxAction(destReturnWhenLoadedBox); 182 addComboBoxAction(loadComboBox); 183 addComboBoxAction(divisionComboBox); 184 185 // setup button 186 addButtonAction(editLoadButton); 187 addButtonAction(editDivisionButton); 188 addButtonAction(editKernelButton); 189 190 // setup checkboxes 191 addCheckBoxAction(ignoreRWECheckBox); 192 addCheckBoxAction(ignoreRWLCheckBox); 193 addCheckBoxAction(autoReturnWhenEmptyTrackCheckBox); 194 addCheckBoxAction(autoReturnWhenLoadedTrackCheckBox); 195 addCheckBoxAction(ignoreLoadCheckBox); 196 addCheckBoxAction(ignoreDivisionCheckBox); 197 addCheckBoxAction(ignoreKernelCheckBox); 198 199 // tool tips 200 ignoreRWECheckBox.setToolTipText(Bundle.getMessage(TIP_IGNORE)); 201 ignoreRWLCheckBox.setToolTipText(Bundle.getMessage(TIP_IGNORE)); 202 ignoreLoadCheckBox.setToolTipText(Bundle.getMessage(TIP_IGNORE)); 203 ignoreDivisionCheckBox.setToolTipText(Bundle.getMessage(TIP_IGNORE)); 204 ignoreKernelCheckBox.setToolTipText(Bundle.getMessage(TIP_IGNORE)); 205 outOfServiceCheckBox.setToolTipText(Bundle.getMessage("TipCarOutOfService")); 206 autoReturnWhenEmptyTrackCheckBox.setToolTipText(Bundle.getMessage("rsTipAutoTrack")); 207 autoReturnWhenLoadedTrackCheckBox.setToolTipText(Bundle.getMessage("rsTipAutoTrack")); 208 209 // get notified if combo box gets modified 210 carLoads.addPropertyChangeListener(this); 211 carManager.addPropertyChangeListener(this); 212 InstanceManager.getDefault(KernelManager.class).addPropertyChangeListener(this); 213 InstanceManager.getDefault(DivisionManager.class).addPropertyChangeListener(this); 214 215 initMinimumSize(new Dimension(Control.panelWidth500, Control.panelHeight500)); 216 } 217 218 public void load(Car car) { 219 _car = car; 220 super.load(car); 221 updateLoadComboBox(); 222 updateRweLoadComboBox(); 223 updateRwlLoadComboBox(); 224 updateDivisionComboBox(); 225 updateKernelComboBox(); 226 } 227 228 @Override 229 protected ResourceBundle getRb() { 230 return rb; 231 } 232 233 @Override 234 protected void updateComboBoxes() { 235 super.updateComboBoxes(); 236 237 locationManager.updateComboBox(destReturnWhenEmptyBox); 238 locationManager.updateComboBox(destReturnWhenLoadedBox); 239 240 updateFinalDestinationComboBoxes(); 241 updateReturnWhenEmptyComboBoxes(); 242 updateReturnWhenLoadedComboBoxes(); 243 } 244 245 @Override 246 protected void enableComponents(boolean enabled) { 247 // If routing is disabled, the RWE and Final Destination fields do not work 248 if (!Setup.isCarRoutingEnabled()) { 249 ignoreRWECheckBox.setSelected(true); 250 ignoreRWLCheckBox.setSelected(true); 251 ignoreFinalDestinationCheckBox.setSelected(true); 252 ignoreDivisionCheckBox.setSelected(true); 253 } 254 255 super.enableComponents(enabled); 256 257 ignoreRWECheckBox.setEnabled(Setup.isCarRoutingEnabled() && enabled); 258 destReturnWhenEmptyBox.setEnabled(!ignoreRWECheckBox.isSelected() && enabled); 259 trackReturnWhenEmptyBox.setEnabled(!ignoreRWECheckBox.isSelected() && enabled); 260 loadReturnWhenEmptyBox.setEnabled(!ignoreRWECheckBox.isSelected() && enabled); 261 autoReturnWhenEmptyTrackCheckBox.setEnabled(!ignoreRWECheckBox.isSelected() && enabled); 262 263 ignoreRWLCheckBox.setEnabled(Setup.isCarRoutingEnabled() && enabled); 264 destReturnWhenLoadedBox.setEnabled(!ignoreRWLCheckBox.isSelected() && enabled); 265 trackReturnWhenLoadedBox.setEnabled(!ignoreRWLCheckBox.isSelected() && enabled); 266 loadReturnWhenLoadedBox.setEnabled(!ignoreRWLCheckBox.isSelected() && enabled); 267 autoReturnWhenLoadedTrackCheckBox.setEnabled(!ignoreRWLCheckBox.isSelected() && enabled); 268 269 ignoreLoadCheckBox.setEnabled(enabled); 270 loadComboBox.setEnabled(!ignoreLoadCheckBox.isSelected() && enabled); 271 editLoadButton.setEnabled(!ignoreLoadCheckBox.isSelected() && enabled && _car != null); 272 273 ignoreDivisionCheckBox.setEnabled(Setup.isCarRoutingEnabled() && enabled); 274 divisionComboBox.setEnabled(!ignoreDivisionCheckBox.isSelected() && enabled); 275 editDivisionButton.setEnabled(!ignoreDivisionCheckBox.isSelected() && enabled && _car != null); 276 277 ignoreKernelCheckBox.setEnabled(enabled); 278 kernelComboBox.setEnabled(!ignoreKernelCheckBox.isSelected() && enabled); 279 editKernelButton.setEnabled(!ignoreKernelCheckBox.isSelected() && enabled && _car != null); 280 281 enableDestinationFields(enabled); 282 } 283 284 private void enableDestinationFields(boolean enabled) { 285 // if car in a built train, enable destination fields 286 boolean enableDest = enableDestination || 287 destinationBox.getSelectedItem() != null || 288 (_car != null && _car.getTrain() != null && _car.getTrain().isBuilt()); 289 290 destinationBox.setEnabled(!ignoreDestinationCheckBox.isSelected() && enableDest && enabled); 291 trackDestinationBox.setEnabled(!ignoreDestinationCheckBox.isSelected() && enableDest && enabled); 292 autoDestinationTrackCheckBox.setEnabled(!ignoreDestinationCheckBox.isSelected() && enableDest && enabled); 293 } 294 295 // combo boxes 296 @Override 297 public void comboBoxActionPerformed(java.awt.event.ActionEvent ae) { 298 super.comboBoxActionPerformed(ae); 299 if (ae.getSource() == finalDestinationBox) { 300 updateFinalDestinationTrack(); 301 } 302 if (ae.getSource() == destReturnWhenEmptyBox) { 303 updateReturnWhenEmptyTrack(); 304 } 305 if (ae.getSource() == destReturnWhenLoadedBox) { 306 updateReturnWhenLoadedTrack(); 307 } 308 } 309 310 CarLoadEditFrame lef; 311 CarAttributeEditFrame cef; 312 DivisionEditFrame def; 313 314 @Override 315 public void buttonActionPerformed(java.awt.event.ActionEvent ae) { 316 super.buttonActionPerformed(ae); 317 if (ae.getSource() == editLoadButton && _car != null) { 318 if (lef != null) { 319 lef.dispose(); 320 } 321 lef = new CarLoadEditFrame(); 322 lef.initComponents(_car.getTypeName(), (String) loadComboBox.getSelectedItem()); 323 } 324 if (ae.getSource() == editKernelButton) { 325 if (cef != null) { 326 cef.dispose(); 327 } 328 cef = new CarAttributeEditFrame(); 329 cef.addPropertyChangeListener(this); 330 cef.initComponents(CarAttributeEditFrame.KERNEL, (String) kernelComboBox.getSelectedItem()); 331 } 332 if (ae.getSource() == editDivisionButton) { 333 if (def != null) { 334 def.dispose(); 335 } 336 def = new DivisionEditFrame((Division) divisionComboBox.getSelectedItem()); 337 } 338 } 339 340 @Override 341 protected boolean save() { 342 if (change(_car)) { 343 OperationsXml.save(); 344 return true; 345 } 346 return false; 347 } 348 349 protected boolean askKernelChange = true; 350 351 @SuppressFBWarnings(value = "ST_WRITE_TO_STATIC_FROM_INSTANCE_METHOD", justification = "GUI ease of use") 352 protected boolean change(Car car) { 353 // save the auto button 354 autoReturnWhenEmptyTrackCheckBoxSelected = autoReturnWhenEmptyTrackCheckBox.isSelected(); 355 autoReturnWhenLoadedTrackCheckBoxSelected = autoReturnWhenLoadedTrackCheckBox.isSelected(); 356 357 // save car's track in case there's a schedule 358 Track saveTrack = car.getTrack(); 359 // update location 360 if (!changeLocation(car)) { 361 return false; 362 } 363 // car load 364 setCarLoad(car); 365 // set final destination fields before destination in case there's a schedule at 366 // destination 367 if (!setCarFinalDestination(car)) { 368 return false; 369 } 370 // division 371 if (!ignoreDivisionCheckBox.isSelected()) { 372 car.setDivision((Division) divisionComboBox.getSelectedItem()); 373 } 374 // kernel 375 setCarKernel(car); 376 if (!super.change(car)) { 377 return false; 378 } 379 // return when empty fields 380 if (!setCarRWE(car)) { 381 return false; 382 } 383 // return when loaded fields 384 if (!setCarRWL(car)) { 385 return false; 386 } 387 // check to see if there's a schedule when placing the car at a spur 388 if (!applySchedule(car, saveTrack)) { 389 return false; 390 } 391 // determine if train services this car's load 392 if (!checkTrainLoad(car)) { 393 return false; 394 } 395 // determine if train's route can service car 396 if (!checkTrainRoute(car)) { 397 return false; 398 } 399 checkTrain(car); 400 // is this car part of a kernel? 401 if (askKernelChange && car.getKernel() != null) { 402 List<Car> list = car.getKernel().getCars(); 403 if (list.size() > 1) { 404 if (JmriJOptionPane.showConfirmDialog(this, 405 Bundle.getMessage("carInKernel", car.toString()), 406 Bundle.getMessage("carPartKernel", car.getKernelName()), 407 JmriJOptionPane.YES_NO_OPTION) == JmriJOptionPane.YES_OPTION) { 408 if (!updateGroup(list)) { 409 return false; 410 } 411 } else if (outOfServiceCheckBox.isSelected()) { 412 car.setKernel(null); // don't leave car in kernel if out of service 413 } 414 } 415 } 416 return true; 417 } 418 419 private void setCarLoad(Car car) { 420 if (!ignoreLoadCheckBox.isSelected() && loadComboBox.getSelectedItem() != null) { 421 String load = (String) loadComboBox.getSelectedItem(); 422 if (!car.getLoadName().equals(load)) { 423 if (carLoads.containsName(car.getTypeName(), load)) { 424 car.setLoadName(load); 425 car.setWait(0); // car could be at spur with schedule 426 car.setScheduleItemId(Car.NONE); 427 updateComboBoxesLoadChange(); 428 } else { 429 JmriJOptionPane.showMessageDialog(this, 430 Bundle.getMessage("carLoadNotValid", load, car.getTypeName()), 431 Bundle.getMessage("carCanNotChangeLoad"), JmriJOptionPane.WARNING_MESSAGE); 432 } 433 } 434 } 435 } 436 437 private boolean setCarFinalDestination(Car car) { 438 if (!ignoreFinalDestinationCheckBox.isSelected()) { 439 if (finalDestinationBox.getSelectedItem() == null) { 440 car.setFinalDestination(null); 441 car.setFinalDestinationTrack(null); 442 } else { 443 Track finalDestTrack = null; 444 if (finalDestTrackBox.getSelectedItem() != null) { 445 finalDestTrack = (Track) finalDestTrackBox.getSelectedItem(); 446 } 447 if (finalDestTrack != null && 448 car.getFinalDestinationTrack() != finalDestTrack && 449 finalDestTrack.isStaging()) { 450 log.debug("Destination track ({}) is staging", finalDestTrack.getName()); 451 JmriJOptionPane.showMessageDialog(this, Bundle.getMessage("rsDoNotSelectStaging"), 452 Bundle.getMessage("rsCanNotFinal"), JmriJOptionPane.ERROR_MESSAGE); 453 return false; 454 } 455 car.setFinalDestination((Location) finalDestinationBox.getSelectedItem()); 456 car.setFinalDestinationTrack(finalDestTrack); 457 String status = getTestCar(car, car.getLoadName()) 458 .checkDestination(car.getFinalDestination(), finalDestTrack); 459 if (!status.equals(Track.OKAY)) { 460 JmriJOptionPane.showMessageDialog(this, 461 Bundle.getMessage("rsCanNotFinalMsg", car.toString(), status), 462 Bundle.getMessage("rsCanNotFinal"), JmriJOptionPane.WARNING_MESSAGE); 463 return false; 464 } else { 465 // check to see if car can be routed to final destination 466 Router router = InstanceManager.getDefault(Router.class); 467 if (!router.isCarRouteable(car, null, car.getFinalDestination(), finalDestTrack, null)) { 468 JmriJOptionPane.showMessageDialog(this, 469 Bundle.getMessage("rsCanNotRouteMsg", car.toString(), 470 car.getLocationName(), car.getTrackName(), car.getFinalDestinationName(), 471 car.getFinalDestinationTrackName()), 472 Bundle.getMessage("rsCanNotFinal"), JmriJOptionPane.WARNING_MESSAGE); 473 return false; 474 } 475 } 476 } 477 } 478 return true; 479 } 480 481 private void setCarKernel(Car car) { 482 if (!ignoreKernelCheckBox.isSelected() && kernelComboBox.getSelectedItem() != null) { 483 if (kernelComboBox.getSelectedItem().equals(RollingStockManager.NONE)) { 484 car.setKernel(null); 485 if (!car.isPassenger()) { 486 car.setBlocking(Car.DEFAULT_BLOCKING_ORDER); 487 } 488 } else if (!car.getKernelName().equals(kernelComboBox.getSelectedItem())) { 489 car.setKernel(InstanceManager.getDefault(KernelManager.class).getKernelByName((String) kernelComboBox.getSelectedItem())); 490 // if car has FRED or is caboose make lead 491 if (car.hasFred() || car.isCaboose()) { 492 car.getKernel().setLead(car); 493 } 494 car.setBlocking(car.getKernel().getSize()); 495 } 496 } 497 } 498 499 private boolean setCarRWE(Car car) { 500 if (!ignoreRWECheckBox.isSelected()) { 501 // check that RWE load is valid for this car's type 502 if (carLoads.getNames(car.getTypeName()).contains(loadReturnWhenEmptyBox.getSelectedItem())) { 503 car.setReturnWhenEmptyLoadName((String) loadReturnWhenEmptyBox.getSelectedItem()); 504 } else { 505 log.debug("Car ({}) type ({}) doesn't support RWE load ({})", car, car.getTypeName(), 506 loadReturnWhenEmptyBox.getSelectedItem()); 507 JmriJOptionPane.showMessageDialog(this, 508 Bundle.getMessage("carLoadNotValid", 509 loadReturnWhenEmptyBox.getSelectedItem(), car.getTypeName()), 510 Bundle.getMessage("carCanNotChangeRweLoad"), JmriJOptionPane.WARNING_MESSAGE); 511 } 512 if (destReturnWhenEmptyBox.getSelectedItem() == null) { 513 car.setReturnWhenEmptyDestination(null); 514 car.setReturnWhenEmptyDestTrack(null); 515 } else { 516 Location locationRWE = (Location) destReturnWhenEmptyBox.getSelectedItem(); 517 if (trackReturnWhenEmptyBox.getSelectedItem() != null) { 518 Track trackRWE = (Track) trackReturnWhenEmptyBox.getSelectedItem(); 519 // warn user if they selected a staging track 520 if (trackRWE != null && trackRWE.isStaging()) { 521 log.debug("Return when empty track ({}) is staging", trackRWE.getName()); 522 JmriJOptionPane.showMessageDialog(this, Bundle.getMessage("rsDoNotSelectStaging"), 523 Bundle.getMessage("carCanNotRWE"), JmriJOptionPane.ERROR_MESSAGE); 524 return false; 525 } 526 // use a test car with a load of "RWE" and no length 527 String status = getTestCar(car, car.getReturnWhenEmptyLoadName()).checkDestination(locationRWE, 528 trackRWE); 529 if (!status.equals(Track.OKAY)) { 530 JmriJOptionPane.showMessageDialog(this, 531 Bundle.getMessage("carCanNotRWEMsg", car.toString(), locationRWE, 532 trackRWE, status), 533 Bundle.getMessage("carCanNotRWE"), JmriJOptionPane.WARNING_MESSAGE); 534 } 535 car.setReturnWhenEmptyDestTrack(trackRWE); 536 } else { 537 car.setReturnWhenEmptyDestTrack(null); 538 } 539 car.setReturnWhenEmptyDestination(locationRWE); 540 } 541 } 542 return true; 543 } 544 545 private boolean setCarRWL(Car car) { 546 if (!ignoreRWLCheckBox.isSelected()) { 547 // check that RWL load is valid for this car's type 548 if (carLoads.getNames(car.getTypeName()).contains(loadReturnWhenLoadedBox.getSelectedItem())) { 549 car.setReturnWhenLoadedLoadName((String) loadReturnWhenLoadedBox.getSelectedItem()); 550 } else { 551 log.debug("Car ({}) type ({}) doesn't support RWL load ({})", car, car.getTypeName(), 552 loadReturnWhenLoadedBox.getSelectedItem()); 553 JmriJOptionPane.showMessageDialog(this, 554 Bundle.getMessage("carLoadNotValid", 555 loadReturnWhenEmptyBox.getSelectedItem(), car.getTypeName()), 556 Bundle.getMessage("carCanNotChangeRwlLoad"), JmriJOptionPane.WARNING_MESSAGE); 557 } 558 if (destReturnWhenLoadedBox.getSelectedItem() == null) { 559 car.setReturnWhenLoadedDestination(null); 560 car.setReturnWhenLoadedDestTrack(null); 561 } else { 562 Location locationRWL = (Location) destReturnWhenLoadedBox.getSelectedItem(); 563 if (trackReturnWhenLoadedBox.getSelectedItem() != null) { 564 Track trackRWL = (Track) trackReturnWhenLoadedBox.getSelectedItem(); 565 // warn user if they selected a staging track 566 if (trackRWL != null && trackRWL.isStaging()) { 567 log.debug("Return when loaded track ({}) is staging", trackRWL.getName()); 568 JmriJOptionPane.showMessageDialog(this, Bundle.getMessage("rsDoNotSelectStaging"), 569 Bundle.getMessage("carCanNotRWL"), JmriJOptionPane.ERROR_MESSAGE); 570 return false; 571 } 572 // use a test car with a load of "RWL" and no length 573 String status = getTestCar(car, car.getReturnWhenLoadedLoadName()).checkDestination(locationRWL, 574 trackRWL); 575 if (!status.equals(Track.OKAY)) { 576 JmriJOptionPane.showMessageDialog(this, 577 Bundle.getMessage("carCanNotRWLMsg", car.toString(), locationRWL, 578 trackRWL, status), 579 Bundle.getMessage("carCanNotRWL"), JmriJOptionPane.WARNING_MESSAGE); 580 } 581 car.setReturnWhenLoadedDestTrack(trackRWL); 582 } else { 583 car.setReturnWhenLoadedDestTrack(null); 584 } 585 car.setReturnWhenLoadedDestination(locationRWL); 586 } 587 } 588 return true; 589 } 590 591 private boolean applySchedule(Car car, Track saveTrack) { 592 if (!ignoreLocationCheckBox.isSelected() && 593 trackLocationBox.getSelectedItem() != null && 594 saveTrack != trackLocationBox.getSelectedItem()) { 595 Track track = (Track) trackLocationBox.getSelectedItem(); 596 if (track.getSchedule() != null) { 597 if (JmriJOptionPane 598 .showConfirmDialog(this, 599 Bundle.getMessage("rsDoYouWantSchedule", car.toString()), 600 Bundle.getMessage("rsSpurHasSchedule", track.getName(), 601 track.getScheduleName()), 602 JmriJOptionPane.YES_NO_OPTION) == JmriJOptionPane.YES_OPTION) { 603 String results = track.checkSchedule(car); 604 if (!results.equals(Track.OKAY)) { 605 JmriJOptionPane.showMessageDialog(this, 606 Bundle.getMessage("rsNotAbleToApplySchedule", results), 607 Bundle.getMessage("rsApplyingScheduleFailed"), JmriJOptionPane.ERROR_MESSAGE); 608 // restore previous location and track so we'll ask to test schedule again 609 if (saveTrack != null) { 610 car.setLocation(saveTrack.getLocation(), saveTrack); 611 } else { 612 car.setLocation(null, null); 613 } 614 return false; 615 } 616 // now apply schedule to car 617 track.scheduleNext(car); 618 car.loadNext(track); 619 } 620 } 621 } 622 return true; 623 } 624 625 private boolean checkTrainLoad(Car car) { 626 if (car.getTrain() != null) { 627 Train train = car.getTrain(); 628 if (!train.isLoadNameAccepted(car.getLoadName(), car.getTypeName())) { 629 JmriJOptionPane.showMessageDialog(this, Bundle.getMessage("carTrainNotServLoad", 630 car.getLoadName(), train.getName()), Bundle.getMessage("rsNotMove"), JmriJOptionPane.ERROR_MESSAGE); 631 // prevent rs from being picked up and delivered 632 setRouteLocationAndDestination(car, train, null, null); 633 return false; 634 } 635 } 636 return true; 637 } 638 639 TrainByCarTypeFrame tctf = null; 640 641 private boolean checkTrainRoute(Car car) { 642 if (car.getTrain() != null) { 643 Train train = car.getTrain(); 644 if (car.getLocation() != null && car.getDestination() != null && !train.isServiceable(car)) { 645 JmriJOptionPane.showMessageDialog(this, 646 Bundle.getMessage("carTrainNotService", car.toString(), train.getName()), 647 Bundle.getMessage("rsNotMove"), JmriJOptionPane.ERROR_MESSAGE); 648 // show the train's route and car location 649 if (tctf != null) { 650 tctf.dispose(); 651 } 652 tctf = new TrainByCarTypeFrame(car); 653 // prevent rs from being picked up and delivered 654 setRouteLocationAndDestination(car, train, null, null); 655 return false; 656 } 657 } 658 return true; 659 } 660 661 /** 662 * Update locations if load changes. New load could change which track are 663 * allowed if auto selected. 664 */ 665 protected void updateComboBoxesLoadChange() { 666 if (autoTrackCheckBox.isSelected()) { 667 updateLocationTrackComboBox(); 668 } 669 if (autoDestinationTrackCheckBox.isSelected()) { 670 updateDestinationTrackComboBox(); 671 } 672 if (autoFinalDestTrackCheckBox.isSelected()) { 673 updateFinalDestinationTrack(); 674 } 675 } 676 677 @Override 678 protected boolean updateGroup(List<Car> list) { 679 for (Car car : list) { 680 if (car == _car) { 681 continue; 682 } 683 // make all cars in kernel the same 684 if (!ignoreRWECheckBox.isSelected()) { 685 car.setReturnWhenEmptyDestination(_car.getReturnWhenEmptyDestination()); 686 car.setReturnWhenEmptyDestTrack(_car.getReturnWhenEmptyDestTrack()); 687 } 688 if (!ignoreRWLCheckBox.isSelected()) { 689 car.setReturnWhenLoadedDestination(_car.getReturnWhenLoadedDestination()); 690 car.setReturnWhenLoadedDestTrack(_car.getReturnWhenLoadedDestTrack()); 691 } 692 if (!ignoreFinalDestinationCheckBox.isSelected()) { 693 car.setFinalDestination(_car.getFinalDestination()); 694 car.setFinalDestinationTrack(_car.getFinalDestinationTrack()); 695 } 696 // update car load 697 if (!ignoreLoadCheckBox.isSelected() && carLoads.containsName(car.getTypeName(), _car.getLoadName())) { 698 car.setLoadName(_car.getLoadName()); 699 car.setWait(0); // car could be at spur with schedule 700 car.setScheduleItemId(Car.NONE); 701 } 702 // update kernel 703 if (!ignoreKernelCheckBox.isSelected()) { 704 car.setKernel(_car.getKernel()); 705 } 706 // update division 707 if (!ignoreDivisionCheckBox.isSelected()) { 708 car.setDivision(_car.getDivision()); 709 } 710 } 711 return super.updateGroup(list); 712 } 713 714 @Override 715 public void checkBoxActionPerformed(java.awt.event.ActionEvent ae) { 716 super.checkBoxActionPerformed(ae); 717 if (ae.getSource() == autoFinalDestTrackCheckBox) { 718 updateFinalDestinationTrack(); 719 } 720 if (ae.getSource() == autoReturnWhenEmptyTrackCheckBox) { 721 updateReturnWhenEmptyTrack(); 722 } 723 if (ae.getSource() == autoReturnWhenLoadedTrackCheckBox) { 724 updateReturnWhenLoadedTrack(); 725 } 726 if (ae.getSource() == autoTrainCheckBox) { 727 updateTrainComboBox(); 728 } 729 if (ae.getSource() == ignoreRWECheckBox) { 730 destReturnWhenEmptyBox.setEnabled(!ignoreRWECheckBox.isSelected()); 731 trackReturnWhenEmptyBox.setEnabled(!ignoreRWECheckBox.isSelected()); 732 loadReturnWhenEmptyBox.setEnabled(!ignoreRWECheckBox.isSelected()); 733 autoReturnWhenEmptyTrackCheckBox.setEnabled(!ignoreRWECheckBox.isSelected()); 734 } 735 if (ae.getSource() == ignoreRWLCheckBox) { 736 destReturnWhenLoadedBox.setEnabled(!ignoreRWLCheckBox.isSelected()); 737 trackReturnWhenLoadedBox.setEnabled(!ignoreRWLCheckBox.isSelected()); 738 loadReturnWhenLoadedBox.setEnabled(!ignoreRWLCheckBox.isSelected()); 739 autoReturnWhenLoadedTrackCheckBox.setEnabled(!ignoreRWLCheckBox.isSelected()); 740 } 741 if (ae.getSource() == ignoreLoadCheckBox) { 742 loadComboBox.setEnabled(!ignoreLoadCheckBox.isSelected()); 743 editLoadButton.setEnabled(!ignoreLoadCheckBox.isSelected() && _car != null); 744 } 745 if (ae.getSource() == ignoreDivisionCheckBox) { 746 divisionComboBox.setEnabled(!ignoreDivisionCheckBox.isSelected()); 747 editDivisionButton.setEnabled(!ignoreDivisionCheckBox.isSelected()); 748 } 749 if (ae.getSource() == ignoreKernelCheckBox) { 750 kernelComboBox.setEnabled(!ignoreKernelCheckBox.isSelected()); 751 editKernelButton.setEnabled(!ignoreKernelCheckBox.isSelected()); 752 } 753 } 754 755 protected void updateReturnWhenEmptyComboBoxes() { 756 if (_car != null) { 757 log.debug("Updating return when empty for car ({})", _car); 758 destReturnWhenEmptyBox.setSelectedItem(_car.getReturnWhenEmptyDestination()); 759 } 760 updateReturnWhenEmptyTrack(); 761 } 762 763 protected void updateReturnWhenEmptyTrack() { 764 if (destReturnWhenEmptyBox.getSelectedItem() == null) { 765 trackReturnWhenEmptyBox.removeAllItems(); 766 } else { 767 log.debug("CarSetFrame sees return when empty: {}", destReturnWhenEmptyBox.getSelectedItem()); 768 Location loc = (Location) destReturnWhenEmptyBox.getSelectedItem(); 769 loc.updateComboBox(trackReturnWhenEmptyBox, getTestCar(_car, _car.getReturnWhenEmptyLoadName()), 770 autoReturnWhenEmptyTrackCheckBox.isSelected(), true); 771 if (_car != null && 772 _car.getReturnWhenEmptyDestination() != null && 773 _car.getReturnWhenEmptyDestination().equals(loc) && 774 _car.getReturnWhenEmptyDestTrack() != null) { 775 trackReturnWhenEmptyBox.setSelectedItem(_car.getReturnWhenEmptyDestTrack()); 776 } 777 } 778 } 779 780 protected void updateReturnWhenLoadedComboBoxes() { 781 if (_car != null) { 782 log.debug("Updating return when loaded for car ({})", _car); 783 destReturnWhenLoadedBox.setSelectedItem(_car.getReturnWhenLoadedDestination()); 784 } 785 updateReturnWhenLoadedTrack(); 786 } 787 788 protected void updateReturnWhenLoadedTrack() { 789 if (destReturnWhenLoadedBox.getSelectedItem() == null) { 790 trackReturnWhenLoadedBox.removeAllItems(); 791 } else { 792 log.debug("CarSetFrame sees return when empty: {}", destReturnWhenLoadedBox.getSelectedItem()); 793 Location loc = (Location) destReturnWhenLoadedBox.getSelectedItem(); 794 loc.updateComboBox(trackReturnWhenLoadedBox, getTestCar(_car, _car.getReturnWhenLoadedLoadName()), 795 autoReturnWhenLoadedTrackCheckBox.isSelected(), true); 796 if (_car != null && 797 _car.getReturnWhenLoadedDestination() != null && 798 _car.getReturnWhenLoadedDestination().equals(loc) && 799 _car.getReturnWhenLoadedDestTrack() != null) { 800 trackReturnWhenLoadedBox.setSelectedItem(_car.getReturnWhenLoadedDestTrack()); 801 } 802 } 803 } 804 805 protected void updateFinalDestinationComboBoxes() { 806 if (_car != null) { 807 log.debug("Updating final destinations for car ({})", _car); 808 finalDestinationBox.setSelectedItem(_car.getFinalDestination()); 809 } 810 updateFinalDestinationTrack(); 811 } 812 813 protected void updateFinalDestinationTrack() { 814 if (finalDestinationBox.getSelectedItem() == null) { 815 finalDestTrackBox.removeAllItems(); 816 } else { 817 log.debug("CarSetFrame sees final destination: {}", finalDestinationBox.getSelectedItem()); 818 Location l = (Location) finalDestinationBox.getSelectedItem(); 819 l.updateComboBox(finalDestTrackBox, _car, autoFinalDestTrackCheckBox.isSelected(), true); 820 if (_car != null && 821 _car.getFinalDestination() != null && 822 _car.getFinalDestination().equals(l) && 823 _car.getFinalDestinationTrack() != null) { 824 finalDestTrackBox.setSelectedItem(_car.getFinalDestinationTrack()); 825 } 826 } 827 } 828 829 protected void updateLoadComboBox() { 830 if (_car != null) { 831 log.debug("Updating load box for car ({})", _car); 832 carLoads.updateComboBox(_car.getTypeName(), loadComboBox); 833 loadComboBox.setSelectedItem(_car.getLoadName()); 834 } 835 } 836 837 protected void updateRweLoadComboBox() { 838 if (_car != null) { 839 log.debug("Updating RWE load box for car ({})", _car); 840 carLoads.updateRweComboBox(_car.getTypeName(), loadReturnWhenEmptyBox); 841 loadReturnWhenEmptyBox.setSelectedItem(_car.getReturnWhenEmptyLoadName()); 842 } 843 } 844 845 protected void updateRwlLoadComboBox() { 846 if (_car != null) { 847 log.debug("Updating RWL load box for car ({})", _car); 848 carLoads.updateRwlComboBox(_car.getTypeName(), loadReturnWhenLoadedBox); 849 loadReturnWhenLoadedBox.setSelectedItem(_car.getReturnWhenLoadedLoadName()); 850 } 851 } 852 853 protected void updateKernelComboBox() { 854 InstanceManager.getDefault(KernelManager.class).updateComboBox(kernelComboBox); 855 if (_car != null) { 856 kernelComboBox.setSelectedItem(_car.getKernelName()); 857 } 858 } 859 860 protected void updateDivisionComboBox() { 861 InstanceManager.getDefault(DivisionManager.class).updateComboBox(divisionComboBox); 862 if (_car != null) { 863 divisionComboBox.setSelectedItem(_car.getDivision()); 864 } 865 } 866 867 @Override 868 protected void updateTrainComboBox() { 869 log.debug("update train combo box"); 870 if (_car != null && autoTrainCheckBox.isSelected()) { 871 log.debug("Updating train box for car ({})", _car); 872 trainManager.updateTrainComboBox(trainBox, _car); 873 } else { 874 trainManager.updateTrainComboBox(trainBox); 875 } 876 if (_car != null) { 877 trainBox.setSelectedItem(_car.getTrain()); 878 } 879 } 880 881 private Car getTestCar(Car car, String loadName) { 882 Car c = car; 883 // clone car and set the load and a length of zero 884 if (car != null) { 885 c = car.copy(); 886 c.setLoadName(loadName); 887 c.setLength(Integer.toString(-RollingStock.COUPLERS)); // ignore car length 888 } 889 return c; 890 } 891 892 @SuppressFBWarnings(value = "ST_WRITE_TO_STATIC_FROM_INSTANCE_METHOD", justification = "GUI ease of use") 893 public void setDestinationEnabled(boolean enable) { 894 enableDestination = !enableDestination; 895 enableDestinationFields(!locationUnknownCheckBox.isSelected()); 896 } 897 898 @Override 899 public void dispose() { 900 if (lef != null) { 901 lef.dispose(); 902 } 903 if (cef != null) { 904 cef.dispose(); 905 } 906 if (def != null) { 907 def.dispose(); 908 } 909 if (tctf != null) { 910 tctf.dispose(); 911 } 912 InstanceManager.getDefault(CarLoads.class).removePropertyChangeListener(this); 913 InstanceManager.getDefault(KernelManager.class).removePropertyChangeListener(this); 914 InstanceManager.getDefault(DivisionManager.class).removePropertyChangeListener(this); 915 carManager.removePropertyChangeListener(this); 916 super.dispose(); 917 } 918 919 @Override 920 public void propertyChange(java.beans.PropertyChangeEvent e) { 921 log.debug("PropertyChange ({}) new ({})", e.getPropertyName(), e.getNewValue()); 922 super.propertyChange(e); 923 if (e.getPropertyName().equals(Car.FINAL_DESTINATION_CHANGED_PROPERTY) || 924 e.getPropertyName().equals(Car.FINAL_DESTINATION_TRACK_CHANGED_PROPERTY)) { 925 updateFinalDestinationComboBoxes(); 926 } 927 if (e.getPropertyName().equals(CarLoads.LOAD_CHANGED_PROPERTY) || 928 e.getPropertyName().equals(Car.LOAD_CHANGED_PROPERTY)) { 929 updateLoadComboBox(); 930 } 931 if (e.getPropertyName().equals(CarLoads.LOAD_CHANGED_PROPERTY) || 932 e.getPropertyName().equals(CarLoads.LOAD_TYPE_CHANGED_PROPERTY) || 933 e.getPropertyName().equals(Car.RWE_LOAD_CHANGED_PROPERTY)) { 934 updateRweLoadComboBox(); 935 } 936 if (e.getPropertyName().equals(CarLoads.LOAD_CHANGED_PROPERTY) || 937 e.getPropertyName().equals(CarLoads.LOAD_TYPE_CHANGED_PROPERTY) || 938 e.getPropertyName().equals(Car.RWL_LOAD_CHANGED_PROPERTY)) { 939 updateRwlLoadComboBox(); 940 } 941 if (e.getPropertyName().equals(Car.RETURN_WHEN_EMPTY_CHANGED_PROPERTY)) { 942 updateReturnWhenEmptyComboBoxes(); 943 } 944 if (e.getPropertyName().equals(Car.RETURN_WHEN_LOADED_CHANGED_PROPERTY)) { 945 updateReturnWhenLoadedComboBoxes(); 946 } 947 if (e.getPropertyName().equals(KernelManager.LISTLENGTH_CHANGED_PROPERTY) || 948 e.getPropertyName().equals(Car.KERNEL_NAME_CHANGED_PROPERTY)) { 949 updateKernelComboBox(); 950 } 951 if (e.getPropertyName().equals(DivisionManager.LISTLENGTH_CHANGED_PROPERTY)) { 952 updateDivisionComboBox(); 953 } 954 if (e.getPropertyName().equals(RollingStock.TRAIN_CHANGED_PROPERTY)) { 955 enableDestinationFields(!locationUnknownCheckBox.isSelected()); 956 } 957 if (e.getPropertyName().equals(CarAttributeEditFrame.DISPOSE)) { 958 cef = null; 959 } 960 } 961 962 private static final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(CarSetFrame.class); 963}