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 ShowTrainsServingLocationAction(_location, null)); 374 toolMenu.add(new ShowRoutesServingLocationAction(_location)); 375 if (_location != null && _location.isStaging()) { 376 toolMenu.add(new SchedulesAndStagingAction()); 377 } 378 toolMenu.addSeparator(); 379 toolMenu.add(new PrintLocationsAction(false, _location)); 380 toolMenu.add(new PrintLocationsAction(true, _location)); 381 } 382 383 // frames 384 DivisionEditFrame def = null; 385 YardEditFrame yef = null; 386 SpurEditFrame sef = null; 387 InterchangeEditFrame ief = null; 388 StagingEditFrame stef = null; 389 390 // Save, Delete, Add 391 @Override 392 public void buttonActionPerformed(java.awt.event.ActionEvent ae) { 393 if (ae.getSource() == editDivisionButton) { 394 if (def != null) { 395 def.dispose(); 396 } 397 def = new DivisionEditFrame((Division) divisionComboBox.getSelectedItem()); 398 } 399 if (ae.getSource() == addYardButton) { 400 yef = new YardEditFrame(); 401 yef.initComponents(_location, null); 402 } 403 if (ae.getSource() == addSpurButton) { 404 sef = new SpurEditFrame(); 405 sef.initComponents(_location, null); 406 } 407 if (ae.getSource() == addInterchangeButton) { 408 ief = new InterchangeEditFrame(); 409 ief.initComponents(_location, null); 410 } 411 if (ae.getSource() == addStagingButton) { 412 stef = new StagingEditFrame(); 413 stef.initComponents(_location, null); 414 } 415 416 if (ae.getSource() == saveLocationButton) { 417 log.debug("location save button activated"); 418 Location l = locationManager.getLocationByName(locationNameTextField.getText()); 419 if (_location == null && l == null) { 420 saveNewLocation(); 421 } else { 422 if (l != null && l != _location) { 423 reportLocationExists(Bundle.getMessage("save")); 424 return; 425 } 426 saveLocation(); 427 if (Setup.isCloseWindowOnSaveEnabled()) { 428 dispose(); 429 } 430 } 431 } 432 if (ae.getSource() == deleteLocationButton) { 433 log.debug("location delete button activated"); 434 deleteLocation(); 435 // save location file 436 OperationsXml.save(); 437 } 438 if (ae.getSource() == addLocationButton) { 439 Location l = locationManager.getLocationByName(locationNameTextField.getText()); 440 if (l != null) { 441 reportLocationExists(Bundle.getMessage("add")); 442 return; 443 } 444 saveNewLocation(); 445 } 446 if (ae.getSource() == setButton) { 447 selectCheckboxes(true); 448 } 449 if (ae.getSource() == clearButton) { 450 selectCheckboxes(false); 451 } 452 if (ae.getSource() == autoSelectButton) { 453 log.debug("auto select button pressed"); 454 if (JmriJOptionPane.showConfirmDialog(this, Bundle.getMessage("autoSelectCarTypes?"), 455 Bundle.getMessage("autoSelectLocations?"), JmriJOptionPane.YES_NO_OPTION) != JmriJOptionPane.YES_OPTION) { 456 return; 457 } 458 autoSelectCheckboxes(); 459 } 460 } 461 462 private void saveNewLocation() { 463 if (!checkName(Bundle.getMessage("add"))) { 464 return; 465 } 466 Location location = locationManager.newLocation(locationNameTextField.getText()); 467 yardModel.initTable(yardTable, location); 468 spurModel.initTable(spurTable, location); 469 interchangeModel.initTable(interchangeTable, location); 470 stagingModel.initTable(stagingTable, location); 471 _location = location; 472 _location.addPropertyChangeListener(this); 473 474 updateCheckboxes(); 475 enableButtons(true); 476 setTrainDirectionBoxes(); 477 saveLocation(); 478 loadToolMenu(); 479 } 480 481 private void deleteLocation() { 482 Location location = locationManager.getLocationByName(locationNameTextField.getText()); 483 if (location == null) { 484 return; 485 } 486 // check to see if any route uses this location 487 Route route = InstanceManager.getDefault(RouteManager.class).isLocationInUse(location); 488 if (route != null) { 489 JmriJOptionPane.showMessageDialog(this, 490 Bundle.getMessage("RouteUsesLocation", route.getName(), location.getName()), 491 Bundle.getMessage("CanNotDeleteLocation"), JmriJOptionPane.ERROR_MESSAGE); 492 // show all the routes using this location 493 ShowRoutesServingLocationFrame frame = new ShowRoutesServingLocationFrame(); 494 frame.initComponents(location); 495 return; 496 } 497 int count = location.getNumberRS(); 498 if (count > 0) { 499 if (JmriJOptionPane.showConfirmDialog(this, Bundle.getMessage("ThereAreCars", Integer.toString(count)), 500 Bundle.getMessage("deletelocation?"), 501 JmriJOptionPane.YES_NO_OPTION) != JmriJOptionPane.YES_OPTION) { 502 return; 503 } 504 } else { 505 if (JmriJOptionPane.showConfirmDialog(this, 506 Bundle.getMessage("DoYouWantToDeleteLocation", locationNameTextField.getText()), 507 Bundle.getMessage("deletelocation?"), 508 JmriJOptionPane.YES_NO_OPTION) != JmriJOptionPane.YES_OPTION) { 509 return; 510 } 511 } 512 513 yardModel.dispose(); 514 spurModel.dispose(); 515 interchangeModel.dispose(); 516 stagingModel.dispose(); 517 518 if (yef != null) { 519 yef.dispose(); 520 } 521 if (sef != null) { 522 sef.dispose(); 523 } 524 if (ief != null) { 525 ief.dispose(); 526 } 527 if (stef != null) { 528 stef.dispose(); 529 } 530 531 locationManager.deregister(location); 532 _location = null; 533 selectCheckboxes(false); 534 enableCheckboxes(false); 535 enableButtons(false); 536 } 537 538 private void saveLocation() { 539 if (!checkName(Bundle.getMessage("save"))) { 540 return; 541 } 542 // stop table editing so "Moves" are properly saved 543 if (spurTable.isEditing()) { 544 spurTable.getCellEditor().stopCellEditing(); 545 } 546 if (yardTable.isEditing()) { 547 yardTable.getCellEditor().stopCellEditing(); 548 } 549 if (interchangeTable.isEditing()) { 550 interchangeTable.getCellEditor().stopCellEditing(); 551 } 552 if (stagingTable.isEditing()) { 553 stagingTable.getCellEditor().stopCellEditing(); 554 } 555 _location.setName(locationNameTextField.getText()); 556 _location.setComment(TrainCommon.formatColorString(commentTextArea.getText(), commentColorChooser.getColor())); 557 _location.setDivision((Division) divisionComboBox.getSelectedItem()); 558 if (Setup.isRfidEnabled() && readerSelector != null) { 559 _location.setReporter(readerSelector.getSelectedItem()); 560 } 561 // save location file 562 OperationsXml.save(); 563 } 564 565 /** 566 * @return true if name OK and is less than the maximum allowed length 567 */ 568 private boolean checkName(String s) { 569 String locationName = locationNameTextField.getText().trim(); 570 if (locationName.isEmpty()) { 571 JmriJOptionPane.showMessageDialog(this, Bundle.getMessage("MustEnterName"), 572 Bundle.getMessage("CanNotLocation", s), JmriJOptionPane.ERROR_MESSAGE); 573 return false; 574 } 575 // hyphen feature needs at least one character to work properly 576 if (locationName.contains(TrainCommon.HYPHEN)) { 577 String[] check = locationName.split(TrainCommon.HYPHEN); 578 if (check.length == 0) { 579 JmriJOptionPane.showMessageDialog(this, Bundle.getMessage("HyphenFeature"), 580 Bundle.getMessage("CanNotLocation", s), JmriJOptionPane.ERROR_MESSAGE); 581 return false; 582 } 583 locationName = check[0]; 584 } 585 if (TrainCommon.splitString(locationName).length() > MAX_NAME_LENGTH) { 586 // log.error("Location name must be less than "+ 587 // Integer.toString(MAX_NAME_LENGTH+1) +" characters"); 588 JmriJOptionPane.showMessageDialog(this, 589 Bundle.getMessage("LocationNameLengthMax", Integer.toString(MAX_NAME_LENGTH + 1)), 590 Bundle.getMessage("CanNotLocation", s), JmriJOptionPane.ERROR_MESSAGE); 591 return false; 592 } 593 if (!OperationsXml.checkFileName(locationName)) { // NOI18N 594 JmriJOptionPane.showMessageDialog(this, 595 Bundle.getMessage("NameResChar") + NEW_LINE + Bundle.getMessage("ReservedChar"), 596 Bundle.getMessage("CanNotLocation", s), JmriJOptionPane.ERROR_MESSAGE); 597 return false; 598 } 599 return true; 600 } 601 602 private void reportLocationExists(String s) { 603 JmriJOptionPane.showMessageDialog(this, Bundle.getMessage("LocationAlreadyExists"), 604 Bundle.getMessage("CanNotLocation", s), JmriJOptionPane.ERROR_MESSAGE); 605 } 606 607 private void enableButtons(boolean enabled) { 608 toolMenu.setEnabled(enabled); 609 northCheckBox.setEnabled(enabled); 610 southCheckBox.setEnabled(enabled); 611 eastCheckBox.setEnabled(enabled); 612 westCheckBox.setEnabled(enabled); 613 divisionComboBox.setEnabled(enabled); 614 editDivisionButton.setEnabled(enabled); 615 clearButton.setEnabled(enabled); 616 setButton.setEnabled(enabled); 617 autoSelectButton.setEnabled(enabled); 618 addYardButton.setEnabled(enabled); 619 addSpurButton.setEnabled(enabled); 620 addInterchangeButton.setEnabled(enabled); 621 addStagingButton.setEnabled(enabled); 622 saveLocationButton.setEnabled(enabled); 623 deleteLocationButton.setEnabled(enabled); 624 // the inverse! 625 addLocationButton.setEnabled(!enabled); 626 // enable radio buttons 627 spurRadioButton.setEnabled(enabled); 628 yardRadioButton.setEnabled(enabled); 629 interchangeRadioButton.setEnabled(enabled); 630 stagingRadioButton.setEnabled(enabled); 631 if (readerSelector != null) { 632 // enable readerSelect. 633 readerSelector.setEnabled(enabled && Setup.isRfidEnabled()); 634 } 635 } 636 637 @Override 638 public void radioButtonActionPerformed(java.awt.event.ActionEvent ae) { 639 setVisibleTrackType(); 640 } 641 642 private void setVisibleTrackType() { 643 enableTrackTypeRadioButtons(); 644 interchangePane.setVisible(interchangeRadioButton.isSelected()); 645 addInterchangeButton.setVisible(interchangeRadioButton.isSelected()); 646 stagingPane.setVisible(stagingRadioButton.isSelected()); 647 addStagingButton.setVisible(stagingRadioButton.isSelected()); 648 yardPane.setVisible(yardRadioButton.isSelected()); 649 addYardButton.setVisible(yardRadioButton.isSelected()); 650 spurPane.setVisible(spurRadioButton.isSelected()); 651 addSpurButton.setVisible(spurRadioButton.isSelected()); 652 } 653 654 private void enableTrackTypeRadioButtons() { 655 if (spurModel.getRowCount() > 0 || yardModel.getRowCount() > 0 || interchangeModel.getRowCount() > 0) { 656 if (stagingRadioButton.isSelected()) { 657 spurRadioButton.setSelected(true); 658 } 659 stagingRadioButton.setEnabled(false); 660 } else if (stagingModel.getRowCount() > 0) { 661 stagingRadioButton.setSelected(true); 662 spurRadioButton.setEnabled(false); 663 yardRadioButton.setEnabled(false); 664 interchangeRadioButton.setEnabled(false); 665 } else if (_location != null) { 666 spurRadioButton.setEnabled(true); 667 yardRadioButton.setEnabled(true); 668 interchangeRadioButton.setEnabled(true); 669 stagingRadioButton.setEnabled(true); 670 } 671 } 672 673 private void enableCheckboxes(boolean enable) { 674 for (JCheckBox checkBox : new ArrayList<>(checkBoxes)) { 675 checkBox.setEnabled(enable); 676 } 677 } 678 679 /* 680 * Protected against concurrent changes by making a copy 681 * of the checkBoxes list. 682 */ 683 private void selectCheckboxes(boolean select) { 684 for (JCheckBox checkBox : new ArrayList<>(checkBoxes)) { 685 checkBox.setSelected(select); 686 if (_location != null) { 687 if (select) { 688 _location.addTypeName(checkBox.getText()); 689 } else { 690 _location.deleteTypeName(checkBox.getText()); 691 } 692 } 693 } 694 } 695 696 private void updateCheckboxes() { 697 x = 0; 698 y = 0; 699 checkBoxes.clear(); 700 panelCheckBoxes.removeAll(); 701 numberOfCheckBoxes = getNumberOfCheckboxesPerLine(); 702 loadTypes(InstanceManager.getDefault(CarTypes.class).getNames()); 703 704 // add space between car and loco types 705 checkNewLine(); 706 707 loadTypes(InstanceManager.getDefault(EngineTypes.class).getNames()); 708 JPanel p = new JPanel(); 709 p.add(clearButton); 710 p.add(setButton); 711 p.add(autoSelectButton); 712 GridBagConstraints gc = new GridBagConstraints(); 713 gc.gridwidth = getNumberOfCheckboxesPerLine() + 1; 714 gc.gridy = ++y; 715 panelCheckBoxes.add(p, gc); 716 panelCheckBoxes.revalidate(); 717 repaint(); 718 } 719 720 protected void updateDivisionComboBox() { 721 InstanceManager.getDefault(DivisionManager.class).updateComboBox(divisionComboBox); 722 if (_location != null) { 723 divisionComboBox.setSelectedItem(_location.getDivision()); 724 } 725 } 726 727 int x = 0; 728 int y = 0; // vertical position in panel 729 730 private void loadTypes(String[] types) { 731 for (String type : types) { 732 JCheckBox checkBox = new JCheckBox(); 733 checkBoxes.add(checkBox); 734 checkBox.setText(type); 735 addCheckBoxAction(checkBox); 736 addItemLeft(panelCheckBoxes, checkBox, x, y); 737 if (_location != null) { 738 if (_location.acceptsTypeName(type)) { 739 checkBox.setSelected(true); 740 } 741 } else { 742 checkBox.setEnabled(false); 743 } 744 checkNewLine(); 745 } 746 } 747 748 int numberOfCheckBoxes; 749 750 private void checkNewLine() { 751 if (++x > numberOfCheckBoxes) { 752 y++; 753 x = 0; 754 } 755 } 756 757 /** 758 * Adjust the location's car service types to only reflect the car types 759 * serviced by the location's tracks. Protected against concurrent changes by 760 * creating a new list of checkboxes. 761 */ 762 private void autoSelectCheckboxes() { 763 for (JCheckBox checkBox : new ArrayList<>(checkBoxes)) { 764 checkBox.setSelected(false); 765 // check each track to determine which car types are serviced by 766 // this location 767 List<Track> tracks = _location.getTracksList(); 768 for (Track track : tracks) { 769 if (track.isTypeNameAccepted(checkBox.getText())) { 770 checkBox.setSelected(true); 771 } 772 } 773 // this type of car isn't serviced by any of the tracks, so delete 774 if (!checkBox.isSelected()) { 775 _location.deleteTypeName(checkBox.getText()); 776 } 777 } 778 } 779 780 LocationsByCarTypeFrame lctf = null; 781 782 @Override 783 public void checkBoxActionPerformed(java.awt.event.ActionEvent ae) { 784 JCheckBox b = (JCheckBox) ae.getSource(); 785 log.debug("checkbox change {}", b.getText()); 786 if (_location == null) { 787 return; 788 } 789 _location.removePropertyChangeListener(this); 790 if (b.isSelected()) { 791 _location.addTypeName(b.getText()); 792 // show which tracks will service this car type 793 if (InstanceManager.getDefault(CarTypes.class).containsName(b.getText())) { 794 if (lctf != null) { 795 lctf.dispose(); 796 } 797 lctf = new LocationsByCarTypeFrame(); 798 lctf.initComponents(_location, b.getText()); 799 } 800 } else { 801 _location.deleteTypeName(b.getText()); 802 } 803 _location.addPropertyChangeListener(this); 804 } 805 806 private void addCheckBoxTrainAction(JCheckBox b) { 807 b.addActionListener(new java.awt.event.ActionListener() { 808 @Override 809 public void actionPerformed(java.awt.event.ActionEvent e) { 810 checkBoxActionTrainPerformed(e); 811 } 812 }); 813 } 814 815 private void checkBoxActionTrainPerformed(java.awt.event.ActionEvent ae) { 816 // save train directions serviced by this location 817 if (_location == null) { 818 return; 819 } 820 int direction = 0; 821 if (northCheckBox.isSelected()) { 822 direction += Location.NORTH; 823 } 824 if (southCheckBox.isSelected()) { 825 direction += Location.SOUTH; 826 } 827 if (eastCheckBox.isSelected()) { 828 direction += Location.EAST; 829 } 830 if (westCheckBox.isSelected()) { 831 direction += Location.WEST; 832 } 833 _location.setTrainDirections(direction); 834 835 } 836 837 private void setTrainDirectionBoxes() { 838 northCheckBox.setVisible((Setup.getTrainDirection() & Setup.NORTH) == Setup.NORTH); 839 southCheckBox.setVisible((Setup.getTrainDirection() & Setup.SOUTH) == Setup.SOUTH); 840 eastCheckBox.setVisible((Setup.getTrainDirection() & Setup.EAST) == Setup.EAST); 841 westCheckBox.setVisible((Setup.getTrainDirection() & Setup.WEST) == Setup.WEST); 842 843 northCheckBox.setSelected((_location.getTrainDirections() & Location.NORTH) == Location.NORTH); 844 southCheckBox.setSelected((_location.getTrainDirections() & Location.SOUTH) == Location.SOUTH); 845 eastCheckBox.setSelected((_location.getTrainDirections() & Location.EAST) == Location.EAST); 846 westCheckBox.setSelected((_location.getTrainDirections() & Location.WEST) == Location.WEST); 847 } 848 849 @Override 850 protected void comboBoxActionPerformed(ActionEvent ae) { 851 setDivisionButtonText(); 852 } 853 854 private void setDivisionButtonText() { 855 if (divisionComboBox.getSelectedItem() == null) { 856 editDivisionButton.setText(Bundle.getMessage("Add")); 857 } else { 858 editDivisionButton.setText(Bundle.getMessage("ButtonEdit")); 859 } 860 } 861 862 @Override 863 public void dispose() { 864 if (_location != null) { 865 _location.removePropertyChangeListener(this); 866 } 867 InstanceManager.getDefault(CarTypes.class).removePropertyChangeListener(this); 868 InstanceManager.getDefault(EngineTypes.class).removePropertyChangeListener(this); 869 yardModel.dispose(); 870 spurModel.dispose(); 871 interchangeModel.dispose(); 872 stagingModel.dispose(); 873 if (lctf != null) { 874 lctf.dispose(); 875 } 876 if (yef != null) { 877 yef.dispose(); 878 } 879 if (sef != null) { 880 sef.dispose(); 881 } 882 if (ief != null) { 883 ief.dispose(); 884 } 885 if (stef != null) { 886 stef.dispose(); 887 } 888 super.dispose(); 889 } 890 891 @Override 892 public void propertyChange(java.beans.PropertyChangeEvent e) { 893 if (Control.SHOW_PROPERTY) { 894 log.debug("Property change: ({}) old: ({}) new: ({})", e.getPropertyName(), e.getOldValue(), 895 e.getNewValue()); 896 } 897 if (e.getPropertyName().equals(CarTypes.CARTYPES_CHANGED_PROPERTY) || 898 e.getPropertyName().equals(EngineTypes.ENGINETYPES_CHANGED_PROPERTY) || 899 e.getPropertyName().equals(Location.TYPES_CHANGED_PROPERTY)) { 900 updateCheckboxes(); 901 } 902 if (e.getPropertyName().equals(DivisionManager.LISTLENGTH_CHANGED_PROPERTY)) { 903 updateDivisionComboBox(); 904 } 905 if (e.getPropertyName().equals(Setup.TRAIN_DIRECTION_PROPERTY_CHANGE)) { 906 setTrainDirectionBoxes(); 907 } 908 } 909 910 private static final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(LocationEditFrame.class); 911}