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