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 // show the type the turnout's own copy was made from, else the first type as before 207 TurnoutOperation definitive = turnOp.getDefinitive(); 208 int index = (definitive != null) ? strings.indexOf(definitive.getName()) : -1; 209 cb.setSelectedIndex(index > 1 ? index : 2); 210 } else { 211 cb.setSelectedItem(turnOp.getName()); 212 } 213 } 214 } 215 // Set custom renderer with tooltips 216 cb.setRenderer(new DefaultListCellRenderer() { 217 @Override 218 public Component getListCellRendererComponent(JList<?> list, Object value, 219 int index, boolean isSelected, boolean cellHasFocus) { 220 JLabel lbl = (JLabel)super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus); 221 if (value != null) { 222 lbl.setToolTipText(InstanceManager.getDefault(TurnoutOperationManager.class) 223 .getTooltipForOperator(value.toString(), t)); 224 } 225 return lbl; 226 } 227 }); 228 } 229 230 /** 231 * Show a pane to configure closed and thrown turnout speed defaults. 232 * 233 * @param _who parent JFrame to center the pane on 234 */ 235 protected void setDefaultSpeeds(JFrame _who) { 236 JComboBox<String> thrownCombo = new JComboBox<>((( TurnoutTableDataModel)m).speedListThrown); 237 JComboBox<String> closedCombo = new JComboBox<>((( TurnoutTableDataModel)m).speedListClosed); 238 thrownCombo.setEditable(true); 239 closedCombo.setEditable(true); 240 241 JComboBoxUtil.setupComboBoxMaxRows(thrownCombo); 242 JComboBoxUtil.setupComboBoxMaxRows(closedCombo); 243 244 JPanel thrown = new JPanel(); 245 thrown.add(new JLabel(Bundle.getMessage("MakeLabel", Bundle.getMessage("ThrownSpeed")))); 246 thrown.add(thrownCombo); 247 248 JPanel closed = new JPanel(); 249 closed.add(new JLabel(Bundle.getMessage("MakeLabel", Bundle.getMessage("ClosedSpeed")))); 250 closed.add(closedCombo); 251 252 thrownCombo.removeItem((( TurnoutTableDataModel)m).defaultThrownSpeedText); 253 closedCombo.removeItem((( TurnoutTableDataModel)m).defaultClosedSpeedText); 254 255 thrownCombo.setSelectedItem(turnoutManager.getDefaultThrownSpeed()); 256 closedCombo.setSelectedItem(turnoutManager.getDefaultClosedSpeed()); 257 258 // block of options above row of buttons; gleaned from Maintenance.makeDialog() 259 // can be accessed by Jemmy in GUI test 260 String title = Bundle.getMessage("TurnoutGlobalSpeedMessageTitle"); 261 // build JPanel for comboboxes 262 JPanel speedspanel = new JPanel(); 263 speedspanel.setLayout(new BoxLayout(speedspanel, BoxLayout.PAGE_AXIS)); 264 speedspanel.add(new JLabel(Bundle.getMessage("TurnoutGlobalSpeedMessage"))); 265 //default LEFT_ALIGNMENT 266 thrown.setAlignmentX(Component.LEFT_ALIGNMENT); 267 speedspanel.add(thrown); 268 closed.setAlignmentX(Component.LEFT_ALIGNMENT); 269 speedspanel.add(closed); 270 271 int retval = JmriJOptionPane.showConfirmDialog(_who, 272 speedspanel, 273 title, 274 JmriJOptionPane.OK_CANCEL_OPTION, 275 JmriJOptionPane.INFORMATION_MESSAGE); 276 log.debug("Retval = {}", retval); 277 if (retval != JmriJOptionPane.OK_OPTION) { // OK button not clicked 278 return; 279 } 280 String closedValue = (String) closedCombo.getSelectedItem(); 281 String thrownValue = (String) thrownCombo.getSelectedItem(); 282 283 // We will allow the turnout manager to handle checking whether the values have changed 284 try { 285 assert thrownValue != null; 286 turnoutManager.setDefaultThrownSpeed(thrownValue); 287 } catch (jmri.JmriException ex) { 288 JmriJOptionPane.showMessageDialog(null, ex.getMessage() + "\n" + thrownValue); 289 } 290 291 try { 292 assert closedValue != null; 293 turnoutManager.setDefaultClosedSpeed(closedValue); 294 } catch (jmri.JmriException ex) { 295 JmriJOptionPane.showMessageDialog(null, ex.getMessage() + "\n" + closedValue); 296 } 297 } 298 299 private final JCheckBox doAutomationBox = new JCheckBox(Bundle.getMessage("AutomaticRetry")); 300 private final TriStateJCheckBox showFeedbackBox = new TriStateJCheckBox(Bundle.getMessage("ShowFeedbackInfo")); 301 private final TriStateJCheckBox showLockBox = new TriStateJCheckBox(Bundle.getMessage("ShowLockInfo")); 302 private final TriStateJCheckBox showTurnoutSpeedBox = new TriStateJCheckBox(Bundle.getMessage("ShowTurnoutSpeedDetails")); 303 private final TriStateJCheckBox showStateForgetAndQueryBox = new TriStateJCheckBox(Bundle.getMessage("ShowStateForgetAndQuery")); 304 305 private void initCheckBoxes(){ 306 doAutomationBox.setSelected(InstanceManager.getDefault(TurnoutOperationManager.class).getDoOperations()); 307 doAutomationBox.setToolTipText(Bundle.getMessage("TurnoutDoAutomationBoxTooltip")); 308 doAutomationBox.addActionListener(e -> InstanceManager.getDefault(TurnoutOperationManager.class).setDoOperations(doAutomationBox.isSelected())); 309 310 showFeedbackBox.setToolTipText(Bundle.getMessage("TurnoutFeedbackToolTip")); 311 showLockBox.setToolTipText(Bundle.getMessage("TurnoutLockToolTip")); 312 showTurnoutSpeedBox.setToolTipText(Bundle.getMessage("TurnoutSpeedToolTip")); 313 showStateForgetAndQueryBox.setToolTipText(Bundle.getMessage("StateForgetAndQueryBoxToolTip")); 314 } 315 316 @Override 317 protected void configureTable(JTable table){ 318 super.configureTable(table); 319 showStateForgetAndQueryBox.addActionListener(e -> 320 ((TurnoutTableDataModel) m).showStateForgetAndQueryChanged(showStateForgetAndQueryBox.isSelected(),table)); 321 showTurnoutSpeedBox.addActionListener(e -> 322 ((TurnoutTableDataModel) m).showTurnoutSpeedChanged(showTurnoutSpeedBox.isSelected(),table)); 323 showFeedbackBox.addActionListener(e -> 324 ((TurnoutTableDataModel) m).showFeedbackChanged(showFeedbackBox.isSelected(), table)); 325 showLockBox.addActionListener(e -> 326 ((TurnoutTableDataModel) m).showLockChanged(showLockBox.isSelected(),table)); 327 } 328 329 /** 330 * Add the check boxes to show/hide extra columns to the Turnout table 331 * frame. 332 * <p> 333 * Keep contents synchronized with 334 * {@link #addToPanel(AbstractTableTabAction)} 335 * 336 * @param f a Turnout table frame 337 */ 338 @Override 339 public void addToFrame(BeanTableFrame<Turnout> f) { 340 initCheckBoxes(); 341 f.addToBottomBox(doAutomationBox, this.getClass().getName()); 342 f.addToBottomBox(showFeedbackBox, this.getClass().getName()); 343 f.addToBottomBox(showLockBox, this.getClass().getName()); 344 f.addToBottomBox(showTurnoutSpeedBox, this.getClass().getName()); 345 f.addToBottomBox(showStateForgetAndQueryBox, this.getClass().getName()); 346 } 347 348 /** 349 * Place the check boxes to show/hide extra columns to the tabbed Turnout 350 * table panel. 351 * <p> 352 * Keep contents synchronized with {@link #addToFrame(BeanTableFrame)} 353 * 354 * @param f a Turnout table action 355 */ 356 @Override 357 public void addToPanel(AbstractTableTabAction<Turnout> f) { 358 String connectionName = turnoutManager.getMemo().getUserName(); 359 if (turnoutManager.getClass().getName().contains("ProxyTurnoutManager")) { 360 connectionName = "All"; // NOI18N 361 } 362 initCheckBoxes(); 363 f.addToBottomBox(doAutomationBox, connectionName); 364 f.addToBottomBox(showFeedbackBox, connectionName); 365 f.addToBottomBox(showLockBox, connectionName); 366 f.addToBottomBox(showTurnoutSpeedBox, connectionName); 367 f.addToBottomBox(showStateForgetAndQueryBox, connectionName); 368 } 369 370 /** 371 * Override to update column select checkboxes. 372 * {@inheritDoc} 373 */ 374 @Override 375 protected void columnsVisibleUpdated(boolean[] colsVisible){ 376 log.debug("columns updated {}",colsVisible); 377 showFeedbackBox.setState(new boolean[]{ 378 colsVisible[TurnoutTableDataModel.KNOWNCOL], 379 colsVisible[TurnoutTableDataModel.MODECOL], 380 colsVisible[TurnoutTableDataModel.SENSOR1COL], 381 colsVisible[TurnoutTableDataModel.SENSOR2COL], 382 colsVisible[TurnoutTableDataModel.OPSONOFFCOL], 383 colsVisible[TurnoutTableDataModel.OPSEDITCOL]}); 384 385 showLockBox.setState(new boolean[]{ 386 colsVisible[TurnoutTableDataModel.LOCKDECCOL], 387 colsVisible[TurnoutTableDataModel.LOCKOPRCOL]}); 388 389 showTurnoutSpeedBox.setState(new boolean[]{ 390 colsVisible[TurnoutTableDataModel.STRAIGHTCOL], 391 colsVisible[TurnoutTableDataModel.DIVERGCOL]}); 392 393 showStateForgetAndQueryBox.setState(new boolean[]{ 394 colsVisible[TurnoutTableDataModel.FORGETCOL], 395 colsVisible[TurnoutTableDataModel.QUERYCOL]}); 396 397 } 398 399 /** 400 * Insert table specific Automation and Speeds menus. Account for the Window and Help 401 * menus, which are already added to the menu bar as part of the creation of 402 * the JFrame, by adding the Automation menu 2 places earlier unless the 403 * table is part of the ListedTableFrame, that adds the Help menu later on. 404 * 405 * @param f the JFrame of this table 406 */ 407 @Override 408 public void setMenuBar(BeanTableFrame<Turnout> f) { 409 final jmri.util.JmriJFrame finalF = f; // needed for anonymous ActionListener class 410 JMenuBar menuBar = f.getJMenuBar(); 411 // check for menu 412 boolean menuAbsent = true; 413 for (int i = 0; i < menuBar.getMenuCount(); ++i) { 414 String name = menuBar.getMenu(i).getAccessibleContext().getAccessibleName(); 415 if (name.equals(Bundle.getMessage("TurnoutAutomationMenu"))) { 416 // using first menu for check, should be identical to next JMenu Bundle 417 menuAbsent = false; 418 break; 419 } 420 } 421 if (menuAbsent) { // create it 422 int pos = menuBar.getMenuCount() - 1; // count the number of menus to insert the TableMenu before 'Window' and 'Help' 423 int offset = 1; 424 log.debug("setMenuBar number of menu items = {}", pos); 425 for (int i = 0; i <= pos; i++) { 426 if (menuBar.getComponent(i) instanceof JMenu) { 427 if (((JMenu) menuBar.getComponent(i)).getText().equals(Bundle.getMessage("MenuHelp"))) { 428 offset = -1; // correct for use as part of ListedTableAction where the Help Menu is not yet present 429 } 430 } 431 } 432 JMenu opsMenu = new JMenu(Bundle.getMessage("TurnoutAutomationMenu")); 433 JMenuItem item = new JMenuItem(Bundle.getMessage("TurnoutAutomationMenuItemEdit")); 434 opsMenu.add(item); 435 item.addActionListener(e -> new TurnoutOperationFrame(finalF)); 436 menuBar.add(opsMenu, pos + offset); 437 438 JMenu speedMenu = new JMenu(Bundle.getMessage("SpeedsMenu")); 439 item = new JMenuItem(Bundle.getMessage("SpeedsMenuItemDefaults")); 440 speedMenu.add(item); 441 item.addActionListener(e -> setDefaultSpeeds(finalF)); 442 menuBar.add(speedMenu, pos + offset + 1); // add this menu to the right of the previous 443 } 444 } 445 446 void cancelPressed(ActionEvent e) { 447 removePrefixBoxListener(prefixBox); 448 addFrame.setVisible(false); 449 addFrame.dispose(); 450 addFrame = null; 451 } 452 453 /** 454 * Respond to Create new item button pressed on Add Turnout pane. 455 * 456 * @param e the click event 457 */ 458 void createPressed(ActionEvent e) { 459 460 int numberOfTurnouts = 1; 461 462 if (rangeBox.isSelected()) { 463 numberOfTurnouts = (Integer) numberToAddSpinner.getValue(); 464 } 465 if (numberOfTurnouts >= 65 // limited by JSpinnerModel to 100 466 && JmriJOptionPane.showConfirmDialog(addFrame, 467 Bundle.getMessage("WarnExcessBeans", Bundle.getMessage("Turnouts"), numberOfTurnouts), 468 Bundle.getMessage("WarningTitle"), 469 JmriJOptionPane.YES_NO_OPTION) != JmriJOptionPane.YES_OPTION ) { 470 return; 471 } 472 473 String sName; 474 String prefix = Objects.requireNonNull(prefixBox.getSelectedItem()).getSystemPrefix(); 475 476 String curAddress = hardwareAddressTextField.getText(); 477 // initial check for empty entry 478 if (curAddress.length() < 1) { 479 statusBarLabel.setText(Bundle.getMessage("WarningEmptyHardwareAddress")); 480 statusBarLabel.setForeground(Color.red); 481 hardwareAddressTextField.setBackground(Color.red); 482 return; 483 } else { 484 hardwareAddressTextField.setBackground(Color.white); 485 } 486 487 String uName = userNameTextField.getText(); 488 if (uName.isEmpty()) { 489 uName = null; 490 } 491 492 // Add some entry pattern checking, before assembling sName and handing it to the TurnoutManager 493 StringBuilder statusMessage = new StringBuilder(Bundle.getMessage("ItemCreateFeedback", Bundle.getMessage("BeanNameTurnout"))); 494 495 // Compose the proposed system name from parts: 496 sName = prefix + InstanceManager.getDefault(TurnoutManager.class).typeLetter() + curAddress; 497 498 int iType = 0; 499 int iNum = 1; 500 boolean useLastBit = false; 501 boolean useLastType = false; 502 503 for (int x = 0; x < numberOfTurnouts; x++) { 504 505 Turnout t; 506 507 // test for a Light by the same hardware address (number): 508 // String testSN = prefix + "L" + curAddress; <========= from sName instead 509 StringBuilder sb = new StringBuilder(sName); 510 int prefixLength = Manager.getSystemPrefixLength(sName); 511 sb.replace(prefixLength, prefixLength+1, "L"); 512 String testSN = new String(sb); 513 log.trace("{} maps to {}", sName, testSN); 514 515 jmri.Light testLight = InstanceManager.lightManagerInstance(). 516 getBySystemName(testSN); 517 if (testLight != null) { 518 // Address (number part) is already used as a Light 519 log.warn("Requested Turnout {} uses same address as Light {}", sName, testSN); 520 if (!noWarn) { 521 int selectedValue = JmriJOptionPane.showOptionDialog(addFrame, 522 Bundle.getMessage("TurnoutWarn1", sName, testSN) 523 + ".\n" + Bundle.getMessage("TurnoutWarn3"), Bundle.getMessage("WarningTitle"), 524 JmriJOptionPane.YES_NO_CANCEL_OPTION, JmriJOptionPane.QUESTION_MESSAGE, null, 525 new Object[]{Bundle.getMessage("ButtonYes"), Bundle.getMessage("ButtonNo"), 526 Bundle.getMessage("ButtonYesPlus")}, Bundle.getMessage("ButtonNo")); // default choice = No 527 if (selectedValue == 1) { // ButtonNo 528 // Show error message in statusBarLabel 529 statusBarLabel.setText(Bundle.getMessage("WarningOverlappingAddress", sName)); 530 statusBarLabel.setForeground(Color.gray); 531 return; // return without creating if "No" response 532 } 533 if (selectedValue == 2) { // ButtonYesPlus 534 // Suppress future warnings, and continue 535 noWarn = true; 536 } 537 } 538 } 539 540 // Ask about two bit turnout control if appropriate 541 if (!useLastBit) { 542 iNum = InstanceManager.getDefault(TurnoutManager.class).askNumControlBits(sName); 543 if ((InstanceManager.getDefault(TurnoutManager.class).isNumControlBitsSupported(sName)) && (rangeBox.isSelected())) { 544 // Add a pop up here asking if the user wishes to use the same value for all 545 if (JmriJOptionPane.showConfirmDialog(addFrame, 546 Bundle.getMessage("UseForAllTurnouts"), Bundle.getMessage("UseSetting"), 547 JmriJOptionPane.YES_NO_OPTION) == 0) { 548 useLastBit = true; 549 } 550 } else { 551 // as isNumControlBits is not supported, we will always use the same value. 552 useLastBit = true; 553 } 554 } 555 if (iNum == 0) { 556 // User specified more bits, but bits are not available - return without creating 557 // Display message in statusBarLabel 558 statusBarLabel.setText(Bundle.getMessage("WarningBitsNotSupported", sName)); 559 statusBarLabel.setForeground(Color.red); 560 return; 561 } else { 562 563 // Create the new turnout 564 try { 565 t = InstanceManager.getDefault(TurnoutManager.class).provideTurnout(sName); 566 } catch (IllegalArgumentException ex) { 567 // user input no good 568 handleCreateException(ex, sName); // displays message dialog to the user 569 return; // without creating 570 } 571 if ((uName != null) && !uName.isEmpty()) { 572 if (InstanceManager.getDefault(TurnoutManager.class).getByUserName(uName) == null) { 573 t.setUserName(uName); 574 } else if (!pref.getPreferenceState(getClassName(), "duplicateUserName")) { 575 InstanceManager.getDefault(jmri.UserPreferencesManager.class). 576 showErrorMessage(Bundle.getMessage("ErrorTitle"), 577 Bundle.getMessage("ErrorDuplicateUserName", uName), 578 getClassName(), "duplicateUserName", false, true); 579 } 580 } 581 582 t.setNumberControlBits(iNum); 583 // Ask about the type of turnout control if appropriate 584 if (!useLastType) { 585 iType = InstanceManager.getDefault(TurnoutManager.class).askControlType(sName); 586 if ((InstanceManager.getDefault(TurnoutManager.class).isControlTypeSupported(sName)) && (rangeBox.isSelected())) { 587 if (JmriJOptionPane.showConfirmDialog(addFrame, 588 Bundle.getMessage("UseForAllTurnouts"), Bundle.getMessage("UseSetting"), 589 JmriJOptionPane.YES_NO_OPTION) == JmriJOptionPane.YES_OPTION ) // Add a pop up here asking if the uName wishes to use the same value for all 590 { 591 useLastType = true; 592 } 593 } 594 } 595 t.setControlType(iType); 596 597 // add first and last names to statusMessage uName feedback string 598 if (x == 0 || x == numberOfTurnouts - 1) { 599 statusMessage.append(" ").append(sName).append(" (").append(uName).append(")"); 600 } 601 if (x == numberOfTurnouts - 2) { 602 statusMessage.append(" ").append(Bundle.getMessage("ItemCreateUpTo")).append(" "); 603 } 604 // only mention first and last of rangeBox added 605 } 606 607 // except on last pass 608 if (x < numberOfTurnouts-1) { 609 // bump system name 610 try { 611 sName = InstanceManager.getDefault(TurnoutManager.class).getNextValidSystemName(t); 612 } catch (jmri.JmriException ex) { 613 displayHwError(curAddress, ex); 614 // directly add to statusBarLabel (but never called?) 615 statusBarLabel.setText(Bundle.getMessage("ErrorConvertHW", curAddress)); 616 statusBarLabel.setForeground(Color.red); 617 return; 618 } 619 620 // bump user name 621 if ((uName != null) && !uName.isEmpty()) { 622 uName = nextName(uName); 623 } 624 } 625 // end of for loop creating rangeBox of Turnouts 626 } 627 628 // provide successfeedback to uName 629 statusBarLabel.setText(statusMessage.toString()); 630 statusBarLabel.setForeground(Color.gray); 631 632 pref.setComboBoxLastSelection(systemSelectionCombo, prefixBox.getSelectedItem().getMemo().getUserName()); // store user pref 633 removePrefixBoxListener(prefixBox); 634 addFrame.setVisible(false); 635 addFrame.dispose(); 636 addFrame = null; 637 } 638 639 private String addEntryToolTip; 640 641 /** 642 * Activate Add a rangeBox option if manager accepts adding more than 1 643 * Turnout and set a manager specific tooltip on the AddNewHardwareDevice 644 * pane. 645 */ 646 private void canAddRange(ActionEvent e) { 647 rangeBox.setEnabled(false); 648 log.debug("T Add box disabled"); 649 rangeBox.setSelected(false); 650 if (prefixBox.getSelectedIndex() == -1) { 651 prefixBox.setSelectedIndex(0); 652 } 653 Manager<Turnout> manager = prefixBox.getSelectedItem(); 654 assert manager != null; 655 String systemPrefix = manager.getSystemPrefix(); 656 rangeBox.setEnabled(((TurnoutManager) manager).allowMultipleAdditions(systemPrefix)); 657 addEntryToolTip = manager.getEntryToolTip(); 658 // show sysName (HW address) field tooltip in the Add Turnout pane that matches system connection selected from combobox 659 hardwareAddressTextField.setToolTipText( 660 Bundle.getMessage("AddEntryToolTipLine1", 661 manager.getMemo().getUserName(), 662 Bundle.getMessage("Turnouts"), 663 addEntryToolTip)); 664 hardwareAddressValidator.setToolTipText(hardwareAddressTextField.getToolTipText()); 665 hardwareAddressValidator.verify(hardwareAddressTextField); 666 } 667 668 void handleCreateException(Exception ex, String sysName) { 669 String err = Bundle.getMessage("ErrorBeanCreateFailed", 670 InstanceManager.getDefault(TurnoutManager.class).getBeanTypeHandled(),sysName); 671 if (ex.getMessage() != null) { 672 statusBarLabel.setText(ex.getLocalizedMessage()); 673 JmriJOptionPane.showMessageDialog(addFrame, 674 ex.getLocalizedMessage(), 675 err, 676 JmriJOptionPane.ERROR_MESSAGE); 677 } else { 678 statusBarLabel.setText(Bundle.getMessage("WarningInvalidRange")); 679 JmriJOptionPane.showMessageDialog(addFrame, 680 err + "\n" + Bundle.getMessage("ErrorAddFailedCheck"), 681 err, 682 JmriJOptionPane.ERROR_MESSAGE); 683 } 684 statusBarLabel.setForeground(Color.red); 685 } 686 687 private boolean noWarn = false; 688 689 /** 690 * {@inheritDoc} 691 */ 692 @Override 693 protected String getClassName() { 694 return TurnoutTableAction.class.getName(); 695 } 696 697 /** 698 * {@inheritDoc} 699 */ 700 @Override 701 public void setMessagePreferencesDetails() { 702 jmri.InstanceManager.getDefault(jmri.UserPreferencesManager.class) 703 .setPreferenceItemDetails(getClassName(), "duplicateUserName", Bundle.getMessage("DuplicateUserNameWarn")); 704 super.setMessagePreferencesDetails(); 705 } 706 707 /** 708 * {@inheritDoc} 709 */ 710 @Override 711 public String getClassDescription() { 712 return Bundle.getMessage("TitleTurnoutTable"); 713 } 714 715 private static final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(TurnoutTableAction.class); 716 717}