001package jmri.jmrit.beantable.beanedit; 002 003import java.awt.Component; 004import java.awt.event.ActionEvent; 005import java.awt.event.ActionListener; 006import javax.swing.AbstractAction; 007import javax.swing.JCheckBox; 008import javax.swing.JComboBox; 009import javax.swing.JPanel; 010import javax.swing.JTextField; 011import jmri.InstanceManager; 012import jmri.Sensor; 013import jmri.Turnout; 014import jmri.TurnoutOperation; 015import jmri.TurnoutOperationManager; 016import jmri.NamedBean.DisplayOptions; 017import jmri.implementation.SignalSpeedMap; 018import jmri.util.swing.JComboBoxUtil; 019import jmri.jmrit.turnoutoperations.TurnoutOperationConfig; 020import jmri.swing.NamedBeanComboBox; 021import jmri.util.swing.JmriJOptionPane; 022 023/** 024 * Provides an edit panel for a turnout object. 025 * 026 * @author Kevin Dickerson Copyright (C) 2011 027 */ 028public class TurnoutEditAction extends BeanEditAction<Turnout> { 029 @Override 030 public String helpTarget() { 031 return "package.jmri.jmrit.beantable.TurnoutAddEdit"; 032 } // NOI18N 033 034 @Override 035 public void actionPerformed(ActionEvent e) { 036 oldAutomationSelection = bean.getTurnoutOperation(); 037 oldModeSelection = bean.getFeedbackModeName(); 038 super.actionPerformed(e); 039 } 040 041 @Override 042 protected void initPanels() { 043 super.initPanels(); 044 feedback(); 045 lock(); 046 speed(); 047 } 048 049 @Override 050 public Turnout getByUserName(String name) { 051 return InstanceManager.turnoutManagerInstance().getByUserName(name); 052 } 053 054 private JCheckBox inverted = new JCheckBox(); 055 056 @Override 057 protected BeanItemPanel basicDetails() { 058 BeanItemPanel basic = super.basicDetails(); 059 basic.addItem(new BeanEditItem(inverted, Bundle.getMessage("Inverted"), 060 Bundle.getMessage("InvertedToolTip"))); 061 return basic; 062 } 063 064 @Override 065 protected void saveBasicItems(ActionEvent e) { 066 super.saveBasicItems(e); 067 Turnout turn = bean; 068 turn.setInverted(inverted.isSelected()); 069 } 070 071 @Override 072 protected void resetBasicItems(ActionEvent e) { 073 super.resetBasicItems(e); 074 Turnout turn = bean; 075 if (turn.canInvert()) { 076 inverted.setSelected(turn.getInverted()); 077 } 078 inverted.setEnabled(turn.canInvert()); 079 } 080 081 private NamedBeanComboBox<Sensor> sensorFeedBack1ComboBox; 082 private NamedBeanComboBox<Sensor> sensorFeedBack2ComboBox; 083 private JComboBox<String> modeBox; 084 private JComboBox<String> automationBox; 085 private String useBlockSpeed = Bundle.getMessage("UseGlobal", "Block Speed"); 086 private TurnoutOperationConfig config; 087 private BeanItemPanel feedback; 088 private final JPanel turnoutOperation = new JPanel(); 089 090 private BeanItemPanel feedback() { 091 feedback = new BeanItemPanel(); 092 feedback.setName(Bundle.getMessage("Feedback")); 093 094 modeBox = new JComboBox<>(bean.getValidFeedbackNames()); 095 modeBox.setMaximumRowCount(modeBox.getItemCount()); 096 oldModeSelection = bean.getFeedbackModeName(); 097 modeBox.setSelectedItem(oldModeSelection); 098 modeBox.addActionListener((ActionEvent e) -> { 099 updateFeedbackOptions(); 100 }); 101 102 feedback.addItem(new BeanEditItem(null, null, Bundle.getMessage("FeedbackToolTip"))); 103 feedback.addItem(new BeanEditItem(modeBox, Bundle.getMessage("FeedbackMode"), 104 Bundle.getMessage("FeedbackModeToolTip"))); 105 106 sensorFeedBack1ComboBox = new NamedBeanComboBox<>( 107 InstanceManager.sensorManagerInstance(), 108 bean.getFirstSensor(), 109 DisplayOptions.DISPLAYNAME); 110 sensorFeedBack1ComboBox.setAllowNull(true); 111 JComboBoxUtil.setupComboBoxMaxRows(sensorFeedBack1ComboBox); 112 feedback.addItem(new BeanEditItem(sensorFeedBack1ComboBox, 113 Bundle.getMessage("FeedbackSensor1"), 114 Bundle.getMessage("FeedbackSensorToolTip"))); 115 116 sensorFeedBack2ComboBox = new NamedBeanComboBox<>( 117 InstanceManager.sensorManagerInstance(), 118 bean.getSecondSensor(), 119 DisplayOptions.DISPLAYNAME); 120 sensorFeedBack2ComboBox.setAllowNull(true); 121 JComboBoxUtil.setupComboBoxMaxRows(sensorFeedBack2ComboBox); 122 feedback.addItem(new BeanEditItem(sensorFeedBack2ComboBox, 123 Bundle.getMessage("FeedbackSensor2"), 124 Bundle.getMessage("FeedbackSensorToolTip"))); 125 126 String[] str = new String[]{"empty"}; 127 automationBox = new JComboBox<>(str); 128 feedback.addItem(new BeanEditItem(automationBox, 129 Bundle.getMessage("TurnoutAutomation"), 130 Bundle.getMessage("TurnoutAutomationToolTip"))); 131 132 oldAutomationSelection = bean.getTurnoutOperation(); 133 if (oldAutomationSelection != null) { 134 config = TurnoutOperationConfig.getConfigPanel(oldAutomationSelection); 135 } else { 136 config = TurnoutOperationConfig.getConfigPanel(new jmri.RawTurnoutOperation()); 137 config.setEnabled(false); 138 for (Component j : config.getComponents()) { 139 j.setEnabled(false); 140 } 141 } 142 143 turnoutOperation.add(config); 144 feedback.addItem(new BeanEditItem(turnoutOperation, 145 Bundle.getMessage("FeedbackOperation"), 146 Bundle.getMessage("FeedbackOperationToolTip"))); 147 feedback.addItem(new BeanEditItem(operationsName, 148 Bundle.getMessage("FeedbackNameSet"), 149 Bundle.getMessage("FeedbackNameSetToolTip"))); 150 151 feedback.setSaveItem(new AbstractAction() { 152 @Override 153 public void actionPerformed(ActionEvent e) { 154 String modeName = (String) modeBox.getSelectedItem(); 155 if (modeName != null) { 156 bean.setFeedbackMode(modeName); 157 } 158 String newName = operationsName.getText(); 159 if ((currentOperation != null) && (newName != null) && !newName.isEmpty()) { 160 if (!currentOperation.rename(newName)) { 161 JmriJOptionPane.showMessageDialog(turnoutOperation, 162 Bundle.getMessage("ErrorDuplicateUserName", newName), 163 Bundle.getMessage("ErrorTitle"), 164 JmriJOptionPane.ERROR_MESSAGE); 165 } else { 166 automationBox.removeActionListener(automationSelectionListener); 167 automationBox.addItem(newName); 168 automationBox.setSelectedItem(newName); 169 automationBox.addActionListener(automationSelectionListener); 170 } 171 bean.setTurnoutOperation(null); 172 bean.setTurnoutOperation(currentOperation); 173 } 174 config.endConfigure(); 175 switch (automationBox.getSelectedIndex()) { 176 case 0: // Off 177 bean.setInhibitOperation(true); 178 bean.setTurnoutOperation(null); 179 break; 180 case 1: // Default 181 bean.setInhibitOperation(false); 182 bean.setTurnoutOperation(null); 183 break; 184 default: // named operation 185 bean.setInhibitOperation(false); 186 String autoMode = (String) automationBox.getSelectedItem(); 187 if (autoMode != null) { 188 TurnoutOperation selectedOp = InstanceManager.getDefault(TurnoutOperationManager.class). 189 getOperation((autoMode)); 190 if (currentOperation != null && currentOperation.isNonce() && !currentOperation.equivalentTo(selectedOp)) { 191 // attach the private copy holding the edited values 192 bean.setTurnoutOperation(currentOperation); 193 } else { 194 bean.setTurnoutOperation(selectedOp); 195 } 196 } 197 break; 198 } 199 oldAutomationSelection = bean.getTurnoutOperation(); 200 oldModeSelection = bean.getFeedbackModeName(); 201 try { 202 bean.provideFirstFeedbackSensor(sensorFeedBack1ComboBox.getSelectedItemDisplayName()); 203 } catch (jmri.JmriException ex) { 204 JmriJOptionPane.showMessageDialog(turnoutOperation, ex.toString()); 205 } 206 try { 207 bean.provideSecondFeedbackSensor(sensorFeedBack2ComboBox.getSelectedItemDisplayName()); 208 } catch (jmri.JmriException ex) { 209 JmriJOptionPane.showMessageDialog(turnoutOperation, ex.toString()); 210 } 211 } 212 }); 213 214 feedback.setResetItem(new AbstractAction() { 215 @Override 216 public void actionPerformed(ActionEvent e) { 217 sensorFeedBack1ComboBox.setSelectedItem(bean.getFirstSensor()); 218 sensorFeedBack2ComboBox.setSelectedItem(bean.getSecondSensor()); 219 220 automationBox.removeActionListener(automationSelectionListener); 221 jmri.jmrit.beantable.TurnoutTableAction.updateAutomationBox(bean, automationBox); 222 automationBox.addActionListener(automationSelectionListener); 223 224 bean.setFeedbackMode(oldModeSelection); 225 updateFeedbackOptions(); 226 } 227 }); 228 bei.add(feedback); 229 return feedback; 230 } // feedback() 231 232 private String oldModeSelection; 233 private TurnoutOperation oldAutomationSelection; 234 private TurnoutOperation currentOperation; 235 private JTextField operationsName = new JTextField(10); 236 237 transient ActionListener automationSelectionListener = (ActionEvent e) -> { 238 updateAutomationOptions(); 239 }; 240 241 private void updateFeedbackOptions() { 242 sensorFeedBack1ComboBox.setEnabled(false); 243 sensorFeedBack2ComboBox.setEnabled(false); 244 245 String mode = (String) modeBox.getSelectedItem(); 246 if (mode != null) { 247 if (mode.equals("ONESENSOR")) { 248 sensorFeedBack1ComboBox.setEnabled(true); 249 } else if (mode.equals("TWOSENSOR")) { 250 sensorFeedBack1ComboBox.setEnabled(true); 251 sensorFeedBack2ComboBox.setEnabled(true); 252 } 253 bean.setFeedbackMode(mode); 254 } 255 256 bean.setFeedbackMode((String) modeBox.getSelectedItem()); 257 jmri.jmrit.beantable.TurnoutTableAction.updateAutomationBox(bean, automationBox); 258 } 259 260 private void updateAutomationOptions() { 261 262 currentOperation = null; 263 automationBox.removeActionListener(automationSelectionListener); 264 if (automationBox.getSelectedIndex() > 1) { 265 String autoMode = (String) automationBox.getSelectedItem(); 266 if (autoMode != null) { 267 currentOperation = InstanceManager.getDefault(TurnoutOperationManager.class). 268 getOperation((autoMode)); 269 } 270 } 271 272 if (currentOperation != null) { 273 turnoutOperation.remove(config); 274 TurnoutOperation existing = bean.getTurnoutOperation(); 275 if (existing != null && existing.isNonce() && currentOperation.equals(existing.getDefinitive())) { 276 // keep editing the turnout's own copy so its saved values show 277 currentOperation = existing; 278 } else if (!currentOperation.isNonce()) { 279 currentOperation = currentOperation.makeNonce(bean); 280 } 281 config = TurnoutOperationConfig.getConfigPanel(currentOperation); 282 operationsName.setEnabled(true); 283 config.setEnabled(true); 284 turnoutOperation.add(config); 285 feedback.revalidate(); 286 feedback.repaint(); 287 } else { 288 operationsName.setEnabled(false); 289 config.setEnabled(false); 290 for (Component j : config.getComponents()) { 291 j.setEnabled(false); 292 } 293 } 294 automationBox.addActionListener(automationSelectionListener); 295 } 296 297 @Override 298 protected void cancelButtonAction(ActionEvent e) { 299 bean.setFeedbackMode(oldModeSelection); 300 bean.setTurnoutOperation(oldAutomationSelection); 301 super.cancelButtonAction(e); 302 } 303 304 private static final String bothText = "Both"; // TODO I18N using bundle. Note: check how this property is stored/loaded 305 private static final String cabOnlyText = "Cab only"; 306 private static final String pushbutText = "Pushbutton only"; 307 private static final String noneText = "None"; 308 309 private JComboBox<String> lockBox; 310 protected BeanItemPanel lock() { 311 BeanItemPanel lock = new BeanItemPanel(); 312 lock.setName(Bundle.getMessage("Lock")); 313 314 if (bean.getPossibleLockModes() != 0) { 315 // lock operations are available, configure pane for them 316 lock.addItem(new BeanEditItem(null, null, Bundle.getMessage("LockToolTip"))); 317 318 // Vector is a JComboBox ctor; List is not 319 java.util.Vector<String> lockOperations = new java.util.Vector<>(); 320 int modes = bean.getPossibleLockModes(); 321 if (((modes & Turnout.CABLOCKOUT) != 0) 322 && ((modes & Turnout.PUSHBUTTONLOCKOUT) != 0)) { 323 lockOperations.add(bothText); 324 } 325 if ((modes & Turnout.CABLOCKOUT) != 0) { 326 lockOperations.add(cabOnlyText); 327 } 328 if ((modes & Turnout.PUSHBUTTONLOCKOUT) != 0) { 329 lockOperations.add(pushbutText); 330 } 331 lockOperations.add(noneText); 332 JComboBox<String> lockOperationBox = new JComboBox<>(lockOperations); 333 lockOperationBox.setMaximumRowCount(lockOperationBox.getItemCount()); 334 335 lock.addItem(new BeanEditItem(lockOperationBox, 336 Bundle.getMessage("LockMode"), 337 Bundle.getMessage("LockModeToolTip"))); 338 lockOperationBox.addActionListener((ActionEvent e) -> { 339 String lockOp = (String) lockOperationBox.getSelectedItem(); 340 if (lockOp != null) { 341 if (lockOp.equals(noneText)) { 342 lockBox.setEnabled(false); 343 } else { 344 lockBox.setEnabled(true); 345 } 346 } 347 }); 348 349 if ((bean.getPossibleLockModes() & Turnout.PUSHBUTTONLOCKOUT) != 0) { 350 lockBox = new JComboBox<>(bean.getValidDecoderNames()); 351 } else { 352 lockBox = new JComboBox<>(new String[]{bean.getDecoderName()}); 353 } 354 lock.addItem(new BeanEditItem(lockBox, 355 Bundle.getMessage("LockModeDecoder"), 356 Bundle.getMessage("LockModeDecoderToolTip"))); 357 358 lock.setSaveItem(new AbstractAction() { 359 @Override 360 public void actionPerformed(ActionEvent e) { 361 String lockOpName = (String) lockOperationBox.getSelectedItem(); 362 if (lockOpName != null) { 363 if (lockOpName.equals(bothText)) { 364 bean.enableLockOperation(Turnout.CABLOCKOUT 365 + Turnout.PUSHBUTTONLOCKOUT, true); 366 } 367 if (lockOpName.equals(cabOnlyText)) { 368 bean.enableLockOperation(Turnout.CABLOCKOUT, true); 369 bean.enableLockOperation(Turnout.PUSHBUTTONLOCKOUT, false); 370 } 371 if (lockOpName.equals(pushbutText)) { 372 bean.enableLockOperation(Turnout.CABLOCKOUT, false); 373 bean.enableLockOperation(Turnout.PUSHBUTTONLOCKOUT, true); 374 } 375 } 376 String decoderName = (String) lockBox.getSelectedItem(); 377 if (decoderName != null) { 378 bean.setDecoderName(decoderName); 379 } 380 } 381 }); 382 383 lock.setResetItem(new AbstractAction() { 384 @Override 385 public void actionPerformed(ActionEvent e) { 386 lockBox.setSelectedItem(bean.getDecoderName()); 387 lockBox.setEnabled(true); 388 if (bean.canLock(Turnout.CABLOCKOUT) 389 && bean.canLock(Turnout.PUSHBUTTONLOCKOUT)) { 390 lockOperationBox.setSelectedItem(bothText); 391 } else if (bean.canLock(Turnout.PUSHBUTTONLOCKOUT)) { 392 lockOperationBox.setSelectedItem(pushbutText); 393 } else if (bean.canLock(Turnout.CABLOCKOUT)) { 394 lockOperationBox.setSelectedItem(cabOnlyText); 395 } else { 396 lockOperationBox.setSelectedItem(noneText); 397 lockBox.setEnabled(false); 398 } 399 } 400 }); 401 } else { 402 // lock operations are not available for this kind of Turnout 403 lock.addItem(new BeanEditItem(null, null, Bundle.getMessage("LockModeUnavailable"))); 404 } 405 bei.add(lock); 406 return lock; 407 } // lock() 408 409 private java.util.Vector<String> speedListClosed = new java.util.Vector<>(); 410 private java.util.Vector<String> speedListThrown = new java.util.Vector<>(); 411 412 private JComboBox<String> closedSpeedBox; 413 private JComboBox<String> thrownSpeedBox; 414 private String defaultThrownSpeedText; 415 private String defaultClosedSpeedText; 416 417 protected BeanItemPanel speed() { 418 BeanItemPanel speed = new BeanItemPanel(); 419 speed.setName(Bundle.getMessage("Speed")); 420 421 speed.addItem(new BeanEditItem(null, null, Bundle.getMessage("SpeedTabToolTip"))); 422 423 defaultThrownSpeedText = (Bundle.getMessage("UseGlobal", "Global") 424 + " " + InstanceManager.turnoutManagerInstance().getDefaultThrownSpeed()); 425 defaultClosedSpeedText = (Bundle.getMessage("UseGlobal", "Global") 426 + " " + InstanceManager.turnoutManagerInstance().getDefaultClosedSpeed()); 427 428 useBlockSpeed = Bundle.getMessage("UseGlobal", "Block Speed"); 429 430 speedListClosed.add(defaultClosedSpeedText); 431 speedListThrown.add(defaultThrownSpeedText); 432 433 speedListClosed.add(useBlockSpeed); 434 speedListThrown.add(useBlockSpeed); 435 436 java.util.Vector<String> _speedMap = jmri.InstanceManager. 437 getDefault(SignalSpeedMap.class).getValidSpeedNames(); 438 for (String speedMap : _speedMap) { 439 if (!speedListClosed.contains(speedMap)) { 440 speedListClosed.add(speedMap); 441 } 442 if (!speedListThrown.contains(speedMap)) { 443 speedListThrown.add(speedMap); 444 } 445 } 446 447 closedSpeedBox = new JComboBox<>(speedListClosed); 448 closedSpeedBox.setMaximumRowCount(closedSpeedBox.getItemCount()); 449 closedSpeedBox.setEditable(true); 450 451 speed.addItem(new BeanEditItem(closedSpeedBox, 452 Bundle.getMessage("ClosedSpeed"), 453 Bundle.getMessage("ClosedSpeedToolTip"))); 454 thrownSpeedBox = new JComboBox<>(speedListThrown); 455 thrownSpeedBox.setMaximumRowCount(thrownSpeedBox.getItemCount()); 456 thrownSpeedBox.setEditable(true); 457 speed.addItem(new BeanEditItem(thrownSpeedBox, 458 Bundle.getMessage("ThrownSpeed"), 459 Bundle.getMessage("ThrownSpeedToolTip"))); 460 461 speed.setSaveItem(new AbstractAction() { 462 @Override 463 public void actionPerformed(ActionEvent e) { 464 String newSpeed = (String) closedSpeedBox.getSelectedItem(); 465 if (newSpeed != null) { 466 try { 467 bean.setStraightSpeed(newSpeed); 468 if ((!speedListClosed.contains(newSpeed)) && !newSpeed.contains("Global")) { 469 speedListClosed.add(newSpeed); 470 } 471 } catch (jmri.JmriException ex) { 472 JmriJOptionPane.showMessageDialog(speed, ex.getMessage() + "\n" + newSpeed); 473 } 474 } 475 newSpeed = (String) thrownSpeedBox.getSelectedItem(); 476 if (newSpeed != null) { 477 try { 478 bean.setDivergingSpeed(newSpeed); 479 if ((!speedListThrown.contains(newSpeed)) && !newSpeed.contains("Global")) { 480 speedListThrown.add(newSpeed); 481 } 482 } catch (jmri.JmriException ex) { 483 JmriJOptionPane.showMessageDialog(speed, ex.getMessage() + "\n" + newSpeed); 484 } 485 } 486 } 487 }); 488 489 speed.setResetItem(new AbstractAction() { 490 @Override 491 public void actionPerformed(ActionEvent e) { 492 String speed = bean.getDivergingSpeed(); 493 speedListThrown.remove(defaultThrownSpeedText); 494 defaultThrownSpeedText = (Bundle.getMessage("UseGlobal", "Global") 495 + " " + InstanceManager.turnoutManagerInstance().getDefaultThrownSpeed()); 496 speedListThrown.add(0, defaultThrownSpeedText); 497 if (!speedListThrown.contains(speed)) { 498 speedListThrown.add(speed); 499 thrownSpeedBox.addItem(speed); 500 } 501 thrownSpeedBox.setSelectedItem(speed); 502 speed = bean.getStraightSpeed(); 503 speedListClosed.remove(defaultClosedSpeedText); 504 defaultClosedSpeedText = (Bundle.getMessage("UseGlobal", "Global") 505 + " " + InstanceManager.turnoutManagerInstance().getDefaultClosedSpeed()); 506 speedListClosed.add(0, defaultClosedSpeedText); 507 if (!speedListClosed.contains(speed)) { 508 speedListClosed.add(speed); 509 closedSpeedBox.addItem(speed); 510 } 511 closedSpeedBox.setSelectedItem(speed); 512 } 513 }); 514 515 bei.add(speed); 516 return speed; 517 } 518 519}