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 protected JComboBox<String> loadComboBox = carLoads.getComboBox(null); 053 protected JComboBox<String> kernelComboBox = InstanceManager.getDefault(KernelManager.class).getComboBox(); 054 055 // buttons 056 protected JButton editDivisionButton = new JButton(Bundle.getMessage("ButtonEdit")); 057 protected JButton editLoadButton = new JButton(Bundle.getMessage("ButtonEdit")); 058 protected 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 // ignore custom load warning 460 if (!status.equals(Track.OKAY) && !status.contains(Track.CUSTOM)) { 461 JmriJOptionPane.showMessageDialog(this, 462 Bundle.getMessage("rsCanNotFinalMsg", car.toString(), status), 463 Bundle.getMessage("rsCanNotFinal"), JmriJOptionPane.WARNING_MESSAGE); 464 return false; 465 } else { 466 // check to see if car can be routed to final destination 467 Router router = InstanceManager.getDefault(Router.class); 468 if (!router.isCarRouteable(car, null, car.getFinalDestination(), finalDestTrack, null)) { 469 JmriJOptionPane.showMessageDialog(this, 470 Bundle.getMessage("rsCanNotRouteMsg", car.toString(), 471 car.getLocationName(), car.getTrackName(), car.getFinalDestinationName(), 472 car.getFinalDestinationTrackName()), 473 Bundle.getMessage("rsCanNotFinal"), JmriJOptionPane.WARNING_MESSAGE); 474 return false; 475 } 476 } 477 } 478 } 479 return true; 480 } 481 482 private void setCarKernel(Car car) { 483 if (!ignoreKernelCheckBox.isSelected() && kernelComboBox.getSelectedItem() != null) { 484 if (kernelComboBox.getSelectedItem().equals(RollingStockManager.NONE)) { 485 car.setKernel(null); 486 if (!car.isPassenger()) { 487 car.setBlocking(Car.DEFAULT_BLOCKING_ORDER); 488 } 489 } else if (!car.getKernelName().equals(kernelComboBox.getSelectedItem())) { 490 car.setKernel(InstanceManager.getDefault(KernelManager.class).getKernelByName((String) kernelComboBox.getSelectedItem())); 491 // if car has FRED or is caboose make lead 492 if (car.hasFred() || car.isCaboose()) { 493 car.getKernel().setLead(car); 494 } 495 car.setBlocking(car.getKernel().getSize()); 496 } 497 } 498 } 499 500 private boolean setCarRWE(Car car) { 501 if (!ignoreRWECheckBox.isSelected()) { 502 // check that RWE load is valid for this car's type 503 if (carLoads.getNames(car.getTypeName()).contains(loadReturnWhenEmptyBox.getSelectedItem())) { 504 car.setReturnWhenEmptyLoadName((String) loadReturnWhenEmptyBox.getSelectedItem()); 505 } else { 506 log.debug("Car ({}) type ({}) doesn't support RWE load ({})", car, car.getTypeName(), 507 loadReturnWhenEmptyBox.getSelectedItem()); 508 JmriJOptionPane.showMessageDialog(this, 509 Bundle.getMessage("carLoadNotValid", 510 loadReturnWhenEmptyBox.getSelectedItem(), car.getTypeName()), 511 Bundle.getMessage("carCanNotChangeRweLoad"), JmriJOptionPane.WARNING_MESSAGE); 512 } 513 if (destReturnWhenEmptyBox.getSelectedItem() == null) { 514 car.setReturnWhenEmptyDestination(null); 515 car.setReturnWhenEmptyDestTrack(null); 516 } else { 517 Location locationRWE = (Location) destReturnWhenEmptyBox.getSelectedItem(); 518 if (trackReturnWhenEmptyBox.getSelectedItem() != null) { 519 Track trackRWE = (Track) trackReturnWhenEmptyBox.getSelectedItem(); 520 // warn user if they selected a staging track 521 if (trackRWE != null && trackRWE.isStaging()) { 522 log.debug("Return when empty track ({}) is staging", trackRWE.getName()); 523 JmriJOptionPane.showMessageDialog(this, Bundle.getMessage("rsDoNotSelectStaging"), 524 Bundle.getMessage("carCanNotRWE"), JmriJOptionPane.ERROR_MESSAGE); 525 return false; 526 } 527 // use a test car with a load of "RWE" and no length 528 String status = getTestCar(car, car.getReturnWhenEmptyLoadName()).checkDestination(locationRWE, 529 trackRWE); 530 if (!status.equals(Track.OKAY)) { 531 JmriJOptionPane.showMessageDialog(this, 532 Bundle.getMessage("carCanNotRWEMsg", car.toString(), locationRWE, 533 trackRWE, status), 534 Bundle.getMessage("carCanNotRWE"), JmriJOptionPane.WARNING_MESSAGE); 535 } 536 car.setReturnWhenEmptyDestTrack(trackRWE); 537 } else { 538 car.setReturnWhenEmptyDestTrack(null); 539 } 540 car.setReturnWhenEmptyDestination(locationRWE); 541 } 542 } 543 return true; 544 } 545 546 private boolean setCarRWL(Car car) { 547 if (!ignoreRWLCheckBox.isSelected()) { 548 // check that RWL load is valid for this car's type 549 if (carLoads.getNames(car.getTypeName()).contains(loadReturnWhenLoadedBox.getSelectedItem())) { 550 car.setReturnWhenLoadedLoadName((String) loadReturnWhenLoadedBox.getSelectedItem()); 551 } else { 552 log.debug("Car ({}) type ({}) doesn't support RWL load ({})", car, car.getTypeName(), 553 loadReturnWhenLoadedBox.getSelectedItem()); 554 JmriJOptionPane.showMessageDialog(this, 555 Bundle.getMessage("carLoadNotValid", 556 loadReturnWhenEmptyBox.getSelectedItem(), car.getTypeName()), 557 Bundle.getMessage("carCanNotChangeRwlLoad"), JmriJOptionPane.WARNING_MESSAGE); 558 } 559 if (destReturnWhenLoadedBox.getSelectedItem() == null) { 560 car.setReturnWhenLoadedDestination(null); 561 car.setReturnWhenLoadedDestTrack(null); 562 } else { 563 Location locationRWL = (Location) destReturnWhenLoadedBox.getSelectedItem(); 564 if (trackReturnWhenLoadedBox.getSelectedItem() != null) { 565 Track trackRWL = (Track) trackReturnWhenLoadedBox.getSelectedItem(); 566 // warn user if they selected a staging track 567 if (trackRWL != null && trackRWL.isStaging()) { 568 log.debug("Return when loaded track ({}) is staging", trackRWL.getName()); 569 JmriJOptionPane.showMessageDialog(this, Bundle.getMessage("rsDoNotSelectStaging"), 570 Bundle.getMessage("carCanNotRWL"), JmriJOptionPane.ERROR_MESSAGE); 571 return false; 572 } 573 // use a test car with a load of "RWL" and no length 574 String status = getTestCar(car, car.getReturnWhenLoadedLoadName()).checkDestination(locationRWL, 575 trackRWL); 576 if (!status.equals(Track.OKAY)) { 577 JmriJOptionPane.showMessageDialog(this, 578 Bundle.getMessage("carCanNotRWLMsg", car.toString(), locationRWL, 579 trackRWL, status), 580 Bundle.getMessage("carCanNotRWL"), JmriJOptionPane.WARNING_MESSAGE); 581 } 582 car.setReturnWhenLoadedDestTrack(trackRWL); 583 } else { 584 car.setReturnWhenLoadedDestTrack(null); 585 } 586 car.setReturnWhenLoadedDestination(locationRWL); 587 } 588 } 589 return true; 590 } 591 592 private boolean applySchedule(Car car, Track saveTrack) { 593 if (!ignoreLocationCheckBox.isSelected() && 594 trackLocationBox.getSelectedItem() != null && 595 saveTrack != trackLocationBox.getSelectedItem()) { 596 Track track = (Track) trackLocationBox.getSelectedItem(); 597 if (track.getSchedule() != null) { 598 if (JmriJOptionPane 599 .showConfirmDialog(this, 600 Bundle.getMessage("rsDoYouWantSchedule", car.toString()), 601 Bundle.getMessage("rsSpurHasSchedule", track.getName(), 602 track.getScheduleName()), 603 JmriJOptionPane.YES_NO_OPTION) == JmriJOptionPane.YES_OPTION) { 604 String results = track.checkSchedule(car); 605 if (!results.equals(Track.OKAY)) { 606 JmriJOptionPane.showMessageDialog(this, 607 Bundle.getMessage("rsNotAbleToApplySchedule", results), 608 Bundle.getMessage("rsApplyingScheduleFailed"), JmriJOptionPane.ERROR_MESSAGE); 609 // restore previous location and track so we'll ask to test schedule again 610 if (saveTrack != null) { 611 car.setLocation(saveTrack.getLocation(), saveTrack); 612 } else { 613 car.setLocation(null, null); 614 } 615 return false; 616 } 617 // now apply schedule to car 618 track.scheduleNext(car); 619 car.loadNext(track); 620 } 621 } 622 } 623 return true; 624 } 625 626 private boolean checkTrainLoad(Car car) { 627 if (car.getTrain() != null) { 628 Train train = car.getTrain(); 629 if (!train.isLoadNameAccepted(car.getLoadName(), car.getTypeName())) { 630 JmriJOptionPane.showMessageDialog(this, Bundle.getMessage("carTrainNotServLoad", 631 car.getLoadName(), train.getName()), Bundle.getMessage("rsNotMove"), JmriJOptionPane.ERROR_MESSAGE); 632 // prevent rs from being picked up and delivered 633 setRouteLocationAndDestination(car, train, null, null); 634 return false; 635 } 636 } 637 return true; 638 } 639 640 TrainByCarTypeFrame tctf = null; 641 642 private boolean checkTrainRoute(Car car) { 643 if (car.getTrain() != null) { 644 Train train = car.getTrain(); 645 if (car.getLocation() != null && car.getDestination() != null && !train.isServiceable(car)) { 646 JmriJOptionPane.showMessageDialog(this, 647 Bundle.getMessage("carTrainNotService", car.toString(), train.getName()), 648 Bundle.getMessage("rsNotMove"), JmriJOptionPane.ERROR_MESSAGE); 649 // show the train's route and car location 650 if (tctf != null) { 651 tctf.dispose(); 652 } 653 tctf = new TrainByCarTypeFrame(car); 654 // prevent rs from being picked up and delivered 655 setRouteLocationAndDestination(car, train, null, null); 656 return false; 657 } 658 } 659 return true; 660 } 661 662 /** 663 * Update locations if load changes. New load could change which track are 664 * allowed if auto selected. 665 */ 666 protected void updateComboBoxesLoadChange() { 667 if (autoTrackCheckBox.isSelected()) { 668 updateLocationTrackComboBox(); 669 } 670 if (autoDestinationTrackCheckBox.isSelected()) { 671 updateDestinationTrackComboBox(); 672 } 673 if (autoFinalDestTrackCheckBox.isSelected()) { 674 updateFinalDestinationTrack(); 675 } 676 } 677 678 @Override 679 protected boolean updateGroup(List<Car> list) { 680 for (Car car : list) { 681 if (car == _car) { 682 continue; 683 } 684 // make all cars in kernel the same 685 if (!ignoreRWECheckBox.isSelected()) { 686 car.setReturnWhenEmptyDestination(_car.getReturnWhenEmptyDestination()); 687 car.setReturnWhenEmptyDestTrack(_car.getReturnWhenEmptyDestTrack()); 688 } 689 if (!ignoreRWLCheckBox.isSelected()) { 690 car.setReturnWhenLoadedDestination(_car.getReturnWhenLoadedDestination()); 691 car.setReturnWhenLoadedDestTrack(_car.getReturnWhenLoadedDestTrack()); 692 } 693 if (!ignoreFinalDestinationCheckBox.isSelected()) { 694 car.setFinalDestination(_car.getFinalDestination()); 695 car.setFinalDestinationTrack(_car.getFinalDestinationTrack()); 696 } 697 // update car load 698 if (!ignoreLoadCheckBox.isSelected() && carLoads.containsName(car.getTypeName(), _car.getLoadName())) { 699 car.setLoadName(_car.getLoadName()); 700 car.setWait(0); // car could be at spur with schedule 701 car.setScheduleItemId(Car.NONE); 702 } 703 // update kernel 704 if (!ignoreKernelCheckBox.isSelected()) { 705 car.setKernel(_car.getKernel()); 706 } 707 // update division 708 if (!ignoreDivisionCheckBox.isSelected()) { 709 car.setDivision(_car.getDivision()); 710 } 711 } 712 return super.updateGroup(list); 713 } 714 715 @Override 716 public void checkBoxActionPerformed(java.awt.event.ActionEvent ae) { 717 super.checkBoxActionPerformed(ae); 718 if (ae.getSource() == autoFinalDestTrackCheckBox) { 719 updateFinalDestinationTrack(); 720 } 721 if (ae.getSource() == autoReturnWhenEmptyTrackCheckBox) { 722 updateReturnWhenEmptyTrack(); 723 } 724 if (ae.getSource() == autoReturnWhenLoadedTrackCheckBox) { 725 updateReturnWhenLoadedTrack(); 726 } 727 if (ae.getSource() == autoTrainCheckBox) { 728 updateTrainComboBox(); 729 } 730 if (ae.getSource() == ignoreRWECheckBox) { 731 destReturnWhenEmptyBox.setEnabled(!ignoreRWECheckBox.isSelected()); 732 trackReturnWhenEmptyBox.setEnabled(!ignoreRWECheckBox.isSelected()); 733 loadReturnWhenEmptyBox.setEnabled(!ignoreRWECheckBox.isSelected()); 734 autoReturnWhenEmptyTrackCheckBox.setEnabled(!ignoreRWECheckBox.isSelected()); 735 } 736 if (ae.getSource() == ignoreRWLCheckBox) { 737 destReturnWhenLoadedBox.setEnabled(!ignoreRWLCheckBox.isSelected()); 738 trackReturnWhenLoadedBox.setEnabled(!ignoreRWLCheckBox.isSelected()); 739 loadReturnWhenLoadedBox.setEnabled(!ignoreRWLCheckBox.isSelected()); 740 autoReturnWhenLoadedTrackCheckBox.setEnabled(!ignoreRWLCheckBox.isSelected()); 741 } 742 if (ae.getSource() == ignoreLoadCheckBox) { 743 loadComboBox.setEnabled(!ignoreLoadCheckBox.isSelected()); 744 editLoadButton.setEnabled(!ignoreLoadCheckBox.isSelected() && _car != null); 745 } 746 if (ae.getSource() == ignoreDivisionCheckBox) { 747 divisionComboBox.setEnabled(!ignoreDivisionCheckBox.isSelected()); 748 editDivisionButton.setEnabled(!ignoreDivisionCheckBox.isSelected()); 749 } 750 if (ae.getSource() == ignoreKernelCheckBox) { 751 kernelComboBox.setEnabled(!ignoreKernelCheckBox.isSelected()); 752 editKernelButton.setEnabled(!ignoreKernelCheckBox.isSelected()); 753 } 754 } 755 756 protected void updateReturnWhenEmptyComboBoxes() { 757 if (_car != null) { 758 log.debug("Updating return when empty for car ({})", _car); 759 destReturnWhenEmptyBox.setSelectedItem(_car.getReturnWhenEmptyDestination()); 760 } 761 updateReturnWhenEmptyTrack(); 762 } 763 764 protected void updateReturnWhenEmptyTrack() { 765 if (destReturnWhenEmptyBox.getSelectedItem() == null) { 766 trackReturnWhenEmptyBox.removeAllItems(); 767 } else { 768 log.debug("CarSetFrame sees return when empty: {}", destReturnWhenEmptyBox.getSelectedItem()); 769 Location loc = (Location) destReturnWhenEmptyBox.getSelectedItem(); 770 loc.updateComboBox(trackReturnWhenEmptyBox, getTestCar(_car, _car.getReturnWhenEmptyLoadName()), 771 autoReturnWhenEmptyTrackCheckBox.isSelected(), true); 772 if (_car != null && 773 _car.getReturnWhenEmptyDestination() != null && 774 _car.getReturnWhenEmptyDestination().equals(loc) && 775 _car.getReturnWhenEmptyDestTrack() != null) { 776 trackReturnWhenEmptyBox.setSelectedItem(_car.getReturnWhenEmptyDestTrack()); 777 } 778 } 779 } 780 781 protected void updateReturnWhenLoadedComboBoxes() { 782 if (_car != null) { 783 log.debug("Updating return when loaded for car ({})", _car); 784 destReturnWhenLoadedBox.setSelectedItem(_car.getReturnWhenLoadedDestination()); 785 } 786 updateReturnWhenLoadedTrack(); 787 } 788 789 protected void updateReturnWhenLoadedTrack() { 790 if (destReturnWhenLoadedBox.getSelectedItem() == null) { 791 trackReturnWhenLoadedBox.removeAllItems(); 792 } else { 793 log.debug("CarSetFrame sees return when empty: {}", destReturnWhenLoadedBox.getSelectedItem()); 794 Location loc = (Location) destReturnWhenLoadedBox.getSelectedItem(); 795 loc.updateComboBox(trackReturnWhenLoadedBox, getTestCar(_car, _car.getReturnWhenLoadedLoadName()), 796 autoReturnWhenLoadedTrackCheckBox.isSelected(), true); 797 if (_car != null && 798 _car.getReturnWhenLoadedDestination() != null && 799 _car.getReturnWhenLoadedDestination().equals(loc) && 800 _car.getReturnWhenLoadedDestTrack() != null) { 801 trackReturnWhenLoadedBox.setSelectedItem(_car.getReturnWhenLoadedDestTrack()); 802 } 803 } 804 } 805 806 protected void updateFinalDestinationComboBoxes() { 807 if (_car != null) { 808 log.debug("Updating final destinations for car ({})", _car); 809 finalDestinationBox.setSelectedItem(_car.getFinalDestination()); 810 } 811 updateFinalDestinationTrack(); 812 } 813 814 protected void updateFinalDestinationTrack() { 815 if (finalDestinationBox.getSelectedItem() == null) { 816 finalDestTrackBox.removeAllItems(); 817 } else { 818 log.debug("CarSetFrame sees final destination: {}", finalDestinationBox.getSelectedItem()); 819 Location l = (Location) finalDestinationBox.getSelectedItem(); 820 l.updateComboBox(finalDestTrackBox, _car, autoFinalDestTrackCheckBox.isSelected(), true); 821 if (_car != null && 822 _car.getFinalDestination() != null && 823 _car.getFinalDestination().equals(l) && 824 _car.getFinalDestinationTrack() != null) { 825 finalDestTrackBox.setSelectedItem(_car.getFinalDestinationTrack()); 826 } 827 } 828 } 829 830 protected void updateLoadComboBox() { 831 if (_car != null) { 832 log.debug("Updating load box for car ({})", _car); 833 carLoads.updateComboBox(_car.getTypeName(), loadComboBox); 834 loadComboBox.setSelectedItem(_car.getLoadName()); 835 } 836 } 837 838 protected void updateRweLoadComboBox() { 839 if (_car != null) { 840 log.debug("Updating RWE load box for car ({})", _car); 841 carLoads.updateRweComboBox(_car.getTypeName(), loadReturnWhenEmptyBox); 842 loadReturnWhenEmptyBox.setSelectedItem(_car.getReturnWhenEmptyLoadName()); 843 } 844 } 845 846 protected void updateRwlLoadComboBox() { 847 if (_car != null) { 848 log.debug("Updating RWL load box for car ({})", _car); 849 carLoads.updateRwlComboBox(_car.getTypeName(), loadReturnWhenLoadedBox); 850 loadReturnWhenLoadedBox.setSelectedItem(_car.getReturnWhenLoadedLoadName()); 851 } 852 } 853 854 protected void updateKernelComboBox() { 855 InstanceManager.getDefault(KernelManager.class).updateComboBox(kernelComboBox); 856 if (_car != null) { 857 kernelComboBox.setSelectedItem(_car.getKernelName()); 858 } 859 } 860 861 protected void updateDivisionComboBox() { 862 InstanceManager.getDefault(DivisionManager.class).updateComboBox(divisionComboBox); 863 if (_car != null) { 864 divisionComboBox.setSelectedItem(_car.getDivision()); 865 } 866 } 867 868 @Override 869 protected void updateTrainComboBox() { 870 log.debug("update train combo box"); 871 if (_car != null && autoTrainCheckBox.isSelected()) { 872 log.debug("Updating train box for car ({})", _car); 873 trainManager.updateTrainComboBox(trainBox, _car); 874 } else { 875 trainManager.updateTrainComboBox(trainBox); 876 } 877 if (_car != null) { 878 trainBox.setSelectedItem(_car.getTrain()); 879 } 880 } 881 882 private Car getTestCar(Car car, String loadName) { 883 Car c = car; 884 // clone car and set the load and a length of zero 885 if (car != null) { 886 c = car.copy(); 887 c.setLoadName(loadName); 888 c.setLength(Integer.toString(-RollingStock.COUPLERS)); // ignore car length 889 } 890 return c; 891 } 892 893 @SuppressFBWarnings(value = "ST_WRITE_TO_STATIC_FROM_INSTANCE_METHOD", justification = "GUI ease of use") 894 public void setDestinationEnabled(boolean enable) { 895 enableDestination = !enableDestination; 896 enableDestinationFields(!locationUnknownCheckBox.isSelected()); 897 } 898 899 @Override 900 public void dispose() { 901 if (lef != null) { 902 lef.dispose(); 903 } 904 if (cef != null) { 905 cef.removePropertyChangeListener(this); 906 cef.dispose(); 907 } 908 if (def != null) { 909 def.dispose(); 910 } 911 if (tctf != null) { 912 tctf.dispose(); 913 } 914 InstanceManager.getDefault(CarLoads.class).removePropertyChangeListener(this); 915 InstanceManager.getDefault(KernelManager.class).removePropertyChangeListener(this); 916 InstanceManager.getDefault(DivisionManager.class).removePropertyChangeListener(this); 917 carManager.removePropertyChangeListener(this); 918 super.dispose(); 919 } 920 921 @Override 922 public void propertyChange(java.beans.PropertyChangeEvent e) { 923 log.debug("PropertyChange ({}) new ({})", e.getPropertyName(), e.getNewValue()); 924 super.propertyChange(e); 925 if (e.getPropertyName().equals(Car.FINAL_DESTINATION_CHANGED_PROPERTY) || 926 e.getPropertyName().equals(Car.FINAL_DESTINATION_TRACK_CHANGED_PROPERTY)) { 927 updateFinalDestinationComboBoxes(); 928 } 929 if (e.getPropertyName().equals(CarLoads.LOAD_CHANGED_PROPERTY) || 930 e.getPropertyName().equals(Car.LOAD_CHANGED_PROPERTY)) { 931 updateLoadComboBox(); 932 } 933 if (e.getPropertyName().equals(CarLoads.LOAD_CHANGED_PROPERTY) || 934 e.getPropertyName().equals(CarLoads.LOAD_TYPE_CHANGED_PROPERTY) || 935 e.getPropertyName().equals(Car.RWE_LOAD_CHANGED_PROPERTY)) { 936 updateRweLoadComboBox(); 937 } 938 if (e.getPropertyName().equals(CarLoads.LOAD_CHANGED_PROPERTY) || 939 e.getPropertyName().equals(CarLoads.LOAD_TYPE_CHANGED_PROPERTY) || 940 e.getPropertyName().equals(Car.RWL_LOAD_CHANGED_PROPERTY)) { 941 updateRwlLoadComboBox(); 942 } 943 if (e.getPropertyName().equals(Car.RETURN_WHEN_EMPTY_CHANGED_PROPERTY)) { 944 updateReturnWhenEmptyComboBoxes(); 945 } 946 if (e.getPropertyName().equals(Car.RETURN_WHEN_LOADED_CHANGED_PROPERTY)) { 947 updateReturnWhenLoadedComboBoxes(); 948 } 949 if (e.getPropertyName().equals(KernelManager.LISTLENGTH_CHANGED_PROPERTY) || 950 e.getPropertyName().equals(Car.KERNEL_NAME_CHANGED_PROPERTY)) { 951 updateKernelComboBox(); 952 } 953 if (e.getPropertyName().equals(DivisionManager.LISTLENGTH_CHANGED_PROPERTY)) { 954 updateDivisionComboBox(); 955 } 956 if (e.getPropertyName().equals(RollingStock.TRAIN_CHANGED_PROPERTY)) { 957 enableDestinationFields(!locationUnknownCheckBox.isSelected()); 958 } 959 if (e.getPropertyName().equals(CarAttributeEditFrame.DISPOSE)) { 960 cef = null; 961 } 962 } 963 964 private static final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(CarSetFrame.class); 965}