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 car.setRoutePath(_car.getRoutePath()); 697 } 698 // update car load 699 if (!ignoreLoadCheckBox.isSelected() && carLoads.containsName(car.getTypeName(), _car.getLoadName())) { 700 car.setLoadName(_car.getLoadName()); 701 car.setWait(0); // car could be at spur with schedule 702 car.setScheduleItemId(Car.NONE); 703 } 704 // update kernel 705 if (!ignoreKernelCheckBox.isSelected()) { 706 car.setKernel(_car.getKernel()); 707 } 708 // update division 709 if (!ignoreDivisionCheckBox.isSelected()) { 710 car.setDivision(_car.getDivision()); 711 } 712 } 713 return super.updateGroup(list); 714 } 715 716 @Override 717 public void checkBoxActionPerformed(java.awt.event.ActionEvent ae) { 718 super.checkBoxActionPerformed(ae); 719 if (ae.getSource() == autoFinalDestTrackCheckBox) { 720 updateFinalDestinationTrack(); 721 } 722 if (ae.getSource() == autoReturnWhenEmptyTrackCheckBox) { 723 updateReturnWhenEmptyTrack(); 724 } 725 if (ae.getSource() == autoReturnWhenLoadedTrackCheckBox) { 726 updateReturnWhenLoadedTrack(); 727 } 728 if (ae.getSource() == autoTrainCheckBox) { 729 updateTrainComboBox(); 730 } 731 if (ae.getSource() == ignoreRWECheckBox) { 732 destReturnWhenEmptyBox.setEnabled(!ignoreRWECheckBox.isSelected()); 733 trackReturnWhenEmptyBox.setEnabled(!ignoreRWECheckBox.isSelected()); 734 loadReturnWhenEmptyBox.setEnabled(!ignoreRWECheckBox.isSelected()); 735 autoReturnWhenEmptyTrackCheckBox.setEnabled(!ignoreRWECheckBox.isSelected()); 736 } 737 if (ae.getSource() == ignoreRWLCheckBox) { 738 destReturnWhenLoadedBox.setEnabled(!ignoreRWLCheckBox.isSelected()); 739 trackReturnWhenLoadedBox.setEnabled(!ignoreRWLCheckBox.isSelected()); 740 loadReturnWhenLoadedBox.setEnabled(!ignoreRWLCheckBox.isSelected()); 741 autoReturnWhenLoadedTrackCheckBox.setEnabled(!ignoreRWLCheckBox.isSelected()); 742 } 743 if (ae.getSource() == ignoreLoadCheckBox) { 744 loadComboBox.setEnabled(!ignoreLoadCheckBox.isSelected()); 745 editLoadButton.setEnabled(!ignoreLoadCheckBox.isSelected() && _car != null); 746 } 747 if (ae.getSource() == ignoreDivisionCheckBox) { 748 divisionComboBox.setEnabled(!ignoreDivisionCheckBox.isSelected()); 749 editDivisionButton.setEnabled(!ignoreDivisionCheckBox.isSelected()); 750 } 751 if (ae.getSource() == ignoreKernelCheckBox) { 752 kernelComboBox.setEnabled(!ignoreKernelCheckBox.isSelected()); 753 editKernelButton.setEnabled(!ignoreKernelCheckBox.isSelected()); 754 } 755 } 756 757 protected void updateReturnWhenEmptyComboBoxes() { 758 if (_car != null) { 759 log.debug("Updating return when empty for car ({})", _car); 760 destReturnWhenEmptyBox.setSelectedItem(_car.getReturnWhenEmptyDestination()); 761 } 762 updateReturnWhenEmptyTrack(); 763 } 764 765 protected void updateReturnWhenEmptyTrack() { 766 if (destReturnWhenEmptyBox.getSelectedItem() == null) { 767 trackReturnWhenEmptyBox.removeAllItems(); 768 } else { 769 log.debug("CarSetFrame sees return when empty: {}", destReturnWhenEmptyBox.getSelectedItem()); 770 Location loc = (Location) destReturnWhenEmptyBox.getSelectedItem(); 771 loc.updateComboBox(trackReturnWhenEmptyBox, getTestCar(_car, _car.getReturnWhenEmptyLoadName()), 772 autoReturnWhenEmptyTrackCheckBox.isSelected(), true); 773 if (_car != null && 774 _car.getReturnWhenEmptyDestination() != null && 775 _car.getReturnWhenEmptyDestination().equals(loc) && 776 _car.getReturnWhenEmptyDestTrack() != null) { 777 trackReturnWhenEmptyBox.setSelectedItem(_car.getReturnWhenEmptyDestTrack()); 778 } 779 } 780 } 781 782 protected void updateReturnWhenLoadedComboBoxes() { 783 if (_car != null) { 784 log.debug("Updating return when loaded for car ({})", _car); 785 destReturnWhenLoadedBox.setSelectedItem(_car.getReturnWhenLoadedDestination()); 786 } 787 updateReturnWhenLoadedTrack(); 788 } 789 790 protected void updateReturnWhenLoadedTrack() { 791 if (destReturnWhenLoadedBox.getSelectedItem() == null) { 792 trackReturnWhenLoadedBox.removeAllItems(); 793 } else { 794 log.debug("CarSetFrame sees return when empty: {}", destReturnWhenLoadedBox.getSelectedItem()); 795 Location loc = (Location) destReturnWhenLoadedBox.getSelectedItem(); 796 loc.updateComboBox(trackReturnWhenLoadedBox, getTestCar(_car, _car.getReturnWhenLoadedLoadName()), 797 autoReturnWhenLoadedTrackCheckBox.isSelected(), true); 798 if (_car != null && 799 _car.getReturnWhenLoadedDestination() != null && 800 _car.getReturnWhenLoadedDestination().equals(loc) && 801 _car.getReturnWhenLoadedDestTrack() != null) { 802 trackReturnWhenLoadedBox.setSelectedItem(_car.getReturnWhenLoadedDestTrack()); 803 } 804 } 805 } 806 807 protected void updateFinalDestinationComboBoxes() { 808 if (_car != null) { 809 log.debug("Updating final destinations for car ({})", _car); 810 finalDestinationBox.setSelectedItem(_car.getFinalDestination()); 811 } 812 updateFinalDestinationTrack(); 813 } 814 815 protected void updateFinalDestinationTrack() { 816 if (finalDestinationBox.getSelectedItem() == null) { 817 finalDestTrackBox.removeAllItems(); 818 } else { 819 log.debug("CarSetFrame sees final destination: {}", finalDestinationBox.getSelectedItem()); 820 Location l = (Location) finalDestinationBox.getSelectedItem(); 821 l.updateComboBox(finalDestTrackBox, _car, autoFinalDestTrackCheckBox.isSelected(), true); 822 if (_car != null && 823 _car.getFinalDestination() != null && 824 _car.getFinalDestination().equals(l) && 825 _car.getFinalDestinationTrack() != null) { 826 finalDestTrackBox.setSelectedItem(_car.getFinalDestinationTrack()); 827 } 828 } 829 } 830 831 protected void updateLoadComboBox() { 832 if (_car != null) { 833 log.debug("Updating load box for car ({})", _car); 834 carLoads.updateComboBox(_car.getTypeName(), loadComboBox); 835 loadComboBox.setSelectedItem(_car.getLoadName()); 836 } 837 } 838 839 protected void updateRweLoadComboBox() { 840 if (_car != null) { 841 log.debug("Updating RWE load box for car ({})", _car); 842 carLoads.updateRweComboBox(_car.getTypeName(), loadReturnWhenEmptyBox); 843 loadReturnWhenEmptyBox.setSelectedItem(_car.getReturnWhenEmptyLoadName()); 844 } 845 } 846 847 protected void updateRwlLoadComboBox() { 848 if (_car != null) { 849 log.debug("Updating RWL load box for car ({})", _car); 850 carLoads.updateRwlComboBox(_car.getTypeName(), loadReturnWhenLoadedBox); 851 loadReturnWhenLoadedBox.setSelectedItem(_car.getReturnWhenLoadedLoadName()); 852 } 853 } 854 855 protected void updateKernelComboBox() { 856 InstanceManager.getDefault(KernelManager.class).updateComboBox(kernelComboBox); 857 if (_car != null) { 858 kernelComboBox.setSelectedItem(_car.getKernelName()); 859 } 860 } 861 862 protected void updateDivisionComboBox() { 863 InstanceManager.getDefault(DivisionManager.class).updateComboBox(divisionComboBox); 864 if (_car != null) { 865 divisionComboBox.setSelectedItem(_car.getDivision()); 866 } 867 } 868 869 @Override 870 protected void updateTrainComboBox() { 871 log.debug("update train combo box"); 872 if (_car != null && autoTrainCheckBox.isSelected()) { 873 log.debug("Updating train box for car ({})", _car); 874 trainManager.updateTrainComboBox(trainBox, _car); 875 } else { 876 trainManager.updateTrainComboBox(trainBox); 877 } 878 if (_car != null) { 879 trainBox.setSelectedItem(_car.getTrain()); 880 } 881 } 882 883 private Car getTestCar(Car car, String loadName) { 884 Car c = car; 885 // clone car and set the load and a length of zero 886 if (car != null) { 887 c = car.copy(); 888 c.setLoadName(loadName); 889 c.setLength(Integer.toString(-RollingStock.COUPLERS)); // ignore car length 890 } 891 return c; 892 } 893 894 @SuppressFBWarnings(value = "ST_WRITE_TO_STATIC_FROM_INSTANCE_METHOD", justification = "GUI ease of use") 895 public void setDestinationEnabled(boolean enable) { 896 enableDestination = !enableDestination; 897 enableDestinationFields(!locationUnknownCheckBox.isSelected()); 898 } 899 900 @Override 901 public void dispose() { 902 if (lef != null) { 903 lef.dispose(); 904 } 905 if (cef != null) { 906 cef.removePropertyChangeListener(this); 907 cef.dispose(); 908 } 909 if (def != null) { 910 def.dispose(); 911 } 912 if (tctf != null) { 913 tctf.dispose(); 914 } 915 InstanceManager.getDefault(CarLoads.class).removePropertyChangeListener(this); 916 InstanceManager.getDefault(KernelManager.class).removePropertyChangeListener(this); 917 InstanceManager.getDefault(DivisionManager.class).removePropertyChangeListener(this); 918 carManager.removePropertyChangeListener(this); 919 super.dispose(); 920 } 921 922 @Override 923 public void propertyChange(java.beans.PropertyChangeEvent e) { 924 log.debug("PropertyChange ({}) new ({})", e.getPropertyName(), e.getNewValue()); 925 super.propertyChange(e); 926 if (e.getPropertyName().equals(Car.FINAL_DESTINATION_CHANGED_PROPERTY) || 927 e.getPropertyName().equals(Car.FINAL_DESTINATION_TRACK_CHANGED_PROPERTY)) { 928 updateFinalDestinationComboBoxes(); 929 } 930 if (e.getPropertyName().equals(CarLoads.LOAD_CHANGED_PROPERTY) || 931 e.getPropertyName().equals(Car.LOAD_CHANGED_PROPERTY)) { 932 updateLoadComboBox(); 933 } 934 if (e.getPropertyName().equals(CarLoads.LOAD_CHANGED_PROPERTY) || 935 e.getPropertyName().equals(CarLoads.LOAD_TYPE_CHANGED_PROPERTY) || 936 e.getPropertyName().equals(Car.RWE_LOAD_CHANGED_PROPERTY)) { 937 updateRweLoadComboBox(); 938 } 939 if (e.getPropertyName().equals(CarLoads.LOAD_CHANGED_PROPERTY) || 940 e.getPropertyName().equals(CarLoads.LOAD_TYPE_CHANGED_PROPERTY) || 941 e.getPropertyName().equals(Car.RWL_LOAD_CHANGED_PROPERTY)) { 942 updateRwlLoadComboBox(); 943 } 944 if (e.getPropertyName().equals(Car.RETURN_WHEN_EMPTY_CHANGED_PROPERTY)) { 945 updateReturnWhenEmptyComboBoxes(); 946 } 947 if (e.getPropertyName().equals(Car.RETURN_WHEN_LOADED_CHANGED_PROPERTY)) { 948 updateReturnWhenLoadedComboBoxes(); 949 } 950 if (e.getPropertyName().equals(KernelManager.LISTLENGTH_CHANGED_PROPERTY) || 951 e.getPropertyName().equals(Car.KERNEL_NAME_CHANGED_PROPERTY)) { 952 updateKernelComboBox(); 953 } 954 if (e.getPropertyName().equals(DivisionManager.LISTLENGTH_CHANGED_PROPERTY)) { 955 updateDivisionComboBox(); 956 } 957 if (e.getPropertyName().equals(RollingStock.TRAIN_CHANGED_PROPERTY)) { 958 enableDestinationFields(!locationUnknownCheckBox.isSelected()); 959 } 960 if (e.getPropertyName().equals(CarAttributeEditFrame.DISPOSE)) { 961 cef = null; 962 } 963 } 964 965 private static final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(CarSetFrame.class); 966}