001package jmri.jmrit.operations.locations.gui; 002 003import java.awt.*; 004import java.awt.event.ActionEvent; 005import java.awt.event.MouseEvent; 006import java.util.ArrayList; 007import java.util.List; 008 009import javax.swing.*; 010 011import jmri.*; 012import jmri.jmrit.operations.*; 013import jmri.jmrit.operations.locations.*; 014import jmri.jmrit.operations.locations.divisions.*; 015import jmri.jmrit.operations.locations.schedules.tools.SchedulesAndStagingAction; 016import jmri.jmrit.operations.locations.tools.*; 017import jmri.jmrit.operations.rollingstock.cars.CarTypes; 018import jmri.jmrit.operations.rollingstock.engines.EngineTypes; 019import jmri.jmrit.operations.routes.Route; 020import jmri.jmrit.operations.routes.RouteManager; 021import jmri.jmrit.operations.routes.tools.ShowRoutesServingLocationAction; 022import jmri.jmrit.operations.routes.tools.ShowRoutesServingLocationFrame; 023import jmri.jmrit.operations.setup.Control; 024import jmri.jmrit.operations.setup.Setup; 025import jmri.jmrit.operations.trains.trainbuilder.TrainCommon; 026import jmri.swing.NamedBeanComboBox; 027import jmri.util.swing.JmriJOptionPane; 028 029/** 030 * Frame for user edit of location 031 * 032 * @author Dan Boudreau Copyright (C) 2008, 2010, 2011, 2012, 2013 033 */ 034public class LocationEditFrame extends OperationsFrame implements java.beans.PropertyChangeListener { 035 036 YardTableModel yardModel = new YardTableModel(); 037 JTable yardTable = new JTable(yardModel); 038 JScrollPane yardPane = new JScrollPane(yardTable); 039 040 SpurTableModel spurModel = new SpurTableModel(); 041 JTable spurTable = new JTable(spurModel) { 042 // create tool tip for Hold column 043 @Override 044 public String getToolTipText(MouseEvent e) { 045 int colIndex = columnAtPoint(e.getPoint()); 046 int realColumnIndex = convertColumnIndexToModel(colIndex); 047 if (realColumnIndex == TrackTableModel.QUICK_SERVICE_COLUMN) { 048 return Bundle.getMessage("QuickServiceTip"); 049 } 050 if (realColumnIndex == TrackTableModel.HOLD_COLUMN) { 051 return Bundle.getMessage("HoldCarsWithCustomLoads"); 052 } 053 return null; 054 } 055 }; 056 JScrollPane spurPane = new JScrollPane(spurTable); 057 058 InterchangeTableModel interchangeModel = new InterchangeTableModel(); 059 JTable interchangeTable = new JTable(interchangeModel) { 060 // create tool tip for Routed column 061 @Override 062 public String getToolTipText(MouseEvent e) { 063 int colIndex = columnAtPoint(e.getPoint()); 064 int realColumnIndex = convertColumnIndexToModel(colIndex); 065 if (realColumnIndex == TrackTableModel.QUICK_SERVICE_COLUMN) { 066 return Bundle.getMessage("QuickServiceTip"); 067 } 068 if (realColumnIndex == TrackTableModel.ROUTED_COLUMN) { 069 return Bundle.getMessage("TipOnlyCarsWithFD"); 070 } 071 return null; 072 } 073 }; 074 JScrollPane interchangePane = new JScrollPane(interchangeTable); 075 076 StagingTableModel stagingModel = new StagingTableModel(); 077 JTable stagingTable = new JTable(stagingModel) { 078 // create tool tip for Routed column 079 @Override 080 public String getToolTipText(MouseEvent e) { 081 int colIndex = columnAtPoint(e.getPoint()); 082 int realColumnIndex = convertColumnIndexToModel(colIndex); 083 if (realColumnIndex == TrackTableModel.ROUTED_COLUMN) { 084 return Bundle.getMessage("TipOnlyCarsWithFD"); 085 } 086 return null; 087 } 088 }; 089 JScrollPane stagingPane = new JScrollPane(stagingTable); 090 091 LocationManager locationManager = InstanceManager.getDefault(LocationManager.class); 092 public Location _location = null; 093 094 ArrayList<JCheckBox> checkBoxes = new ArrayList<>(); 095 JPanel panelCheckBoxes = new JPanel(); 096 JScrollPane typePane = new JScrollPane(panelCheckBoxes); 097 098 JPanel directionPanel = new JPanel(); 099 100 // major buttons 101 JButton clearButton = new JButton(Bundle.getMessage("ClearAll")); 102 JButton setButton = new JButton(Bundle.getMessage("SelectAll")); 103 JButton autoSelectButton = new JButton(Bundle.getMessage("AutoSelect")); 104 JButton editDivisionButton = new JButton(Bundle.getMessage("ButtonEdit")); 105 JButton saveLocationButton = new JButton(Bundle.getMessage("SaveLocation")); 106 JButton deleteLocationButton = new JButton(Bundle.getMessage("DeleteLocation")); 107 JButton addLocationButton = new JButton(Bundle.getMessage("AddLocation")); 108 JButton addYardButton = new JButton(Bundle.getMessage("AddYard")); 109 JButton addSpurButton = new JButton(Bundle.getMessage("AddSpur")); 110 JButton addInterchangeButton = new JButton(Bundle.getMessage("AddInterchange")); 111 JButton addStagingButton = new JButton(Bundle.getMessage("AddStaging")); 112 113 // check boxes 114 JCheckBox northCheckBox = new JCheckBox(Bundle.getMessage("North")); 115 JCheckBox southCheckBox = new JCheckBox(Bundle.getMessage("South")); 116 JCheckBox eastCheckBox = new JCheckBox(Bundle.getMessage("East")); 117 JCheckBox westCheckBox = new JCheckBox(Bundle.getMessage("West")); 118 119 // radio buttons 120 JRadioButton stagingRadioButton = new JRadioButton(Bundle.getMessage("StagingOnly")); 121 JRadioButton interchangeRadioButton = new JRadioButton(Bundle.getMessage("Interchange")); 122 JRadioButton yardRadioButton = new JRadioButton(Bundle.getMessage("Yards")); 123 JRadioButton spurRadioButton = new JRadioButton(Bundle.getMessage("Spurs")); 124 125 // text field 126 JTextField locationNameTextField = new JTextField(Control.max_len_string_location_name); 127 128 // text area 129 JTextArea commentTextArea = new JTextArea(2, 60); 130 JScrollPane commentScroller = new JScrollPane(commentTextArea, JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED, 131 JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED); 132 JColorChooser commentColorChooser = new JColorChooser(); 133 134 // combo boxes 135 protected JComboBox<Division> divisionComboBox = InstanceManager.getDefault(DivisionManager.class).getComboBox(); 136 137 // Reader selection dropdown. 138 NamedBeanComboBox<Reporter> readerSelector; 139 140 JMenu toolMenu = new JMenu(Bundle.getMessage("MenuTools")); 141 142 public static final String NAME = Bundle.getMessage("Name"); 143 public static final int MAX_NAME_LENGTH = Control.max_len_string_location_name; 144 public static final String DISPOSE = "dispose"; // NOI18N 145 146 public LocationEditFrame(Location location) { 147 super(Bundle.getMessage("TitleLocationEdit")); 148 149 _location = location; 150 151 // Set up the jtable in a Scroll Pane.. 152 typePane = new JScrollPane(panelCheckBoxes); 153 typePane.setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED); 154 typePane.setBorder(BorderFactory.createTitledBorder(Bundle.getMessage("TypesLocation"))); 155 156 yardPane.setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED); 157 yardPane.setBorder(BorderFactory.createTitledBorder("")); 158 159 spurPane.setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED); 160 spurPane.setBorder(BorderFactory.createTitledBorder("")); 161 162 interchangePane.setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED); 163 interchangePane.setBorder(BorderFactory.createTitledBorder("")); 164 165 stagingPane.setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED); 166 stagingPane.setBorder(BorderFactory.createTitledBorder("")); 167 168 // button group 169 ButtonGroup opsGroup = new ButtonGroup(); 170 opsGroup.add(spurRadioButton); 171 opsGroup.add(yardRadioButton); 172 opsGroup.add(interchangeRadioButton); 173 opsGroup.add(stagingRadioButton); 174 175 if (_location != null) { 176 enableButtons(true); 177 locationNameTextField.setText(_location.getName()); 178 commentTextArea.setText(_location.getComment()); 179 divisionComboBox.setSelectedItem(_location.getDivision()); 180 yardModel.initTable(yardTable, location); 181 spurModel.initTable(spurTable, location); 182 interchangeModel.initTable(interchangeTable, location); 183 stagingModel.initTable(stagingTable, location); 184 _location.addPropertyChangeListener(this); 185 if (!_location.isStaging()) { 186 if (spurModel.getRowCount() > 0) { 187 spurRadioButton.setSelected(true); 188 } else if (yardModel.getRowCount() > 0) { 189 yardRadioButton.setSelected(true); 190 } else if (interchangeModel.getRowCount() > 0) { 191 interchangeRadioButton.setSelected(true); 192 } else { 193 spurRadioButton.setSelected(true); 194 } 195 } else { 196 stagingRadioButton.setSelected(true); 197 } 198 setTrainDirectionBoxes(); 199 } else { 200 enableButtons(false); 201 spurRadioButton.setSelected(true); 202 } 203 204 setVisibleTrackType(); 205 206 getContentPane().setLayout(new BoxLayout(getContentPane(), BoxLayout.Y_AXIS)); 207 208 // Layout the panel by rows 209 // row 1 210 JPanel p1 = new JPanel(); 211 p1.setLayout(new BoxLayout(p1, BoxLayout.X_AXIS)); 212 JScrollPane p1Pane = new JScrollPane(p1); 213 p1Pane.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_NEVER); 214 p1Pane.setMinimumSize(new Dimension(300, 3 * locationNameTextField.getPreferredSize().height)); 215 p1Pane.setBorder(BorderFactory.createTitledBorder("")); 216 217 // row 1a 218 JPanel pName = new JPanel(); 219 pName.setLayout(new GridBagLayout()); 220 pName.setBorder(BorderFactory.createTitledBorder(Bundle.getMessage("Name"))); 221 222 addItem(pName, locationNameTextField, 0, 0); 223 224 // row 1b 225 directionPanel.setLayout(new GridBagLayout()); 226 directionPanel.setBorder(BorderFactory.createTitledBorder(Bundle.getMessage("TrainLocation"))); 227 addItem(directionPanel, northCheckBox, 1, 0); 228 addItem(directionPanel, southCheckBox, 2, 0); 229 addItem(directionPanel, eastCheckBox, 3, 0); 230 addItem(directionPanel, westCheckBox, 4, 0); 231 232 p1.add(pName); 233 p1.add(directionPanel); 234 235 // division field 236 JPanel pDivision = new JPanel(); 237 pDivision.setLayout(new GridBagLayout()); 238 pDivision.setBorder(BorderFactory.createTitledBorder(Bundle.getMessage("Division"))); 239 addItem(pDivision, divisionComboBox, 2, 0); 240 addItem(pDivision, editDivisionButton, 3, 0); 241 setDivisionButtonText(); 242 243 // row 5 244 panelCheckBoxes.setLayout(new GridBagLayout()); 245 updateCheckboxes(); 246 247 // row 9 248 JPanel pOp = new JPanel(); 249 pOp.setLayout(new GridBagLayout()); 250 pOp.setBorder(BorderFactory.createTitledBorder(Bundle.getMessage("TracksAtLocation"))); 251 pOp.add(spurRadioButton); 252 pOp.add(yardRadioButton); 253 pOp.add(interchangeRadioButton); 254 pOp.add(stagingRadioButton); 255 256 // row 11 257 JPanel pC = new JPanel(); 258 pC.setLayout(new GridBagLayout()); 259 pC.setBorder(BorderFactory.createTitledBorder(Bundle.getMessage("Comment"))); 260 addItem(pC, commentScroller, 0, 0); 261 if (_location != null) { 262 addItem(pC, OperationsPanel.getColorChooserPanel(_location.getCommentWithColor(), commentColorChooser), 2, 0); 263 } else { 264 addItem(pC, OperationsPanel.getColorChooserPanel("", commentColorChooser), 2, 0); 265 } 266 267 // adjust text area width based on window size less color chooser 268 Dimension d = new Dimension(getPreferredSize().width - 100, getPreferredSize().height); 269 adjustTextAreaColumnWidth(commentScroller, commentTextArea, d); 270 271 JPanel readerPanel = new JPanel(); 272 readerPanel.setVisible(false); 273 // reader row 274 if (Setup.isRfidEnabled()) { 275 ReporterManager reporterManager = InstanceManager.getDefault(ReporterManager.class); 276 readerSelector = new NamedBeanComboBox<Reporter>(reporterManager); 277 readerSelector.setAllowNull(true); 278 readerPanel.setLayout(new GridBagLayout()); 279 readerPanel.setBorder(BorderFactory.createTitledBorder(Bundle.getMessage("idReporter"))); 280 addItem(readerPanel, readerSelector, 0, 0); 281 readerPanel.setVisible(true); 282 if (_location != null) { 283 readerSelector.setSelectedItem(_location.getReporter()); 284 } 285 } 286 287 // row 12 288 JPanel pB = new JPanel(); 289 pB.setLayout(new GridBagLayout()); 290 addItem(pB, deleteLocationButton, 0, 0); 291 addItem(pB, addLocationButton, 1, 0); 292 addItem(pB, saveLocationButton, 3, 0); 293 294 getContentPane().add(p1Pane); 295 getContentPane().add(pDivision); 296 getContentPane().add(typePane); 297 getContentPane().add(pOp); 298 getContentPane().add(yardPane); 299 getContentPane().add(addYardButton); 300 getContentPane().add(spurPane); 301 getContentPane().add(addSpurButton); 302 getContentPane().add(interchangePane); 303 getContentPane().add(addInterchangeButton); 304 getContentPane().add(stagingPane); 305 getContentPane().add(addStagingButton); 306 getContentPane().add(pC); 307 getContentPane().add(readerPanel); 308 getContentPane().add(pB); 309 310 // setup buttons 311 addButtonAction(setButton); 312 addButtonAction(clearButton); 313 addButtonAction(autoSelectButton); 314 addButtonAction(editDivisionButton); 315 addButtonAction(deleteLocationButton); 316 addButtonAction(addLocationButton); 317 addButtonAction(saveLocationButton); 318 addButtonAction(addYardButton); 319 addButtonAction(addSpurButton); 320 addButtonAction(addInterchangeButton); 321 addButtonAction(addStagingButton); 322 323 // add tool tips 324 autoSelectButton.setToolTipText(Bundle.getMessage("TipAutoSelect")); 325 326 addRadioButtonAction(spurRadioButton); 327 addRadioButtonAction(yardRadioButton); 328 addRadioButtonAction(interchangeRadioButton); 329 addRadioButtonAction(stagingRadioButton); 330 331 addCheckBoxTrainAction(northCheckBox); 332 addCheckBoxTrainAction(southCheckBox); 333 addCheckBoxTrainAction(eastCheckBox); 334 addCheckBoxTrainAction(westCheckBox); 335 336 addComboBoxAction(divisionComboBox); 337 338 // add property listeners 339 InstanceManager.getDefault(CarTypes.class).addPropertyChangeListener(this); 340 InstanceManager.getDefault(EngineTypes.class).addPropertyChangeListener(this); 341 InstanceManager.getDefault(DivisionManager.class).addPropertyChangeListener(this); 342 InstanceManager.getDefault(Setup.class).addPropertyChangeListener(this); 343 344 // build menu 345 JMenuBar menuBar = new JMenuBar(); 346 347 loadToolMenu(); 348 menuBar.add(toolMenu); 349 setJMenuBar(menuBar); 350 addHelpMenu("package.jmri.jmrit.operations.Operations_AddLocation", true); // NOI18N 351 352 initMinimumSize(new Dimension(Control.panelWidth600, Control.panelHeight500)); 353 } 354 355 private void loadToolMenu() { 356 toolMenu.removeAll(); 357 toolMenu.add(new LocationCopyAction(_location)); 358 toolMenu.add(new TrackCopyAction(null, _location)); 359 toolMenu.add(new ChangeTracksTypeAction(this)); 360 if (_location != null && !_location.isStaging()) { 361 toolMenu.add(new LocationTrackBlockingOrderAction(_location)); 362 } 363 toolMenu.add(new ShowTrackMovesAction()); 364 toolMenu.add(new EditCarTypeAction()); 365 if (Setup.isVsdPhysicalLocationEnabled()) { 366 toolMenu.add(new SetPhysicalLocationAction(_location)); 367 } 368 toolMenu.addSeparator(); 369 toolMenu.add(new ModifyLocationsAction(_location)); 370 toolMenu.add(new ModifyLocationsCarLoadsAction(_location)); 371 toolMenu.addSeparator(); 372 toolMenu.add(new ShowCarsByLocationAction(false, _location, null)); 373 toolMenu.add(new ShowLocosByLocationAction(false, _location, null)); 374 toolMenu.addSeparator(); 375 toolMenu.add(new ShowTrainsServingLocationAction(_location, null)); 376 toolMenu.add(new ShowRoutesServingLocationAction(_location)); 377 if (_location != null && _location.isStaging()) { 378 toolMenu.add(new SchedulesAndStagingAction()); 379 } 380 toolMenu.addSeparator(); 381 toolMenu.add(new PrintLocationsAction(false, _location)); 382 toolMenu.add(new PrintLocationsAction(true, _location)); 383 } 384 385 // frames 386 DivisionEditFrame def = null; 387 YardEditFrame yef = null; 388 SpurEditFrame sef = null; 389 InterchangeEditFrame ief = null; 390 StagingEditFrame stef = null; 391 392 // Save, Delete, Add 393 @Override 394 public void buttonActionPerformed(java.awt.event.ActionEvent ae) { 395 if (ae.getSource() == editDivisionButton) { 396 if (def != null) { 397 def.dispose(); 398 } 399 def = new DivisionEditFrame((Division) divisionComboBox.getSelectedItem()); 400 } 401 if (ae.getSource() == addYardButton) { 402 yef = new YardEditFrame(); 403 yef.initComponents(_location, null); 404 } 405 if (ae.getSource() == addSpurButton) { 406 sef = new SpurEditFrame(); 407 sef.initComponents(_location, null); 408 } 409 if (ae.getSource() == addInterchangeButton) { 410 ief = new InterchangeEditFrame(); 411 ief.initComponents(_location, null); 412 } 413 if (ae.getSource() == addStagingButton) { 414 stef = new StagingEditFrame(); 415 stef.initComponents(_location, null); 416 } 417 418 if (ae.getSource() == saveLocationButton) { 419 log.debug("location save button activated"); 420 Location l = locationManager.getLocationByName(locationNameTextField.getText()); 421 if (_location == null && l == null) { 422 saveNewLocation(); 423 } else { 424 if (l != null && l != _location) { 425 reportLocationExists(Bundle.getMessage("save")); 426 return; 427 } 428 saveLocation(); 429 if (Setup.isCloseWindowOnSaveEnabled()) { 430 dispose(); 431 } 432 } 433 } 434 if (ae.getSource() == deleteLocationButton) { 435 log.debug("location delete button activated"); 436 deleteLocation(); 437 // save location file 438 OperationsXml.save(); 439 } 440 if (ae.getSource() == addLocationButton) { 441 Location l = locationManager.getLocationByName(locationNameTextField.getText()); 442 if (l != null) { 443 reportLocationExists(Bundle.getMessage("add")); 444 return; 445 } 446 saveNewLocation(); 447 } 448 if (ae.getSource() == setButton) { 449 selectCheckboxes(true); 450 } 451 if (ae.getSource() == clearButton) { 452 selectCheckboxes(false); 453 } 454 if (ae.getSource() == autoSelectButton) { 455 log.debug("auto select button pressed"); 456 if (JmriJOptionPane.showConfirmDialog(this, Bundle.getMessage("autoSelectCarTypes?"), 457 Bundle.getMessage("autoSelectLocations?"), JmriJOptionPane.YES_NO_OPTION) != JmriJOptionPane.YES_OPTION) { 458 return; 459 } 460 autoSelectCheckboxes(); 461 } 462 } 463 464 private void saveNewLocation() { 465 if (!checkName(Bundle.getMessage("add"))) { 466 return; 467 } 468 Location location = locationManager.newLocation(locationNameTextField.getText()); 469 yardModel.initTable(yardTable, location); 470 spurModel.initTable(spurTable, location); 471 interchangeModel.initTable(interchangeTable, location); 472 stagingModel.initTable(stagingTable, location); 473 _location = location; 474 _location.addPropertyChangeListener(this); 475 476 updateCheckboxes(); 477 enableButtons(true); 478 setTrainDirectionBoxes(); 479 saveLocation(); 480 loadToolMenu(); 481 } 482 483 private void deleteLocation() { 484 Location location = locationManager.getLocationByName(locationNameTextField.getText()); 485 if (location == null) { 486 return; 487 } 488 // check to see if any route uses this location 489 Route route = InstanceManager.getDefault(RouteManager.class).isLocationInUse(location); 490 if (route != null) { 491 JmriJOptionPane.showMessageDialog(this, 492 Bundle.getMessage("RouteUsesLocation", route.getName(), location.getName()), 493 Bundle.getMessage("CanNotDeleteLocation"), JmriJOptionPane.ERROR_MESSAGE); 494 // show all the routes using this location 495 ShowRoutesServingLocationFrame frame = new ShowRoutesServingLocationFrame(); 496 frame.initComponents(location); 497 return; 498 } 499 int count = location.getNumberRS(); 500 if (count > 0) { 501 if (JmriJOptionPane.showConfirmDialog(this, Bundle.getMessage("ThereAreCars", Integer.toString(count)), 502 Bundle.getMessage("deletelocation?"), 503 JmriJOptionPane.YES_NO_OPTION) != JmriJOptionPane.YES_OPTION) { 504 return; 505 } 506 } else { 507 if (JmriJOptionPane.showConfirmDialog(this, 508 Bundle.getMessage("DoYouWantToDeleteLocation", locationNameTextField.getText()), 509 Bundle.getMessage("deletelocation?"), 510 JmriJOptionPane.YES_NO_OPTION) != JmriJOptionPane.YES_OPTION) { 511 return; 512 } 513 } 514 515 yardModel.dispose(); 516 spurModel.dispose(); 517 interchangeModel.dispose(); 518 stagingModel.dispose(); 519 520 if (yef != null) { 521 yef.dispose(); 522 } 523 if (sef != null) { 524 sef.dispose(); 525 } 526 if (ief != null) { 527 ief.dispose(); 528 } 529 if (stef != null) { 530 stef.dispose(); 531 } 532 533 locationManager.deregister(location); 534 _location = null; 535 selectCheckboxes(false); 536 enableCheckboxes(false); 537 enableButtons(false); 538 } 539 540 private void saveLocation() { 541 if (!checkName(Bundle.getMessage("save"))) { 542 return; 543 } 544 // stop table editing so "Moves" are properly saved 545 if (spurTable.isEditing()) { 546 spurTable.getCellEditor().stopCellEditing(); 547 } 548 if (yardTable.isEditing()) { 549 yardTable.getCellEditor().stopCellEditing(); 550 } 551 if (interchangeTable.isEditing()) { 552 interchangeTable.getCellEditor().stopCellEditing(); 553 } 554 if (stagingTable.isEditing()) { 555 stagingTable.getCellEditor().stopCellEditing(); 556 } 557 _location.setName(locationNameTextField.getText()); 558 _location.setComment(TrainCommon.formatColorString(commentTextArea.getText(), commentColorChooser.getColor())); 559 _location.setDivision((Division) divisionComboBox.getSelectedItem()); 560 if (Setup.isRfidEnabled() && readerSelector != null) { 561 _location.setReporter(readerSelector.getSelectedItem()); 562 } 563 // save location file 564 OperationsXml.save(); 565 } 566 567 /** 568 * @return true if name OK and is less than the maximum allowed length 569 */ 570 private boolean checkName(String s) { 571 String locationName = locationNameTextField.getText().trim(); 572 if (locationName.isEmpty()) { 573 JmriJOptionPane.showMessageDialog(this, Bundle.getMessage("MustEnterName"), 574 Bundle.getMessage("CanNotLocation", s), JmriJOptionPane.ERROR_MESSAGE); 575 return false; 576 } 577 // hyphen feature needs at least one character to work properly 578 if (locationName.contains(TrainCommon.HYPHEN)) { 579 String[] check = locationName.split(TrainCommon.HYPHEN); 580 if (check.length == 0) { 581 JmriJOptionPane.showMessageDialog(this, Bundle.getMessage("HyphenFeature"), 582 Bundle.getMessage("CanNotLocation", s), JmriJOptionPane.ERROR_MESSAGE); 583 return false; 584 } 585 locationName = check[0]; 586 } 587 if (TrainCommon.splitString(locationName).length() > MAX_NAME_LENGTH) { 588 // log.error("Location name must be less than "+ 589 // Integer.toString(MAX_NAME_LENGTH+1) +" characters"); 590 JmriJOptionPane.showMessageDialog(this, 591 Bundle.getMessage("LocationNameLengthMax", Integer.toString(MAX_NAME_LENGTH + 1)), 592 Bundle.getMessage("CanNotLocation", s), JmriJOptionPane.ERROR_MESSAGE); 593 return false; 594 } 595 if (!OperationsXml.checkFileName(locationName)) { // NOI18N 596 JmriJOptionPane.showMessageDialog(this, 597 Bundle.getMessage("NameResChar") + NEW_LINE + Bundle.getMessage("ReservedChar"), 598 Bundle.getMessage("CanNotLocation", s), JmriJOptionPane.ERROR_MESSAGE); 599 return false; 600 } 601 return true; 602 } 603 604 private void reportLocationExists(String s) { 605 JmriJOptionPane.showMessageDialog(this, Bundle.getMessage("LocationAlreadyExists"), 606 Bundle.getMessage("CanNotLocation", s), JmriJOptionPane.ERROR_MESSAGE); 607 } 608 609 private void enableButtons(boolean enabled) { 610 toolMenu.setEnabled(enabled); 611 northCheckBox.setEnabled(enabled); 612 southCheckBox.setEnabled(enabled); 613 eastCheckBox.setEnabled(enabled); 614 westCheckBox.setEnabled(enabled); 615 divisionComboBox.setEnabled(enabled); 616 editDivisionButton.setEnabled(enabled); 617 clearButton.setEnabled(enabled); 618 setButton.setEnabled(enabled); 619 autoSelectButton.setEnabled(enabled); 620 addYardButton.setEnabled(enabled); 621 addSpurButton.setEnabled(enabled); 622 addInterchangeButton.setEnabled(enabled); 623 addStagingButton.setEnabled(enabled); 624 saveLocationButton.setEnabled(enabled); 625 deleteLocationButton.setEnabled(enabled); 626 // the inverse! 627 addLocationButton.setEnabled(!enabled); 628 // enable radio buttons 629 spurRadioButton.setEnabled(enabled); 630 yardRadioButton.setEnabled(enabled); 631 interchangeRadioButton.setEnabled(enabled); 632 stagingRadioButton.setEnabled(enabled); 633 if (readerSelector != null) { 634 // enable readerSelect. 635 readerSelector.setEnabled(enabled && Setup.isRfidEnabled()); 636 } 637 } 638 639 @Override 640 public void radioButtonActionPerformed(java.awt.event.ActionEvent ae) { 641 setVisibleTrackType(); 642 } 643 644 private void setVisibleTrackType() { 645 enableTrackTypeRadioButtons(); 646 interchangePane.setVisible(interchangeRadioButton.isSelected()); 647 addInterchangeButton.setVisible(interchangeRadioButton.isSelected()); 648 stagingPane.setVisible(stagingRadioButton.isSelected()); 649 addStagingButton.setVisible(stagingRadioButton.isSelected()); 650 yardPane.setVisible(yardRadioButton.isSelected()); 651 addYardButton.setVisible(yardRadioButton.isSelected()); 652 spurPane.setVisible(spurRadioButton.isSelected()); 653 addSpurButton.setVisible(spurRadioButton.isSelected()); 654 } 655 656 private void enableTrackTypeRadioButtons() { 657 if (spurModel.getRowCount() > 0 || yardModel.getRowCount() > 0 || interchangeModel.getRowCount() > 0) { 658 if (stagingRadioButton.isSelected()) { 659 spurRadioButton.setSelected(true); 660 } 661 stagingRadioButton.setEnabled(false); 662 } else if (stagingModel.getRowCount() > 0) { 663 stagingRadioButton.setSelected(true); 664 spurRadioButton.setEnabled(false); 665 yardRadioButton.setEnabled(false); 666 interchangeRadioButton.setEnabled(false); 667 } else if (_location != null) { 668 spurRadioButton.setEnabled(true); 669 yardRadioButton.setEnabled(true); 670 interchangeRadioButton.setEnabled(true); 671 stagingRadioButton.setEnabled(true); 672 } 673 } 674 675 private void enableCheckboxes(boolean enable) { 676 for (JCheckBox checkBox : new ArrayList<>(checkBoxes)) { 677 checkBox.setEnabled(enable); 678 } 679 } 680 681 /* 682 * Protected against concurrent changes by making a copy 683 * of the checkBoxes list. 684 */ 685 private void selectCheckboxes(boolean select) { 686 for (JCheckBox checkBox : new ArrayList<>(checkBoxes)) { 687 checkBox.setSelected(select); 688 if (_location != null) { 689 if (select) { 690 _location.addTypeName(checkBox.getText()); 691 } else { 692 _location.deleteTypeName(checkBox.getText()); 693 } 694 } 695 } 696 } 697 698 private void updateCheckboxes() { 699 x = 0; 700 y = 0; 701 checkBoxes.clear(); 702 panelCheckBoxes.removeAll(); 703 numberOfCheckBoxes = getNumberOfCheckboxesPerLine(); 704 loadTypes(InstanceManager.getDefault(CarTypes.class).getNames()); 705 706 // add space between car and loco types 707 checkNewLine(); 708 709 loadTypes(InstanceManager.getDefault(EngineTypes.class).getNames()); 710 JPanel p = new JPanel(); 711 p.add(clearButton); 712 p.add(setButton); 713 p.add(autoSelectButton); 714 GridBagConstraints gc = new GridBagConstraints(); 715 gc.gridwidth = getNumberOfCheckboxesPerLine() + 1; 716 gc.gridy = ++y; 717 panelCheckBoxes.add(p, gc); 718 panelCheckBoxes.revalidate(); 719 repaint(); 720 } 721 722 protected void updateDivisionComboBox() { 723 InstanceManager.getDefault(DivisionManager.class).updateComboBox(divisionComboBox); 724 if (_location != null) { 725 divisionComboBox.setSelectedItem(_location.getDivision()); 726 } 727 } 728 729 int x = 0; 730 int y = 0; // vertical position in panel 731 732 private void loadTypes(String[] types) { 733 for (String type : types) { 734 JCheckBox checkBox = new JCheckBox(); 735 checkBoxes.add(checkBox); 736 checkBox.setText(type); 737 addCheckBoxAction(checkBox); 738 addItemLeft(panelCheckBoxes, checkBox, x, y); 739 if (_location != null) { 740 if (_location.acceptsTypeName(type)) { 741 checkBox.setSelected(true); 742 } 743 } else { 744 checkBox.setEnabled(false); 745 } 746 checkNewLine(); 747 } 748 } 749 750 int numberOfCheckBoxes; 751 752 private void checkNewLine() { 753 if (++x > numberOfCheckBoxes) { 754 y++; 755 x = 0; 756 } 757 } 758 759 /** 760 * Adjust the location's car service types to only reflect the car types 761 * serviced by the location's tracks. Protected against concurrent changes by 762 * creating a new list of checkboxes. 763 */ 764 private void autoSelectCheckboxes() { 765 for (JCheckBox checkBox : new ArrayList<>(checkBoxes)) { 766 checkBox.setSelected(false); 767 // check each track to determine which car types are serviced by 768 // this location 769 List<Track> tracks = _location.getTracksList(); 770 for (Track track : tracks) { 771 if (track.isTypeNameAccepted(checkBox.getText())) { 772 checkBox.setSelected(true); 773 } 774 } 775 // this type of car isn't serviced by any of the tracks, so delete 776 if (!checkBox.isSelected()) { 777 _location.deleteTypeName(checkBox.getText()); 778 } 779 } 780 } 781 782 LocationsByCarTypeFrame lctf = null; 783 784 @Override 785 public void checkBoxActionPerformed(java.awt.event.ActionEvent ae) { 786 JCheckBox b = (JCheckBox) ae.getSource(); 787 log.debug("checkbox change {}", b.getText()); 788 if (_location == null) { 789 return; 790 } 791 _location.removePropertyChangeListener(this); 792 if (b.isSelected()) { 793 _location.addTypeName(b.getText()); 794 // show which tracks will service this car type 795 if (InstanceManager.getDefault(CarTypes.class).containsName(b.getText())) { 796 if (lctf != null) { 797 lctf.dispose(); 798 } 799 lctf = new LocationsByCarTypeFrame(); 800 lctf.initComponents(_location, b.getText()); 801 } 802 } else { 803 _location.deleteTypeName(b.getText()); 804 } 805 _location.addPropertyChangeListener(this); 806 } 807 808 private void addCheckBoxTrainAction(JCheckBox b) { 809 b.addActionListener(new java.awt.event.ActionListener() { 810 @Override 811 public void actionPerformed(java.awt.event.ActionEvent e) { 812 checkBoxActionTrainPerformed(e); 813 } 814 }); 815 } 816 817 private void checkBoxActionTrainPerformed(java.awt.event.ActionEvent ae) { 818 // save train directions serviced by this location 819 if (_location == null) { 820 return; 821 } 822 int direction = 0; 823 if (northCheckBox.isSelected()) { 824 direction += Location.NORTH; 825 } 826 if (southCheckBox.isSelected()) { 827 direction += Location.SOUTH; 828 } 829 if (eastCheckBox.isSelected()) { 830 direction += Location.EAST; 831 } 832 if (westCheckBox.isSelected()) { 833 direction += Location.WEST; 834 } 835 _location.setTrainDirections(direction); 836 837 } 838 839 private void setTrainDirectionBoxes() { 840 northCheckBox.setVisible((Setup.getTrainDirection() & Setup.NORTH) == Setup.NORTH); 841 southCheckBox.setVisible((Setup.getTrainDirection() & Setup.SOUTH) == Setup.SOUTH); 842 eastCheckBox.setVisible((Setup.getTrainDirection() & Setup.EAST) == Setup.EAST); 843 westCheckBox.setVisible((Setup.getTrainDirection() & Setup.WEST) == Setup.WEST); 844 845 northCheckBox.setSelected((_location.getTrainDirections() & Location.NORTH) == Location.NORTH); 846 southCheckBox.setSelected((_location.getTrainDirections() & Location.SOUTH) == Location.SOUTH); 847 eastCheckBox.setSelected((_location.getTrainDirections() & Location.EAST) == Location.EAST); 848 westCheckBox.setSelected((_location.getTrainDirections() & Location.WEST) == Location.WEST); 849 } 850 851 @Override 852 protected void comboBoxActionPerformed(ActionEvent ae) { 853 setDivisionButtonText(); 854 } 855 856 private void setDivisionButtonText() { 857 if (divisionComboBox.getSelectedItem() == null) { 858 editDivisionButton.setText(Bundle.getMessage("Add")); 859 } else { 860 editDivisionButton.setText(Bundle.getMessage("ButtonEdit")); 861 } 862 } 863 864 @Override 865 public void dispose() { 866 if (_location != null) { 867 _location.removePropertyChangeListener(this); 868 } 869 InstanceManager.getDefault(CarTypes.class).removePropertyChangeListener(this); 870 InstanceManager.getDefault(EngineTypes.class).removePropertyChangeListener(this); 871 yardModel.dispose(); 872 spurModel.dispose(); 873 interchangeModel.dispose(); 874 stagingModel.dispose(); 875 if (lctf != null) { 876 lctf.dispose(); 877 } 878 if (yef != null) { 879 yef.dispose(); 880 } 881 if (sef != null) { 882 sef.dispose(); 883 } 884 if (ief != null) { 885 ief.dispose(); 886 } 887 if (stef != null) { 888 stef.dispose(); 889 } 890 super.dispose(); 891 } 892 893 @Override 894 public void propertyChange(java.beans.PropertyChangeEvent e) { 895 if (Control.SHOW_PROPERTY) { 896 log.debug("Property change: ({}) old: ({}) new: ({})", e.getPropertyName(), e.getOldValue(), 897 e.getNewValue()); 898 } 899 if (e.getPropertyName().equals(CarTypes.CARTYPES_CHANGED_PROPERTY) || 900 e.getPropertyName().equals(EngineTypes.ENGINETYPES_CHANGED_PROPERTY) || 901 e.getPropertyName().equals(Location.TYPES_CHANGED_PROPERTY)) { 902 updateCheckboxes(); 903 } 904 if (e.getPropertyName().equals(DivisionManager.LISTLENGTH_CHANGED_PROPERTY)) { 905 updateDivisionComboBox(); 906 } 907 if (e.getPropertyName().equals(Setup.TRAIN_DIRECTION_PROPERTY_CHANGE)) { 908 setTrainDirectionBoxes(); 909 } 910 } 911 912 private static final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(LocationEditFrame.class); 913}