001package jmri.jmrit.operations.locations.tools; 002 003import java.awt.*; 004 005import javax.swing.*; 006 007import org.slf4j.Logger; 008import org.slf4j.LoggerFactory; 009 010import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; 011import jmri.InstanceManager; 012import jmri.jmrit.operations.OperationsFrame; 013import jmri.jmrit.operations.OperationsXml; 014import jmri.jmrit.operations.locations.Location; 015import jmri.jmrit.operations.locations.Track; 016import jmri.jmrit.operations.rollingstock.cars.*; 017import jmri.jmrit.operations.setup.Control; 018import jmri.jmrit.operations.setup.Setup; 019 020/** 021 * Frame for user edit of track loads 022 * 023 * @author Dan Boudreau Copyright (C) 2013, 2014, 2015 024 * 025 */ 026public class TrackLoadEditFrame extends OperationsFrame implements java.beans.PropertyChangeListener { 027 028 private static boolean loadAndType = false; 029 private static boolean shipLoadAndType = false; 030 031 Location _location = null; 032 Track _track = null; 033 String _type = ""; 034 JMenu _toolMenu = null; 035 036 // panels 037 JPanel pLoadControls = new JPanel(); 038 JPanel panelLoads = new JPanel(); 039 JScrollPane paneLoads = new JScrollPane(panelLoads); 040 041 JPanel pShipLoadControls = new JPanel(); 042 JPanel panelShipLoads = new JPanel(); 043 JScrollPane paneShipLoadControls; 044 JScrollPane paneShipLoads = new JScrollPane(panelShipLoads); 045 046 // major buttons 047 JButton saveTrackButton = new JButton(Bundle.getMessage("SaveTrack")); 048 049 JButton addLoadButton = new JButton(Bundle.getMessage("AddLoad")); 050 JButton deleteLoadButton = new JButton(Bundle.getMessage("DeleteLoad")); 051 JButton deleteAllLoadsButton = new JButton(Bundle.getMessage("DeleteAll")); 052 053 JButton addShipLoadButton = new JButton(Bundle.getMessage("AddLoad")); 054 JButton deleteShipLoadButton = new JButton(Bundle.getMessage("DeleteLoad")); 055 JButton deleteAllShipLoadsButton = new JButton(Bundle.getMessage("DeleteAll")); 056 057 // check boxes 058 JCheckBox loadAndTypeCheckBox = new JCheckBox(Bundle.getMessage("TypeAndLoad")); 059 JCheckBox shipLoadAndTypeCheckBox = new JCheckBox(Bundle.getMessage("TypeAndLoad")); 060 JCheckBox holdCars = new JCheckBox(Bundle.getMessage("HoldCarsWithCustomLoads")); 061 062 // radio buttons 063 JRadioButton loadNameAll = new JRadioButton(Bundle.getMessage("AcceptAll")); 064 JRadioButton loadNameInclude = new JRadioButton(Bundle.getMessage("AcceptOnly")); 065 JRadioButton loadNameExclude = new JRadioButton(Bundle.getMessage("Exclude")); 066 067 JRadioButton shipLoadNameAll = new JRadioButton(Bundle.getMessage("ShipAll")); 068 JRadioButton shipLoadNameInclude = new JRadioButton(Bundle.getMessage("ShipOnly")); 069 JRadioButton shipLoadNameExclude = new JRadioButton(Bundle.getMessage("Exclude")); 070 071 // combo box 072 JComboBox<String> comboBoxLoads = InstanceManager.getDefault(CarLoads.class).getComboBox(null); 073 JComboBox<String> comboBoxShipLoads = InstanceManager.getDefault(CarLoads.class).getComboBox(null); 074 JComboBox<String> comboBoxTypes = InstanceManager.getDefault(CarTypes.class).getComboBox(); 075 JComboBox<String> comboBoxShipTypes = InstanceManager.getDefault(CarTypes.class).getComboBox(); 076 077 // labels 078 JLabel trackName = new JLabel(); 079 080 public static final String DISPOSE = "dispose"; // NOI18N 081 public static final int MAX_NAME_LENGTH = Control.max_len_string_track_name; 082 083 public TrackLoadEditFrame() { 084 super(Bundle.getMessage("TitleEditTrackLoads")); 085 } 086 087 public void initComponents(Location location, Track track) { 088 _location = location; 089 _track = track; 090 091 // property changes 092 _location.addPropertyChangeListener(this); 093 // listen for car load name and type changes 094 InstanceManager.getDefault(CarLoads.class).addPropertyChangeListener(this); 095 InstanceManager.getDefault(CarTypes.class).addPropertyChangeListener(this); 096 097 // the following code sets the frame's initial state 098 getContentPane().setLayout(new BoxLayout(getContentPane(), BoxLayout.Y_AXIS)); 099 100 // Set up the panels 101 // Layout the panel by rows 102 // row 1 103 JPanel p1 = new JPanel(); 104 p1.setLayout(new BoxLayout(p1, BoxLayout.X_AXIS)); 105 p1.setMaximumSize(new Dimension(2000, 250)); 106 107 // row 1a 108 JPanel pTrackName = new JPanel(); 109 pTrackName.setLayout(new GridBagLayout()); 110 pTrackName.setBorder(BorderFactory.createTitledBorder(Bundle.getMessage("Track"))); 111 addItem(pTrackName, trackName, 0, 0); 112 113 // row 1b 114 JPanel pLocationName = new JPanel(); 115 pLocationName.setLayout(new GridBagLayout()); 116 pLocationName.setBorder(BorderFactory.createTitledBorder(Bundle.getMessage("Location"))); 117 addItem(pLocationName, new JLabel(_location.getName()), 0, 0); 118 119 p1.add(pTrackName); 120 p1.add(pLocationName); 121 122 // row 3 123 JPanel p3 = new JPanel(); 124 p3.setLayout(new BoxLayout(p3, BoxLayout.Y_AXIS)); 125 JScrollPane pane3 = new JScrollPane(p3); 126 pane3.setBorder(BorderFactory.createTitledBorder(Bundle.getMessage("LoadsTrack"))); 127 pane3.setMaximumSize(new Dimension(2000, 400)); 128 129 JPanel pLoadRadioButtons = new JPanel(); 130 pLoadRadioButtons.setLayout(new FlowLayout()); 131 132 pLoadRadioButtons.add(loadNameAll); 133 pLoadRadioButtons.add(loadNameInclude); 134 pLoadRadioButtons.add(loadNameExclude); 135 pLoadRadioButtons.add(loadAndTypeCheckBox); 136 137 pLoadControls.setLayout(new FlowLayout()); 138 139 pLoadControls.add(comboBoxTypes); 140 pLoadControls.add(comboBoxLoads); 141 pLoadControls.add(addLoadButton); 142 pLoadControls.add(deleteLoadButton); 143 pLoadControls.add(deleteAllLoadsButton); 144 145 pLoadControls.setVisible(false); 146 147 p3.add(pLoadRadioButtons); 148 p3.add(pLoadControls); 149 150 // row 4 151 panelLoads.setLayout(new GridBagLayout()); 152 paneLoads.setBorder(BorderFactory.createTitledBorder(Bundle.getMessage("Loads"))); 153 154 ButtonGroup loadGroup = new ButtonGroup(); 155 loadGroup.add(loadNameAll); 156 loadGroup.add(loadNameInclude); 157 loadGroup.add(loadNameExclude); 158 159 // row 6 160 JPanel p6 = new JPanel(); 161 p6.setLayout(new BoxLayout(p6, BoxLayout.Y_AXIS)); 162 paneShipLoadControls = new JScrollPane(p6); 163 paneShipLoadControls.setBorder(BorderFactory.createTitledBorder(Bundle.getMessage("ShipLoadsTrack"))); 164 paneShipLoadControls.setMaximumSize(new Dimension(2000, 400)); 165 166 JPanel pShipLoadRadioButtons = new JPanel(); 167 pShipLoadRadioButtons.setLayout(new FlowLayout()); 168 169 pShipLoadRadioButtons.add(shipLoadNameAll); 170 pShipLoadRadioButtons.add(shipLoadNameInclude); 171 pShipLoadRadioButtons.add(shipLoadNameExclude); 172 pShipLoadRadioButtons.add(shipLoadAndTypeCheckBox); 173 174 pShipLoadControls.setLayout(new FlowLayout()); 175 176 pShipLoadControls.add(comboBoxShipTypes); 177 pShipLoadControls.add(comboBoxShipLoads); 178 pShipLoadControls.add(addShipLoadButton); 179 pShipLoadControls.add(deleteShipLoadButton); 180 pShipLoadControls.add(deleteAllShipLoadsButton); 181 182 pShipLoadControls.setVisible(false); 183 184 p6.add(pShipLoadRadioButtons); 185 p6.add(pShipLoadControls); 186 187 // row 7 188 panelShipLoads.setLayout(new GridBagLayout()); 189 paneShipLoads.setBorder(BorderFactory.createTitledBorder(Bundle.getMessage("Loads"))); 190 191 ButtonGroup shipLoadGroup = new ButtonGroup(); 192 shipLoadGroup.add(shipLoadNameAll); 193 shipLoadGroup.add(shipLoadNameInclude); 194 shipLoadGroup.add(shipLoadNameExclude); 195 196 JPanel pOptions = new JPanel(); 197 pOptions.setLayout(new GridBagLayout()); 198 pOptions.setBorder(BorderFactory.createTitledBorder(Bundle.getMessage("Options"))); 199 pOptions.setMaximumSize(new Dimension(2000, 400)); 200 addItem(pOptions, holdCars, 0, 0); 201 holdCars.setToolTipText(Bundle.getMessage("HoldCarsWithCustomLoadsTip")); 202 203 // row 12 204 JPanel panelButtons = new JPanel(); 205 panelButtons.setLayout(new GridBagLayout()); 206 panelButtons.setBorder(BorderFactory.createTitledBorder("")); 207 panelButtons.setMaximumSize(new Dimension(2000, 200)); 208 209 // row 13 210 addItem(panelButtons, saveTrackButton, 0, 0); 211 212 getContentPane().add(p1); 213 getContentPane().add(pane3); 214 getContentPane().add(paneLoads); 215 getContentPane().add(paneShipLoadControls); 216 getContentPane().add(paneShipLoads); 217 getContentPane().add(pOptions); 218 getContentPane().add(panelButtons); 219 220 // setup buttons 221 addButtonAction(saveTrackButton); 222 223 addButtonAction(deleteLoadButton); 224 addButtonAction(deleteAllLoadsButton); 225 addButtonAction(addLoadButton); 226 227 addButtonAction(deleteShipLoadButton); 228 addButtonAction(deleteAllShipLoadsButton); 229 addButtonAction(addShipLoadButton); 230 231 addRadioButtonAction(loadNameAll); 232 addRadioButtonAction(loadNameInclude); 233 addRadioButtonAction(loadNameExclude); 234 235 addRadioButtonAction(shipLoadNameAll); 236 addRadioButtonAction(shipLoadNameInclude); 237 addRadioButtonAction(shipLoadNameExclude); 238 239 addComboBoxAction(comboBoxTypes); 240 addComboBoxAction(comboBoxShipTypes); 241 242 paneShipLoadControls.setVisible(false); 243 paneShipLoads.setVisible(false); 244 pOptions.setVisible(false); 245 246 // load fields and enable buttons 247 if (_track != null) { 248 _track.addPropertyChangeListener(this); 249 trackName.setText(_track.getName()); 250 // only show ship loads for staging tracks 251 paneShipLoadControls.setVisible(_track.isStaging()); 252 paneShipLoads.setVisible(_track.isStaging()); 253 pOptions.setVisible(_track.isSpur()); 254 holdCars.setSelected(_track.isHoldCarsWithCustomLoadsEnabled()); 255 updateButtons(true); 256 } else { 257 updateButtons(false); 258 } 259 260 // build menu 261 // JMenuBar menuBar = new JMenuBar(); 262 // _toolMenu = new JMenu(Bundle.getMessage("MenuTools")); 263 // menuBar.add(_toolMenu); 264 // setJMenuBar(menuBar); 265 // load 266 updateTypeComboBoxes(); 267 updateLoadComboBoxes(); 268 updateLoadNames(); 269 updateShipLoadNames(); 270 271 loadAndTypeCheckBox.setSelected(loadAndType); 272 shipLoadAndTypeCheckBox.setSelected(shipLoadAndType); 273 274 // add help menu to window 275 addHelpMenu("package.jmri.jmrit.operations.Operations_LoadOptions", true); // NOI18N 276 277 initMinimumSize(new Dimension(Control.panelWidth600, Control.panelHeight400)); 278 } 279 280 // Save, Delete, Add 281 @Override 282 public void buttonActionPerformed(java.awt.event.ActionEvent ae) { 283 if (_track == null) { 284 return; 285 } 286 if (ae.getSource() == saveTrackButton) { 287 log.debug("track save button activated"); 288 save(); 289 if (Setup.isCloseWindowOnSaveEnabled()) { 290 dispose(); 291 } 292 } 293 if (ae.getSource() == addLoadButton) { 294 String loadName = (String) comboBoxLoads.getSelectedItem(); 295 if (loadAndTypeCheckBox.isSelected()) { 296 loadName = comboBoxTypes.getSelectedItem() + CarLoad.SPLIT_CHAR + loadName; 297 } 298 _track.addLoadName(loadName); 299 selectNextItemComboBox(comboBoxLoads); 300 } 301 if (ae.getSource() == deleteLoadButton) { 302 String loadName = (String) comboBoxLoads.getSelectedItem(); 303 if (loadAndTypeCheckBox.isSelected()) { 304 loadName = comboBoxTypes.getSelectedItem() + CarLoad.SPLIT_CHAR + loadName; 305 } 306 _track.deleteLoadName(loadName); 307 selectNextItemComboBox(comboBoxLoads); 308 } 309 if (ae.getSource() == deleteAllLoadsButton) { 310 deleteAllLoads(); 311 } 312 if (ae.getSource() == addShipLoadButton) { 313 String loadName = (String) comboBoxShipLoads.getSelectedItem(); 314 if (shipLoadAndTypeCheckBox.isSelected()) { 315 loadName = comboBoxShipTypes.getSelectedItem() + CarLoad.SPLIT_CHAR + loadName; 316 } 317 _track.addShipLoadName(loadName); 318 selectNextItemComboBox(comboBoxShipLoads); 319 } 320 if (ae.getSource() == deleteShipLoadButton) { 321 String loadName = (String) comboBoxShipLoads.getSelectedItem(); 322 if (shipLoadAndTypeCheckBox.isSelected()) { 323 loadName = comboBoxShipTypes.getSelectedItem() + CarLoad.SPLIT_CHAR + loadName; 324 } 325 _track.deleteShipLoadName(loadName); 326 selectNextItemComboBox(comboBoxShipLoads); 327 } 328 if (ae.getSource() == deleteAllShipLoadsButton) { 329 deleteAllShipLoads(); 330 } 331 } 332 333 @SuppressFBWarnings(value = "ST_WRITE_TO_STATIC_FROM_INSTANCE_METHOD", justification = "GUI ease of use") 334 protected void save() { 335 checkForErrors(); 336 _track.setHoldCarsWithCustomLoadsEnabled(holdCars.isSelected()); 337 // save the last state of the "Use car type and load" checkbox 338 loadAndType = loadAndTypeCheckBox.isSelected(); 339 shipLoadAndType = shipLoadAndTypeCheckBox.isSelected(); 340 // save location file 341 OperationsXml.save(); 342 } 343 344 protected void updateButtons(boolean enabled) { 345 saveTrackButton.setEnabled(enabled); 346 347 loadNameAll.setEnabled(enabled); 348 loadNameInclude.setEnabled(enabled); 349 loadNameExclude.setEnabled(enabled); 350 loadAndTypeCheckBox.setEnabled(enabled); 351 352 // enable ship options if any of the three generate loads from staging is selected 353 // or if there are any ship load restrictions for this track 354 boolean en = enabled 355 && (_track.isAddCustomLoadsAnyStagingTrackEnabled() || _track.isAddCustomLoadsAnySpurEnabled() || _track 356 .isAddCustomLoadsEnabled() || !_track.getShipLoadOption().equals(Track.ALL_LOADS)); 357 358 shipLoadNameAll.setEnabled(en); 359 shipLoadNameInclude.setEnabled(en); 360 shipLoadNameExclude.setEnabled(en); 361 shipLoadAndTypeCheckBox.setEnabled(en); 362 363 addShipLoadButton.setEnabled(en); 364 deleteShipLoadButton.setEnabled(en); 365 deleteAllShipLoadsButton.setEnabled(en); 366 367 comboBoxShipLoads.setEnabled(en); 368 comboBoxShipTypes.setEnabled(en); 369 370 } 371 372 @Override 373 public void radioButtonActionPerformed(java.awt.event.ActionEvent ae) { 374 log.debug("radio button activated"); 375 if (ae.getSource() == loadNameAll) { 376 _track.setLoadOption(Track.ALL_LOADS); 377 } 378 if (ae.getSource() == loadNameInclude) { 379 _track.setLoadOption(Track.INCLUDE_LOADS); 380 } 381 if (ae.getSource() == loadNameExclude) { 382 _track.setLoadOption(Track.EXCLUDE_LOADS); 383 } 384 if (ae.getSource() == shipLoadNameAll) { 385 _track.setShipLoadOption(Track.ALL_LOADS); 386 } 387 if (ae.getSource() == shipLoadNameInclude) { 388 _track.setShipLoadOption(Track.INCLUDE_LOADS); 389 } 390 if (ae.getSource() == shipLoadNameExclude) { 391 _track.setShipLoadOption(Track.EXCLUDE_LOADS); 392 } 393 } 394 395 // Car type combo box has been changed, show loads associated with this car type 396 @Override 397 public void comboBoxActionPerformed(java.awt.event.ActionEvent ae) { 398 updateLoadComboBoxes(); 399 } 400 401 private void updateLoadComboBoxes() { 402 String carType = (String) comboBoxTypes.getSelectedItem(); 403 InstanceManager.getDefault(CarLoads.class).updateComboBox(carType, comboBoxLoads); 404 carType = (String) comboBoxShipTypes.getSelectedItem(); 405 InstanceManager.getDefault(CarLoads.class).updateComboBox(carType, comboBoxShipLoads); 406 } 407 408 private void updateLoadNames() { 409 log.debug("Update load names"); 410 panelLoads.removeAll(); 411 if (_track != null) { 412 // set radio button 413 loadNameAll.setSelected(_track.getLoadOption().equals(Track.ALL_LOADS)); 414 loadNameInclude.setSelected(_track.getLoadOption().equals(Track.INCLUDE_LOADS)); 415 loadNameExclude.setSelected(_track.getLoadOption().equals(Track.EXCLUDE_LOADS)); 416 417 pLoadControls.setVisible(!loadNameAll.isSelected()); 418 419 if (!loadNameAll.isSelected()) { 420 int x = 0; 421 int y = 0; // vertical position in panel 422 423 int numberOfLoads = getNumberOfCheckboxesPerLine() / 2 + 1; 424 for (String loadName : _track.getLoadNames()) { 425 JLabel load = new JLabel(); 426 load.setText(loadName); 427 addItemTop(panelLoads, load, x++, y); 428 // limit the number of loads per line 429 if (x > numberOfLoads) { 430 y++; 431 x = 0; 432 } 433 } 434 revalidate(); 435 } 436 } else { 437 loadNameAll.setSelected(true); 438 } 439 panelLoads.repaint(); 440 panelLoads.revalidate(); 441 } 442 443 private void updateShipLoadNames() { 444 log.debug("Update ship load names"); 445 panelShipLoads.removeAll(); 446 if (_track != null) { 447 // set radio button 448 shipLoadNameAll.setSelected(_track.getShipLoadOption().equals(Track.ALL_LOADS)); 449 shipLoadNameInclude.setSelected(_track.getShipLoadOption().equals(Track.INCLUDE_LOADS)); 450 shipLoadNameExclude.setSelected(_track.getShipLoadOption().equals(Track.EXCLUDE_LOADS)); 451 452 pShipLoadControls.setVisible(!shipLoadNameAll.isSelected()); 453 454 if (!shipLoadNameAll.isSelected()) { 455 int x = 0; 456 int y = 0; // vertical position in panel 457 458 int numberOfLoads = getNumberOfCheckboxesPerLine() / 2 + 1; 459 for (String loadName : _track.getShipLoadNames()) { 460 JLabel load = new JLabel(); 461 load.setText(loadName); 462 addItemTop(panelShipLoads, load, x++, y); 463 // limit the number of loads per line 464 if (x > numberOfLoads) { 465 y++; 466 x = 0; 467 } 468 } 469 revalidate(); 470 } 471 } else { 472 shipLoadNameAll.setSelected(true); 473 } 474 panelShipLoads.repaint(); 475 panelShipLoads.revalidate(); 476 } 477 478 private void deleteAllLoads() { 479 if (_track != null) { 480 for (String loadName : _track.getLoadNames()) { 481 _track.deleteLoadName(loadName); 482 } 483 } 484 } 485 486 private void deleteAllShipLoads() { 487 if (_track != null) { 488 for (String loadName : _track.getShipLoadNames()) { 489 _track.deleteShipLoadName(loadName); 490 } 491 } 492 } 493 494 private void updateTypeComboBoxes() { 495 InstanceManager.getDefault(CarTypes.class).updateComboBox(comboBoxTypes); 496 // remove car types not serviced by this location and track 497 for (int i = comboBoxTypes.getItemCount() - 1; i >= 0; i--) { 498 String type = comboBoxTypes.getItemAt(i); 499 if (_track != null && !_track.isTypeNameAccepted(type)) { 500 comboBoxTypes.removeItem(type); 501 } 502 } 503 InstanceManager.getDefault(CarTypes.class).updateComboBox(comboBoxShipTypes); 504 // remove car types not serviced by this location and track 505 for (int i = comboBoxShipTypes.getItemCount() - 1; i >= 0; i--) { 506 String type = comboBoxShipTypes.getItemAt(i); 507 if (_track != null && !_track.isTypeNameAccepted(type)) { 508 comboBoxShipTypes.removeItem(type); 509 } 510 } 511 } 512 513 private void checkForErrors() { 514 if (_track.getLoadOption().equals(Track.INCLUDE_LOADS) && _track.getLoadNames().length == 0 515 || _track.getShipLoadOption().equals(Track.INCLUDE_LOADS) && _track.getShipLoadNames().length == 0) { 516 JOptionPane.showMessageDialog(this, Bundle.getMessage("ErrorNeedLoads"), Bundle.getMessage("ErrorNoLoads"), 517 JOptionPane.ERROR_MESSAGE); 518 } 519 } 520 521 @Override 522 public void dispose() { 523 if (_track != null) { 524 _track.removePropertyChangeListener(this); 525 } 526 _location.removePropertyChangeListener(this); 527 InstanceManager.getDefault(CarLoads.class).removePropertyChangeListener(this); 528 InstanceManager.getDefault(CarTypes.class).removePropertyChangeListener(this); 529 super.dispose(); 530 } 531 532 @Override 533 public void propertyChange(java.beans.PropertyChangeEvent e) { 534 if (Control.SHOW_PROPERTY) { 535 log.debug("Property change ({}) old: ({}) new: ({})", e.getPropertyName(), e.getOldValue(), e.getNewValue()); // NOI18N 536 } 537 if (e.getPropertyName().equals(Location.TYPES_CHANGED_PROPERTY) 538 || e.getPropertyName().equals(CarTypes.CARTYPES_CHANGED_PROPERTY) 539 || e.getPropertyName().equals(Track.TYPES_CHANGED_PROPERTY)) { 540 updateTypeComboBoxes(); 541 } 542 if (e.getPropertyName().equals(CarLoads.LOAD_NAME_CHANGED_PROPERTY) 543 || e.getPropertyName().equals(CarLoads.LOAD_CHANGED_PROPERTY)) { 544 updateLoadComboBoxes(); 545 updateLoadNames(); 546 updateShipLoadNames(); 547 } 548 if (e.getPropertyName().equals(Track.LOADS_CHANGED_PROPERTY)) { 549 updateLoadNames(); 550 updateShipLoadNames(); 551 } 552 if (_track != null && e.getPropertyName().equals(Track.LOAD_OPTIONS_CHANGED_PROPERTY)) { 553 updateButtons(true); 554 } 555 if (_track != null && e.getPropertyName().equals(Track.HOLD_CARS_CHANGED_PROPERTY)) { 556 holdCars.setSelected(_track.isHoldCarsWithCustomLoadsEnabled()); 557 } 558 } 559 560 private final static Logger log = LoggerFactory.getLogger(TrackLoadEditFrame.class); 561}