001package jmri.jmrit.beantable; 002 003import java.awt.Color; 004import java.awt.Component; 005import java.awt.event.ActionEvent; 006import java.awt.event.ActionListener; 007import java.util.Objects; 008import java.util.Vector; 009 010import javax.annotation.Nonnull; 011import javax.swing.*; 012 013import jmri.*; 014import jmri.jmrit.beantable.turnout.TurnoutTableDataModel; 015import jmri.jmrit.turnoutoperations.TurnoutOperationFrame; 016import jmri.swing.ManagerComboBox; 017import jmri.swing.SystemNameValidator; 018import jmri.util.JmriJFrame; 019import jmri.util.swing.*; 020 021/** 022 * Swing action to create and register a TurnoutTable GUI. 023 * 024 * @author Bob Jacobsen Copyright (C) 2003, 2004, 2007 025 * @author Egbert Broerse Copyright (C) 2017 026 */ 027public class TurnoutTableAction extends AbstractTableAction<Turnout> { 028 029 /** 030 * Create an action with a specific title. 031 * <p> 032 * Note that the argument is the Action title, not the title of the 033 * resulting frame. Perhaps this should be changed? 034 * 035 * @param actionName title of the action 036 */ 037 public TurnoutTableAction(String actionName) { 038 super(actionName); 039 040 // disable ourself if there is no primary turnout manager available 041 if (turnoutManager == null) { 042 super.setEnabled(false); 043 } 044 } 045 046 public TurnoutTableAction() { 047 this(Bundle.getMessage("TitleTurnoutTable")); 048 } 049 050 protected TurnoutManager turnoutManager = InstanceManager.getDefault(TurnoutManager.class); 051 052 /** 053 * {@inheritDoc} 054 */ 055 @Override 056 public void setManager(@Nonnull Manager<Turnout> man) { 057 if (man instanceof TurnoutManager) { 058 log.debug("setting manager of TTAction {} to {}",this,man.getClass()); 059 turnoutManager = (TurnoutManager) man; 060 if (m!=null){ // also update Table Model 061 m.setManager(man); 062 } 063 } 064 } 065 066 /** 067 * Create the JTable DataModel, along with the changes for the specific case 068 * of Turnouts. 069 */ 070 @Override 071 protected void createModel() { 072 m = new TurnoutTableDataModel(turnoutManager); 073 } 074 075 /** 076 * {@inheritDoc} 077 */ 078 @Override 079 protected void setTitle() { 080 f.setTitle(Bundle.getMessage("TitleTurnoutTable")); 081 } 082 083 /** 084 * {@inheritDoc} 085 */ 086 @Override 087 protected String helpTarget() { 088 return "package.jmri.jmrit.beantable.TurnoutTable"; 089 } 090 091 JmriJFrame addFrame = null; 092 093 JTextField hardwareAddressTextField = new JTextField(20); 094 // initially allow any 20 char string, updated to prefixBox selection by canAddRange() 095 JTextField userNameTextField = new JTextField(40); 096 ManagerComboBox<Turnout> prefixBox = new ManagerComboBox<>(); 097 SpinnerNumberModel rangeSpinner = new SpinnerNumberModel(1, 1, 100, 1); // maximum 100 items 098 JSpinner numberToAddSpinner = new JSpinner(rangeSpinner); 099 JCheckBox rangeBox = new JCheckBox(Bundle.getMessage("AddRangeBox")); 100 String systemSelectionCombo = this.getClass().getName() + ".SystemSelected"; 101 JButton addButton; 102 JLabel statusBarLabel = new JLabel(Bundle.getMessage("HardwareAddStatusEnter"), JLabel.LEADING); 103 jmri.UserPreferencesManager pref; 104 SystemNameValidator hardwareAddressValidator; 105 106 /** 107 * {@inheritDoc} 108 */ 109 @Override 110 protected void addPressed(ActionEvent e) { 111 pref = jmri.InstanceManager.getDefault(jmri.UserPreferencesManager.class); 112 113 if (addFrame == null) { 114 addFrame = new JmriJFrame(Bundle.getMessage("TitleAddTurnout"), false, true); 115 addFrame.addHelpMenu("package.jmri.jmrit.beantable.TurnoutAddEdit", true); 116 addFrame.getContentPane().setLayout(new BoxLayout(addFrame.getContentPane(), BoxLayout.Y_AXIS)); 117 118 ActionListener cancelListener = this::cancelPressed; 119 // add rangeBox box turned on/off 120 ActionListener rangeListener = this::canAddRange; 121 122 /* We use the proxy manager in this instance so that we can deal with 123 duplicate usernames in multiple classes */ 124 configureManagerComboBox(prefixBox, turnoutManager, TurnoutManager.class); 125 userNameTextField.setName("userNameTextField"); // NOI18N 126 prefixBox.setName("prefixBox"); // NOI18N 127 // set up validation, zero text = false 128 addButton = new JButton(Bundle.getMessage("ButtonCreate")); 129 addButton.addActionListener(this::createPressed); 130 // create panel 131 132 if (hardwareAddressValidator==null){ 133 hardwareAddressValidator = new SystemNameValidator(hardwareAddressTextField, Objects.requireNonNull(prefixBox.getSelectedItem()), true); 134 } else { 135 hardwareAddressValidator.setManager(prefixBox.getSelectedItem()); 136 } 137 138 addFrame.add(new AddNewHardwareDevicePanel(hardwareAddressTextField, hardwareAddressValidator, userNameTextField, prefixBox, 139 numberToAddSpinner, rangeBox, addButton, cancelListener, rangeListener, statusBarLabel)); 140 // tooltip for hardwareAddressTextField will be assigned next by canAddRange() 141 canAddRange(null); 142 } 143 hardwareAddressTextField.setName("hwAddressTextField"); // for GUI test NOI18N 144 addButton.setName("createButton"); // for GUI test NOI18N 145 146 addFrame.setEscapeKeyClosesWindow(true); 147 addFrame.getRootPane().setDefaultButton(addButton); 148 149 // reset statusBarLabel text 150 statusBarLabel.setText(Bundle.getMessage("HardwareAddStatusEnter")); 151 statusBarLabel.setForeground(Color.gray); 152 153 addFrame.pack(); 154 addFrame.setVisible(true); 155 } 156 157 /** 158 * Add the content and make the appropriate selection to a combo box for a 159 * turnout's automation choices. 160 * 161 * @param t turnout 162 * @param cb the JComboBox 163 */ 164 public static void updateAutomationBox(Turnout t, JComboBox<String> cb) { 165 TurnoutOperation[] ops = InstanceManager.getDefault(TurnoutOperationManager.class).getTurnoutOperations(); 166 cb.removeAllItems(); 167 Vector<String> strings = new Vector<>(20); 168 Vector<String> defStrings = new Vector<>(20); 169 log.debug("opsCombo start {}", ops.length); 170 for (TurnoutOperation op : ops) { 171 if (log.isDebugEnabled()) { 172 log.debug("isDef {} mFMM {} isNonce {}", op.isDefinitive(), op.matchFeedbackMode(t.getFeedbackMode()), op.isNonce()); 173 } 174 if (!op.isDefinitive() && op.matchFeedbackMode(t.getFeedbackMode()) && !op.isNonce()) { 175 strings.addElement(op.getName()); 176 } 177 } 178 log.debug("opsCombo end"); 179 for (TurnoutOperation op : ops) { 180 if (op.isDefinitive() && op.matchFeedbackMode(t.getFeedbackMode())) { 181 defStrings.addElement(op.getName()); 182 } 183 } 184 java.util.Collections.sort(strings); 185 java.util.Collections.sort(defStrings); 186 strings.insertElementAt(Bundle.getMessage("TurnoutOperationOff"), 0); 187 strings.insertElementAt(Bundle.getMessage("TurnoutOperationDefault"), 1); 188 for (int i = 0; i < defStrings.size(); ++i) { 189 try { 190 strings.insertElementAt(defStrings.elementAt(i), i + 2); 191 } catch (java.lang.ArrayIndexOutOfBoundsException obe) { 192 // just catch it 193 } 194 } 195 for (int i = 0; i < strings.size(); ++i) { 196 cb.addItem(strings.elementAt(i)); 197 } 198 if (t.getInhibitOperation()) { 199 cb.setSelectedIndex(0); 200 } else { 201 TurnoutOperation turnOp = t.getTurnoutOperation(); 202 if (turnOp == null) { 203 cb.setSelectedIndex(1); 204 } else { 205 if (turnOp.isNonce()) { 206 cb.setSelectedIndex(2); 207 } else { 208 cb.setSelectedItem(turnOp.getName()); 209 } 210 } 211 } 212 // Set custom renderer with tooltips 213 cb.setRenderer(new DefaultListCellRenderer() { 214 @Override 215 public Component getListCellRendererComponent(JList<?> list, Object value, 216 int index, boolean isSelected, boolean cellHasFocus) { 217 JLabel lbl = (JLabel)super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus); 218 if (value != null) { 219 lbl.setToolTipText(InstanceManager.getDefault(TurnoutOperationManager.class) 220 .getTooltipForOperator(value.toString(), t)); 221 } 222 return lbl; 223 } 224 }); 225 } 226 227 /** 228 * Show a pane to configure closed and thrown turnout speed defaults. 229 * 230 * @param _who parent JFrame to center the pane on 231 */ 232 protected void setDefaultSpeeds(JFrame _who) { 233 JComboBox<String> thrownCombo = new JComboBox<>((( TurnoutTableDataModel)m).speedListThrown); 234 JComboBox<String> closedCombo = new JComboBox<>((( TurnoutTableDataModel)m).speedListClosed); 235 thrownCombo.setEditable(true); 236 closedCombo.setEditable(true); 237 238 JComboBoxUtil.setupComboBoxMaxRows(thrownCombo); 239 JComboBoxUtil.setupComboBoxMaxRows(closedCombo); 240 241 JPanel thrown = new JPanel(); 242 thrown.add(new JLabel(Bundle.getMessage("MakeLabel", Bundle.getMessage("ThrownSpeed")))); 243 thrown.add(thrownCombo); 244 245 JPanel closed = new JPanel(); 246 closed.add(new JLabel(Bundle.getMessage("MakeLabel", Bundle.getMessage("ClosedSpeed")))); 247 closed.add(closedCombo); 248 249 thrownCombo.removeItem((( TurnoutTableDataModel)m).defaultThrownSpeedText); 250 closedCombo.removeItem((( TurnoutTableDataModel)m).defaultClosedSpeedText); 251 252 thrownCombo.setSelectedItem(turnoutManager.getDefaultThrownSpeed()); 253 closedCombo.setSelectedItem(turnoutManager.getDefaultClosedSpeed()); 254 255 // block of options above row of buttons; gleaned from Maintenance.makeDialog() 256 // can be accessed by Jemmy in GUI test 257 String title = Bundle.getMessage("TurnoutGlobalSpeedMessageTitle"); 258 // build JPanel for comboboxes 259 JPanel speedspanel = new JPanel(); 260 speedspanel.setLayout(new BoxLayout(speedspanel, BoxLayout.PAGE_AXIS)); 261 speedspanel.add(new JLabel(Bundle.getMessage("TurnoutGlobalSpeedMessage"))); 262 //default LEFT_ALIGNMENT 263 thrown.setAlignmentX(Component.LEFT_ALIGNMENT); 264 speedspanel.add(thrown); 265 closed.setAlignmentX(Component.LEFT_ALIGNMENT); 266 speedspanel.add(closed); 267 268 int retval = JmriJOptionPane.showConfirmDialog(_who, 269 speedspanel, 270 title, 271 JmriJOptionPane.OK_CANCEL_OPTION, 272 JmriJOptionPane.INFORMATION_MESSAGE); 273 log.debug("Retval = {}", retval); 274 if (retval != JmriJOptionPane.OK_OPTION) { // OK button not clicked 275 return; 276 } 277 String closedValue = (String) closedCombo.getSelectedItem(); 278 String thrownValue = (String) thrownCombo.getSelectedItem(); 279 280 // We will allow the turnout manager to handle checking whether the values have changed 281 try { 282 assert thrownValue != null; 283 turnoutManager.setDefaultThrownSpeed(thrownValue); 284 } catch (jmri.JmriException ex) { 285 JmriJOptionPane.showMessageDialog(null, ex.getMessage() + "\n" + thrownValue); 286 } 287 288 try { 289 assert closedValue != null; 290 turnoutManager.setDefaultClosedSpeed(closedValue); 291 } catch (jmri.JmriException ex) { 292 JmriJOptionPane.showMessageDialog(null, ex.getMessage() + "\n" + closedValue); 293 } 294 } 295 296 private final JCheckBox doAutomationBox = new JCheckBox(Bundle.getMessage("AutomaticRetry")); 297 private final TriStateJCheckBox showFeedbackBox = new TriStateJCheckBox(Bundle.getMessage("ShowFeedbackInfo")); 298 private final TriStateJCheckBox showLockBox = new TriStateJCheckBox(Bundle.getMessage("ShowLockInfo")); 299 private final TriStateJCheckBox showTurnoutSpeedBox = new TriStateJCheckBox(Bundle.getMessage("ShowTurnoutSpeedDetails")); 300 private final TriStateJCheckBox showStateForgetAndQueryBox = new TriStateJCheckBox(Bundle.getMessage("ShowStateForgetAndQuery")); 301 302 private void initCheckBoxes(){ 303 doAutomationBox.setSelected(InstanceManager.getDefault(TurnoutOperationManager.class).getDoOperations()); 304 doAutomationBox.setToolTipText(Bundle.getMessage("TurnoutDoAutomationBoxTooltip")); 305 doAutomationBox.addActionListener(e -> InstanceManager.getDefault(TurnoutOperationManager.class).setDoOperations(doAutomationBox.isSelected())); 306 307 showFeedbackBox.setToolTipText(Bundle.getMessage("TurnoutFeedbackToolTip")); 308 showLockBox.setToolTipText(Bundle.getMessage("TurnoutLockToolTip")); 309 showTurnoutSpeedBox.setToolTipText(Bundle.getMessage("TurnoutSpeedToolTip")); 310 showStateForgetAndQueryBox.setToolTipText(Bundle.getMessage("StateForgetAndQueryBoxToolTip")); 311 } 312 313 @Override 314 protected void configureTable(JTable table){ 315 super.configureTable(table); 316 showStateForgetAndQueryBox.addActionListener(e -> 317 ((TurnoutTableDataModel) m).showStateForgetAndQueryChanged(showStateForgetAndQueryBox.isSelected(),table)); 318 showTurnoutSpeedBox.addActionListener(e -> 319 ((TurnoutTableDataModel) m).showTurnoutSpeedChanged(showTurnoutSpeedBox.isSelected(),table)); 320 showFeedbackBox.addActionListener(e -> 321 ((TurnoutTableDataModel) m).showFeedbackChanged(showFeedbackBox.isSelected(), table)); 322 showLockBox.addActionListener(e -> 323 ((TurnoutTableDataModel) m).showLockChanged(showLockBox.isSelected(),table)); 324 } 325 326 /** 327 * Add the check boxes to show/hide extra columns to the Turnout table 328 * frame. 329 * <p> 330 * Keep contents synchronized with 331 * {@link #addToPanel(AbstractTableTabAction)} 332 * 333 * @param f a Turnout table frame 334 */ 335 @Override 336 public void addToFrame(BeanTableFrame<Turnout> f) { 337 initCheckBoxes(); 338 f.addToBottomBox(doAutomationBox, this.getClass().getName()); 339 f.addToBottomBox(showFeedbackBox, this.getClass().getName()); 340 f.addToBottomBox(showLockBox, this.getClass().getName()); 341 f.addToBottomBox(showTurnoutSpeedBox, this.getClass().getName()); 342 f.addToBottomBox(showStateForgetAndQueryBox, this.getClass().getName()); 343 } 344 345 /** 346 * Place the check boxes to show/hide extra columns to the tabbed Turnout 347 * table panel. 348 * <p> 349 * Keep contents synchronized with {@link #addToFrame(BeanTableFrame)} 350 * 351 * @param f a Turnout table action 352 */ 353 @Override 354 public void addToPanel(AbstractTableTabAction<Turnout> f) { 355 String connectionName = turnoutManager.getMemo().getUserName(); 356 if (turnoutManager.getClass().getName().contains("ProxyTurnoutManager")) { 357 connectionName = "All"; // NOI18N 358 } 359 initCheckBoxes(); 360 f.addToBottomBox(doAutomationBox, connectionName); 361 f.addToBottomBox(showFeedbackBox, connectionName); 362 f.addToBottomBox(showLockBox, connectionName); 363 f.addToBottomBox(showTurnoutSpeedBox, connectionName); 364 f.addToBottomBox(showStateForgetAndQueryBox, connectionName); 365 } 366 367 /** 368 * Override to update column select checkboxes. 369 * {@inheritDoc} 370 */ 371 @Override 372 protected void columnsVisibleUpdated(boolean[] colsVisible){ 373 log.debug("columns updated {}",colsVisible); 374 showFeedbackBox.setState(new boolean[]{ 375 colsVisible[TurnoutTableDataModel.KNOWNCOL], 376 colsVisible[TurnoutTableDataModel.MODECOL], 377 colsVisible[TurnoutTableDataModel.SENSOR1COL], 378 colsVisible[TurnoutTableDataModel.SENSOR2COL], 379 colsVisible[TurnoutTableDataModel.OPSONOFFCOL], 380 colsVisible[TurnoutTableDataModel.OPSEDITCOL]}); 381 382 showLockBox.setState(new boolean[]{ 383 colsVisible[TurnoutTableDataModel.LOCKDECCOL], 384 colsVisible[TurnoutTableDataModel.LOCKOPRCOL]}); 385 386 showTurnoutSpeedBox.setState(new boolean[]{ 387 colsVisible[TurnoutTableDataModel.STRAIGHTCOL], 388 colsVisible[TurnoutTableDataModel.DIVERGCOL]}); 389 390 showStateForgetAndQueryBox.setState(new boolean[]{ 391 colsVisible[TurnoutTableDataModel.FORGETCOL], 392 colsVisible[TurnoutTableDataModel.QUERYCOL]}); 393 394 } 395 396 /** 397 * Insert table specific Automation and Speeds menus. Account for the Window and Help 398 * menus, which are already added to the menu bar as part of the creation of 399 * the JFrame, by adding the Automation menu 2 places earlier unless the 400 * table is part of the ListedTableFrame, that adds the Help menu later on. 401 * 402 * @param f the JFrame of this table 403 */ 404 @Override 405 public void setMenuBar(BeanTableFrame<Turnout> f) { 406 final jmri.util.JmriJFrame finalF = f; // needed for anonymous ActionListener class 407 JMenuBar menuBar = f.getJMenuBar(); 408 // check for menu 409 boolean menuAbsent = true; 410 for (int i = 0; i < menuBar.getMenuCount(); ++i) { 411 String name = menuBar.getMenu(i).getAccessibleContext().getAccessibleName(); 412 if (name.equals(Bundle.getMessage("TurnoutAutomationMenu"))) { 413 // using first menu for check, should be identical to next JMenu Bundle 414 menuAbsent = false; 415 break; 416 } 417 } 418 if (menuAbsent) { // create it 419 int pos = menuBar.getMenuCount() - 1; // count the number of menus to insert the TableMenu before 'Window' and 'Help' 420 int offset = 1; 421 log.debug("setMenuBar number of menu items = {}", pos); 422 for (int i = 0; i <= pos; i++) { 423 if (menuBar.getComponent(i) instanceof JMenu) { 424 if (((JMenu) menuBar.getComponent(i)).getText().equals(Bundle.getMessage("MenuHelp"))) { 425 offset = -1; // correct for use as part of ListedTableAction where the Help Menu is not yet present 426 } 427 } 428 } 429 JMenu opsMenu = new JMenu(Bundle.getMessage("TurnoutAutomationMenu")); 430 JMenuItem item = new JMenuItem(Bundle.getMessage("TurnoutAutomationMenuItemEdit")); 431 opsMenu.add(item); 432 item.addActionListener(e -> new TurnoutOperationFrame(finalF)); 433 menuBar.add(opsMenu, pos + offset); 434 435 JMenu speedMenu = new JMenu(Bundle.getMessage("SpeedsMenu")); 436 item = new JMenuItem(Bundle.getMessage("SpeedsMenuItemDefaults")); 437 speedMenu.add(item); 438 item.addActionListener(e -> setDefaultSpeeds(finalF)); 439 menuBar.add(speedMenu, pos + offset + 1); // add this menu to the right of the previous 440 } 441 } 442 443 void cancelPressed(ActionEvent e) { 444 removePrefixBoxListener(prefixBox); 445 addFrame.setVisible(false); 446 addFrame.dispose(); 447 addFrame = null; 448 } 449 450 /** 451 * Respond to Create new item button pressed on Add Turnout pane. 452 * 453 * @param e the click event 454 */ 455 void createPressed(ActionEvent e) { 456 457 int numberOfTurnouts = 1; 458 459 if (rangeBox.isSelected()) { 460 numberOfTurnouts = (Integer) numberToAddSpinner.getValue(); 461 } 462 if (numberOfTurnouts >= 65 // limited by JSpinnerModel to 100 463 && JmriJOptionPane.showConfirmDialog(addFrame, 464 Bundle.getMessage("WarnExcessBeans", Bundle.getMessage("Turnouts"), numberOfTurnouts), 465 Bundle.getMessage("WarningTitle"), 466 JmriJOptionPane.YES_NO_OPTION) != JmriJOptionPane.YES_OPTION ) { 467 return; 468 } 469 470 String sName; 471 String prefix = Objects.requireNonNull(prefixBox.getSelectedItem()).getSystemPrefix(); 472 473 String curAddress = hardwareAddressTextField.getText(); 474 // initial check for empty entry 475 if (curAddress.length() < 1) { 476 statusBarLabel.setText(Bundle.getMessage("WarningEmptyHardwareAddress")); 477 statusBarLabel.setForeground(Color.red); 478 hardwareAddressTextField.setBackground(Color.red); 479 return; 480 } else { 481 hardwareAddressTextField.setBackground(Color.white); 482 } 483 484 String uName = userNameTextField.getText(); 485 if (uName.isEmpty()) { 486 uName = null; 487 } 488 489 // Add some entry pattern checking, before assembling sName and handing it to the TurnoutManager 490 StringBuilder statusMessage = new StringBuilder(Bundle.getMessage("ItemCreateFeedback", Bundle.getMessage("BeanNameTurnout"))); 491 492 // Compose the proposed system name from parts: 493 sName = prefix + InstanceManager.getDefault(TurnoutManager.class).typeLetter() + curAddress; 494 495 int iType = 0; 496 int iNum = 1; 497 boolean useLastBit = false; 498 boolean useLastType = false; 499 500 for (int x = 0; x < numberOfTurnouts; x++) { 501 502 Turnout t; 503 504 // test for a Light by the same hardware address (number): 505 // String testSN = prefix + "L" + curAddress; <========= from sName instead 506 StringBuilder sb = new StringBuilder(sName); 507 int prefixLength = Manager.getSystemPrefixLength(sName); 508 sb.replace(prefixLength, prefixLength+1, "L"); 509 String testSN = new String(sb); 510 log.trace("{} maps to {}", sName, testSN); 511 512 jmri.Light testLight = InstanceManager.lightManagerInstance(). 513 getBySystemName(testSN); 514 if (testLight != null) { 515 // Address (number part) is already used as a Light 516 log.warn("Requested Turnout {} uses same address as Light {}", sName, testSN); 517 if (!noWarn) { 518 int selectedValue = JmriJOptionPane.showOptionDialog(addFrame, 519 Bundle.getMessage("TurnoutWarn1", sName, testSN) 520 + ".\n" + Bundle.getMessage("TurnoutWarn3"), Bundle.getMessage("WarningTitle"), 521 JmriJOptionPane.YES_NO_CANCEL_OPTION, JmriJOptionPane.QUESTION_MESSAGE, null, 522 new Object[]{Bundle.getMessage("ButtonYes"), Bundle.getMessage("ButtonNo"), 523 Bundle.getMessage("ButtonYesPlus")}, Bundle.getMessage("ButtonNo")); // default choice = No 524 if (selectedValue == 1) { // ButtonNo 525 // Show error message in statusBarLabel 526 statusBarLabel.setText(Bundle.getMessage("WarningOverlappingAddress", sName)); 527 statusBarLabel.setForeground(Color.gray); 528 return; // return without creating if "No" response 529 } 530 if (selectedValue == 2) { // ButtonYesPlus 531 // Suppress future warnings, and continue 532 noWarn = true; 533 } 534 } 535 } 536 537 // Ask about two bit turnout control if appropriate 538 if (!useLastBit) { 539 iNum = InstanceManager.getDefault(TurnoutManager.class).askNumControlBits(sName); 540 if ((InstanceManager.getDefault(TurnoutManager.class).isNumControlBitsSupported(sName)) && (rangeBox.isSelected())) { 541 // Add a pop up here asking if the user wishes to use the same value for all 542 if (JmriJOptionPane.showConfirmDialog(addFrame, 543 Bundle.getMessage("UseForAllTurnouts"), Bundle.getMessage("UseSetting"), 544 JmriJOptionPane.YES_NO_OPTION) == 0) { 545 useLastBit = true; 546 } 547 } else { 548 // as isNumControlBits is not supported, we will always use the same value. 549 useLastBit = true; 550 } 551 } 552 if (iNum == 0) { 553 // User specified more bits, but bits are not available - return without creating 554 // Display message in statusBarLabel 555 statusBarLabel.setText(Bundle.getMessage("WarningBitsNotSupported", sName)); 556 statusBarLabel.setForeground(Color.red); 557 return; 558 } else { 559 560 // Create the new turnout 561 try { 562 t = InstanceManager.getDefault(TurnoutManager.class).provideTurnout(sName); 563 } catch (IllegalArgumentException ex) { 564 // user input no good 565 handleCreateException(ex, sName); // displays message dialog to the user 566 return; // without creating 567 } 568 if ((uName != null) && !uName.isEmpty()) { 569 if (InstanceManager.getDefault(TurnoutManager.class).getByUserName(uName) == null) { 570 t.setUserName(uName); 571 } else if (!pref.getPreferenceState(getClassName(), "duplicateUserName")) { 572 InstanceManager.getDefault(jmri.UserPreferencesManager.class). 573 showErrorMessage(Bundle.getMessage("ErrorTitle"), 574 Bundle.getMessage("ErrorDuplicateUserName", uName), 575 getClassName(), "duplicateUserName", false, true); 576 } 577 } 578 579 t.setNumberControlBits(iNum); 580 // Ask about the type of turnout control if appropriate 581 if (!useLastType) { 582 iType = InstanceManager.getDefault(TurnoutManager.class).askControlType(sName); 583 if ((InstanceManager.getDefault(TurnoutManager.class).isControlTypeSupported(sName)) && (rangeBox.isSelected())) { 584 if (JmriJOptionPane.showConfirmDialog(addFrame, 585 Bundle.getMessage("UseForAllTurnouts"), Bundle.getMessage("UseSetting"), 586 JmriJOptionPane.YES_NO_OPTION) == JmriJOptionPane.YES_OPTION ) // Add a pop up here asking if the uName wishes to use the same value for all 587 { 588 useLastType = true; 589 } 590 } 591 } 592 t.setControlType(iType); 593 594 // add first and last names to statusMessage uName feedback string 595 if (x == 0 || x == numberOfTurnouts - 1) { 596 statusMessage.append(" ").append(sName).append(" (").append(uName).append(")"); 597 } 598 if (x == numberOfTurnouts - 2) { 599 statusMessage.append(" ").append(Bundle.getMessage("ItemCreateUpTo")).append(" "); 600 } 601 // only mention first and last of rangeBox added 602 } 603 604 // except on last pass 605 if (x < numberOfTurnouts-1) { 606 // bump system name 607 try { 608 sName = InstanceManager.getDefault(TurnoutManager.class).getNextValidSystemName(t); 609 } catch (jmri.JmriException ex) { 610 displayHwError(curAddress, ex); 611 // directly add to statusBarLabel (but never called?) 612 statusBarLabel.setText(Bundle.getMessage("ErrorConvertHW", curAddress)); 613 statusBarLabel.setForeground(Color.red); 614 return; 615 } 616 617 // bump user name 618 if ((uName != null) && !uName.isEmpty()) { 619 uName = nextName(uName); 620 } 621 } 622 // end of for loop creating rangeBox of Turnouts 623 } 624 625 // provide successfeedback to uName 626 statusBarLabel.setText(statusMessage.toString()); 627 statusBarLabel.setForeground(Color.gray); 628 629 pref.setComboBoxLastSelection(systemSelectionCombo, prefixBox.getSelectedItem().getMemo().getUserName()); // store user pref 630 removePrefixBoxListener(prefixBox); 631 addFrame.setVisible(false); 632 addFrame.dispose(); 633 addFrame = null; 634 } 635 636 private String addEntryToolTip; 637 638 /** 639 * Activate Add a rangeBox option if manager accepts adding more than 1 640 * Turnout and set a manager specific tooltip on the AddNewHardwareDevice 641 * pane. 642 */ 643 private void canAddRange(ActionEvent e) { 644 rangeBox.setEnabled(false); 645 log.debug("T Add box disabled"); 646 rangeBox.setSelected(false); 647 if (prefixBox.getSelectedIndex() == -1) { 648 prefixBox.setSelectedIndex(0); 649 } 650 Manager<Turnout> manager = prefixBox.getSelectedItem(); 651 assert manager != null; 652 String systemPrefix = manager.getSystemPrefix(); 653 rangeBox.setEnabled(((TurnoutManager) manager).allowMultipleAdditions(systemPrefix)); 654 addEntryToolTip = manager.getEntryToolTip(); 655 // show sysName (HW address) field tooltip in the Add Turnout pane that matches system connection selected from combobox 656 hardwareAddressTextField.setToolTipText( 657 Bundle.getMessage("AddEntryToolTipLine1", 658 manager.getMemo().getUserName(), 659 Bundle.getMessage("Turnouts"), 660 addEntryToolTip)); 661 hardwareAddressValidator.setToolTipText(hardwareAddressTextField.getToolTipText()); 662 hardwareAddressValidator.verify(hardwareAddressTextField); 663 } 664 665 void handleCreateException(Exception ex, String sysName) { 666 String err = Bundle.getMessage("ErrorBeanCreateFailed", 667 InstanceManager.getDefault(TurnoutManager.class).getBeanTypeHandled(),sysName); 668 if (ex.getMessage() != null) { 669 statusBarLabel.setText(ex.getLocalizedMessage()); 670 JmriJOptionPane.showMessageDialog(addFrame, 671 ex.getLocalizedMessage(), 672 err, 673 JmriJOptionPane.ERROR_MESSAGE); 674 } else { 675 statusBarLabel.setText(Bundle.getMessage("WarningInvalidRange")); 676 JmriJOptionPane.showMessageDialog(addFrame, 677 err + "\n" + Bundle.getMessage("ErrorAddFailedCheck"), 678 err, 679 JmriJOptionPane.ERROR_MESSAGE); 680 } 681 statusBarLabel.setForeground(Color.red); 682 } 683 684 private boolean noWarn = false; 685 686 /** 687 * {@inheritDoc} 688 */ 689 @Override 690 protected String getClassName() { 691 return TurnoutTableAction.class.getName(); 692 } 693 694 /** 695 * {@inheritDoc} 696 */ 697 @Override 698 public void setMessagePreferencesDetails() { 699 jmri.InstanceManager.getDefault(jmri.UserPreferencesManager.class) 700 .setPreferenceItemDetails(getClassName(), "duplicateUserName", Bundle.getMessage("DuplicateUserNameWarn")); 701 super.setMessagePreferencesDetails(); 702 } 703 704 /** 705 * {@inheritDoc} 706 */ 707 @Override 708 public String getClassDescription() { 709 return Bundle.getMessage("TitleTurnoutTable"); 710 } 711 712 private final static org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(TurnoutTableAction.class); 713 714}