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.addItem(newName); 167 automationBox.setSelectedItem(newName); 168 } 169 bean.setTurnoutOperation(null); 170 bean.setTurnoutOperation(currentOperation); 171 } 172 config.endConfigure(); 173 switch (automationBox.getSelectedIndex()) { 174 case 0: // Off 175 bean.setInhibitOperation(true); 176 bean.setTurnoutOperation(null); 177 break; 178 case 1: // Default 179 bean.setInhibitOperation(false); 180 bean.setTurnoutOperation(null); 181 break; 182 default: // named operation 183 bean.setInhibitOperation(false); 184 String autoMode = (String) automationBox.getSelectedItem(); 185 if (autoMode != null) { 186 bean.setTurnoutOperation(InstanceManager.getDefault(TurnoutOperationManager.class). 187 getOperation((autoMode))); 188 } 189 break; 190 } 191 oldAutomationSelection = bean.getTurnoutOperation(); 192 oldModeSelection = bean.getFeedbackModeName(); 193 try { 194 bean.provideFirstFeedbackSensor(sensorFeedBack1ComboBox.getSelectedItemDisplayName()); 195 } catch (jmri.JmriException ex) { 196 JmriJOptionPane.showMessageDialog(turnoutOperation, ex.toString()); 197 } 198 try { 199 bean.provideSecondFeedbackSensor(sensorFeedBack2ComboBox.getSelectedItemDisplayName()); 200 } catch (jmri.JmriException ex) { 201 JmriJOptionPane.showMessageDialog(turnoutOperation, ex.toString()); 202 } 203 } 204 }); 205 206 feedback.setResetItem(new AbstractAction() { 207 @Override 208 public void actionPerformed(ActionEvent e) { 209 sensorFeedBack1ComboBox.setSelectedItem(bean.getFirstSensor()); 210 sensorFeedBack2ComboBox.setSelectedItem(bean.getSecondSensor()); 211 212 automationBox.removeActionListener(automationSelectionListener); 213 jmri.jmrit.beantable.TurnoutTableAction.updateAutomationBox(bean, automationBox); 214 automationBox.addActionListener(automationSelectionListener); 215 216 bean.setFeedbackMode(oldModeSelection); 217 updateFeedbackOptions(); 218 } 219 }); 220 bei.add(feedback); 221 return feedback; 222 } // feedback() 223 224 private String oldModeSelection; 225 private TurnoutOperation oldAutomationSelection; 226 private TurnoutOperation currentOperation; 227 private JTextField operationsName = new JTextField(10); 228 229 transient ActionListener automationSelectionListener = (ActionEvent e) -> { 230 updateAutomationOptions(); 231 }; 232 233 private void updateFeedbackOptions() { 234 sensorFeedBack1ComboBox.setEnabled(false); 235 sensorFeedBack2ComboBox.setEnabled(false); 236 237 String mode = (String) modeBox.getSelectedItem(); 238 if (mode != null) { 239 if (mode.equals("ONESENSOR")) { 240 sensorFeedBack1ComboBox.setEnabled(true); 241 } else if (mode.equals("TWOSENSOR")) { 242 sensorFeedBack1ComboBox.setEnabled(true); 243 sensorFeedBack2ComboBox.setEnabled(true); 244 } 245 bean.setFeedbackMode(mode); 246 } 247 248 bean.setFeedbackMode((String) modeBox.getSelectedItem()); 249 jmri.jmrit.beantable.TurnoutTableAction.updateAutomationBox(bean, automationBox); 250 } 251 252 private void updateAutomationOptions() { 253 254 currentOperation = null; 255 automationBox.removeActionListener(automationSelectionListener); 256 if (automationBox.getSelectedIndex() > 1) { 257 String autoMode = (String) automationBox.getSelectedItem(); 258 if (autoMode != null) { 259 currentOperation = InstanceManager.getDefault(TurnoutOperationManager.class). 260 getOperation((autoMode)); 261 } 262 } 263 264 if (currentOperation != null) { 265 turnoutOperation.remove(config); 266 if (!currentOperation.isNonce()) { 267 currentOperation = currentOperation.makeNonce(bean); 268 } 269 config = TurnoutOperationConfig.getConfigPanel(currentOperation); 270 operationsName.setEnabled(true); 271 config.setEnabled(true); 272 turnoutOperation.add(config); 273 feedback.revalidate(); 274 feedback.repaint(); 275 } else { 276 operationsName.setEnabled(false); 277 config.setEnabled(false); 278 for (Component j : config.getComponents()) { 279 j.setEnabled(false); 280 } 281 } 282 automationBox.addActionListener(automationSelectionListener); 283 } 284 285 @Override 286 protected void cancelButtonAction(ActionEvent e) { 287 bean.setFeedbackMode(oldModeSelection); 288 bean.setTurnoutOperation(oldAutomationSelection); 289 super.cancelButtonAction(e); 290 } 291 292 private final static String bothText = "Both"; // TODO I18N using bundle. Note: check how this property is stored/loaded 293 private final static String cabOnlyText = "Cab only"; 294 private final static String pushbutText = "Pushbutton only"; 295 private final static String noneText = "None"; 296 297 private JComboBox<String> lockBox; 298 protected BeanItemPanel lock() { 299 BeanItemPanel lock = new BeanItemPanel(); 300 lock.setName(Bundle.getMessage("Lock")); 301 302 if (bean.getPossibleLockModes() != 0) { 303 // lock operations are available, configure pane for them 304 lock.addItem(new BeanEditItem(null, null, Bundle.getMessage("LockToolTip"))); 305 306 // Vector is a JComboBox ctor; List is not 307 java.util.Vector<String> lockOperations = new java.util.Vector<>(); 308 int modes = bean.getPossibleLockModes(); 309 if (((modes & Turnout.CABLOCKOUT) != 0) 310 && ((modes & Turnout.PUSHBUTTONLOCKOUT) != 0)) { 311 lockOperations.add(bothText); 312 } 313 if ((modes & Turnout.CABLOCKOUT) != 0) { 314 lockOperations.add(cabOnlyText); 315 } 316 if ((modes & Turnout.PUSHBUTTONLOCKOUT) != 0) { 317 lockOperations.add(pushbutText); 318 } 319 lockOperations.add(noneText); 320 JComboBox<String> lockOperationBox = new JComboBox<>(lockOperations); 321 lockOperationBox.setMaximumRowCount(lockOperationBox.getItemCount()); 322 323 lock.addItem(new BeanEditItem(lockOperationBox, 324 Bundle.getMessage("LockMode"), 325 Bundle.getMessage("LockModeToolTip"))); 326 lockOperationBox.addActionListener((ActionEvent e) -> { 327 String lockOp = (String) lockOperationBox.getSelectedItem(); 328 if (lockOp != null) { 329 if (lockOp.equals(noneText)) { 330 lockBox.setEnabled(false); 331 } else { 332 lockBox.setEnabled(true); 333 } 334 } 335 }); 336 337 if ((bean.getPossibleLockModes() & Turnout.PUSHBUTTONLOCKOUT) != 0) { 338 lockBox = new JComboBox<>(bean.getValidDecoderNames()); 339 } else { 340 lockBox = new JComboBox<>(new String[]{bean.getDecoderName()}); 341 } 342 lock.addItem(new BeanEditItem(lockBox, 343 Bundle.getMessage("LockModeDecoder"), 344 Bundle.getMessage("LockModeDecoderToolTip"))); 345 346 lock.setSaveItem(new AbstractAction() { 347 @Override 348 public void actionPerformed(ActionEvent e) { 349 String lockOpName = (String) lockOperationBox.getSelectedItem(); 350 if (lockOpName != null) { 351 if (lockOpName.equals(bothText)) { 352 bean.enableLockOperation(Turnout.CABLOCKOUT 353 + Turnout.PUSHBUTTONLOCKOUT, true); 354 } 355 if (lockOpName.equals(cabOnlyText)) { 356 bean.enableLockOperation(Turnout.CABLOCKOUT, true); 357 bean.enableLockOperation(Turnout.PUSHBUTTONLOCKOUT, false); 358 } 359 if (lockOpName.equals(pushbutText)) { 360 bean.enableLockOperation(Turnout.CABLOCKOUT, false); 361 bean.enableLockOperation(Turnout.PUSHBUTTONLOCKOUT, true); 362 } 363 } 364 String decoderName = (String) lockBox.getSelectedItem(); 365 if (decoderName != null) { 366 bean.setDecoderName(decoderName); 367 } 368 } 369 }); 370 371 lock.setResetItem(new AbstractAction() { 372 @Override 373 public void actionPerformed(ActionEvent e) { 374 lockBox.setSelectedItem(bean.getDecoderName()); 375 lockBox.setEnabled(true); 376 if (bean.canLock(Turnout.CABLOCKOUT) 377 && bean.canLock(Turnout.PUSHBUTTONLOCKOUT)) { 378 lockOperationBox.setSelectedItem(bothText); 379 } else if (bean.canLock(Turnout.PUSHBUTTONLOCKOUT)) { 380 lockOperationBox.setSelectedItem(pushbutText); 381 } else if (bean.canLock(Turnout.CABLOCKOUT)) { 382 lockOperationBox.setSelectedItem(cabOnlyText); 383 } else { 384 lockOperationBox.setSelectedItem(noneText); 385 lockBox.setEnabled(false); 386 } 387 } 388 }); 389 } else { 390 // lock operations are not available for this kind of Turnout 391 lock.addItem(new BeanEditItem(null, null, Bundle.getMessage("LockModeUnavailable"))); 392 } 393 bei.add(lock); 394 return lock; 395 } // lock() 396 397 private java.util.Vector<String> speedListClosed = new java.util.Vector<>(); 398 private java.util.Vector<String> speedListThrown = new java.util.Vector<>(); 399 400 private JComboBox<String> closedSpeedBox; 401 private JComboBox<String> thrownSpeedBox; 402 private String defaultThrownSpeedText; 403 private String defaultClosedSpeedText; 404 405 protected BeanItemPanel speed() { 406 BeanItemPanel speed = new BeanItemPanel(); 407 speed.setName(Bundle.getMessage("Speed")); 408 409 speed.addItem(new BeanEditItem(null, null, Bundle.getMessage("SpeedTabToolTip"))); 410 411 defaultThrownSpeedText = (Bundle.getMessage("UseGlobal", "Global") 412 + " " + InstanceManager.turnoutManagerInstance().getDefaultThrownSpeed()); 413 defaultClosedSpeedText = (Bundle.getMessage("UseGlobal", "Global") 414 + " " + InstanceManager.turnoutManagerInstance().getDefaultClosedSpeed()); 415 416 useBlockSpeed = Bundle.getMessage("UseGlobal", "Block Speed"); 417 418 speedListClosed.add(defaultClosedSpeedText); 419 speedListThrown.add(defaultThrownSpeedText); 420 421 speedListClosed.add(useBlockSpeed); 422 speedListThrown.add(useBlockSpeed); 423 424 java.util.Vector<String> _speedMap = jmri.InstanceManager. 425 getDefault(SignalSpeedMap.class).getValidSpeedNames(); 426 for (String speedMap : _speedMap) { 427 if (!speedListClosed.contains(speedMap)) { 428 speedListClosed.add(speedMap); 429 } 430 if (!speedListThrown.contains(speedMap)) { 431 speedListThrown.add(speedMap); 432 } 433 } 434 435 closedSpeedBox = new JComboBox<>(speedListClosed); 436 closedSpeedBox.setMaximumRowCount(closedSpeedBox.getItemCount()); 437 closedSpeedBox.setEditable(true); 438 439 speed.addItem(new BeanEditItem(closedSpeedBox, 440 Bundle.getMessage("ClosedSpeed"), 441 Bundle.getMessage("ClosedSpeedToolTip"))); 442 thrownSpeedBox = new JComboBox<>(speedListThrown); 443 thrownSpeedBox.setMaximumRowCount(thrownSpeedBox.getItemCount()); 444 thrownSpeedBox.setEditable(true); 445 speed.addItem(new BeanEditItem(thrownSpeedBox, 446 Bundle.getMessage("ThrownSpeed"), 447 Bundle.getMessage("ThrownSpeedToolTip"))); 448 449 speed.setSaveItem(new AbstractAction() { 450 @Override 451 public void actionPerformed(ActionEvent e) { 452 String newSpeed = (String) closedSpeedBox.getSelectedItem(); 453 if (newSpeed != null) { 454 try { 455 bean.setStraightSpeed(newSpeed); 456 if ((!speedListClosed.contains(newSpeed)) && !newSpeed.contains("Global")) { 457 speedListClosed.add(newSpeed); 458 } 459 } catch (jmri.JmriException ex) { 460 JmriJOptionPane.showMessageDialog(speed, ex.getMessage() + "\n" + newSpeed); 461 } 462 } 463 newSpeed = (String) thrownSpeedBox.getSelectedItem(); 464 if (newSpeed != null) { 465 try { 466 bean.setDivergingSpeed(newSpeed); 467 if ((!speedListThrown.contains(newSpeed)) && !newSpeed.contains("Global")) { 468 speedListThrown.add(newSpeed); 469 } 470 } catch (jmri.JmriException ex) { 471 JmriJOptionPane.showMessageDialog(speed, ex.getMessage() + "\n" + newSpeed); 472 } 473 } 474 } 475 }); 476 477 speed.setResetItem(new AbstractAction() { 478 @Override 479 public void actionPerformed(ActionEvent e) { 480 String speed = bean.getDivergingSpeed(); 481 speedListThrown.remove(defaultThrownSpeedText); 482 defaultThrownSpeedText = (Bundle.getMessage("UseGlobal", "Global") 483 + " " + InstanceManager.turnoutManagerInstance().getDefaultThrownSpeed()); 484 speedListThrown.add(0, defaultThrownSpeedText); 485 if (!speedListThrown.contains(speed)) { 486 speedListThrown.add(speed); 487 thrownSpeedBox.addItem(speed); 488 } 489 thrownSpeedBox.setSelectedItem(speed); 490 speed = bean.getStraightSpeed(); 491 speedListClosed.remove(defaultClosedSpeedText); 492 defaultClosedSpeedText = (Bundle.getMessage("UseGlobal", "Global") 493 + " " + InstanceManager.turnoutManagerInstance().getDefaultClosedSpeed()); 494 speedListClosed.add(0, defaultClosedSpeedText); 495 if (!speedListClosed.contains(speed)) { 496 speedListClosed.add(speed); 497 closedSpeedBox.addItem(speed); 498 } 499 closedSpeedBox.setSelectedItem(speed); 500 } 501 }); 502 503 bei.add(speed); 504 return speed; 505 } 506 507}