001package jmri.jmrit.conditional; 002 003import java.awt.BorderLayout; 004import java.awt.Color; 005import java.awt.Component; 006import java.awt.Container; 007import java.awt.GridBagConstraints; 008import java.awt.GridBagLayout; 009import java.awt.event.*; 010import java.util.ArrayList; 011import java.util.List; 012import java.util.TreeMap; 013import java.util.TreeSet; 014import javax.swing.*; 015import javax.swing.event.*; 016import javax.swing.tree.*; 017 018import org.apache.commons.lang3.StringUtils; 019 020import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; 021 022import javax.swing.filechooser.FileNameExtensionFilter; 023 024import jmri.*; 025import jmri.Conditional.Operator; 026import jmri.implementation.DefaultConditional; 027import jmri.implementation.DefaultConditionalAction; 028import jmri.jmrit.beantable.LRouteTableAction; 029import jmri.jmrit.logix.OBlock; 030import jmri.jmrit.logix.Warrant; 031import jmri.script.swing.ScriptFileChooser; 032import jmri.swing.NamedBeanComboBox; 033import jmri.util.FileUtil; 034import jmri.util.JmriJFrame; 035import jmri.util.swing.JComboBoxUtil; 036import jmri.util.swing.JmriJOptionPane; 037 038/** 039 * A tree based editor for maintaining Logix Conditionals, State Variables and 040 * Actions. 041 * <p> 042 * The tree has 3 levels. The first level are the conditionals contained in the 043 * selected Logix. The second level contains the antecedent, logic type and 044 * trigger mode settings. The third level contains the detail Variable and 045 * Action lines. 046 * <p> 047 * Compare with the other Conditional Edit tool {@link ConditionalListEdit} 048 * 049 * @author Dave Sand copyright (c) 2017 050 */ 051public class ConditionalTreeEdit extends ConditionalEditBase { 052 053 /** 054 * Create a new Conditional Tree View editor. 055 * 056 * @param sName The system name of the current Logix 057 */ 058 public ConditionalTreeEdit(String sName) { 059 super(sName); 060 buildConditionalComponents(); 061 buildActionComponents(); 062 buildVariableComponents(); 063 makeEditLogixWindow(); 064 setFocusListeners(); 065 setEditMode(false); 066 } 067 068 public ConditionalTreeEdit() { 069 } 070 071 JPanel _curDetailPanel = new JPanel(); 072 JTextField _editLogixUserName = new JTextField(20); // Logix User Name field 073 NamedBeanComboBox<?> _comboNameBox = null; 074 075 076 // ------------ Edit detail components ------------ 077 JPanel _detailGrid = new JPanel(); 078 JPanel _detailFooter = new JPanel(); 079 JPanel _gridPanel; // Child of _detailGrid, contains the current grid labels and fields 080 JTextField _editConditionalUserName; 081 JTextField _editAntecedent; 082 JComboBox<Conditional.AntecedentOperator> _editOperatorMode; 083 boolean _editActive = false; 084 JButton _cancelAction; 085 JButton _updateAction; 086 String _pickCommand = null; 087 Conditional.ItemType _pickItem = Conditional.ItemType.NONE; 088 089 // ------------ Tree variables ------------ 090 JTree _cdlTree; 091 DefaultTreeModel _cdlModel; 092 DefaultMutableTreeNode _cdlRoot; 093 TreeSelectionListener _cdlListener; 094 TreePath _curTreePath = null; 095 096 // ------------ Tree components ------------ 097 ConditionalTreeNode _cdlNode = null; 098 ConditionalTreeNode _varHead = null; 099 ConditionalTreeNode _varNode = null; 100 ConditionalTreeNode _actHead = null; 101 ConditionalTreeNode _actNode = null; 102 ConditionalTreeNode _leafNode = null; 103 104 // ------------ Current tree node variables ------------ 105 ConditionalTreeNode _curNode = null; 106 String _curNodeName = null; 107 String _curNodeType = null; 108 String _curNodeText = null; 109 int _curNodeRow = -1; 110 111 // ------------ Button bar components ------------ 112 JPanel _leftButtonBar; 113 JPanel _labelPanel; 114 JPanel _addButtonPanel; 115 JPanel _toggleButtonPanel; 116 JPanel _checkButtonPanel; 117 JPanel _moveButtonPanel; 118 JPanel _deleteButtonPanel; 119 JPanel _helpButtonPanel; 120 121 JLabel _conditionalLabel = new JLabel(Bundle.getMessage("LabelConditionalActions")); // NOI18N 122 JLabel _antecedentLabel = new JLabel(Bundle.getMessage("LabelAntecedentActions")); // NOI18N 123 JLabel _logicTypeLabel = new JLabel(Bundle.getMessage("LabelLogicTypeActions")); // NOI18N 124 JLabel _triggerModeLabel = new JLabel(Bundle.getMessage("LabelTriggerModeActions")); // NOI18N 125 JLabel _variablesLabel = new JLabel(Bundle.getMessage("LabelVariablesActions")); // NOI18N 126 JLabel _variableLabel = new JLabel(Bundle.getMessage("LabelVariableActions")); // NOI18N 127 JLabel _actionsLabel = new JLabel(Bundle.getMessage("LabelActionsActions")); // NOI18N 128 JLabel _actionLabel = new JLabel(Bundle.getMessage("LabelActionActions")); // NOI18N 129 130 // ------------ Current conditional components ------------ 131 Conditional _curConditional; 132 List<ConditionalVariable> _variableList; // Current Variable List 133 List<ConditionalAction> _actionList; // Current Action List 134 ConditionalVariable _curVariable; // Current Variable 135 ConditionalAction _curAction; // Current Action 136 Conditional.ItemType _curVariableItem = Conditional.ItemType.NONE; 137 Conditional.ItemType _curActionItem = Conditional.ItemType.NONE; 138 String _curConditionalName = ""; 139 String _antecedent; 140 Conditional.AntecedentOperator _logicType; 141 boolean _triggerMode; 142 boolean _newActionItem = false; 143 boolean _newVariableItem = false; 144 TreeSet<String> _oldTargetNames = new TreeSet<>(); 145 146 // ------------ Select Conditional Variables ------------ 147 JComboBox<String> _selectLogixBox = new JComboBox<>(); 148 JComboBox<String> _selectConditionalBox = new JComboBox<>(); 149 TreeMap<String, String> _selectLogixMap = new TreeMap<>(); 150 ArrayList<String> _selectConditionalList = new ArrayList<>(); 151 152 // ------------ Components of Edit Variable pane ------------ 153 JComboBox<Conditional.ItemType> _variableItemBox; 154 JComboBox<Conditional.Type> _variableStateBox; 155 JComboBox<String> _variableOperBox; 156 JCheckBox _variableNegated; 157 JCheckBox _variableTriggerActions; 158 JTextField _variableNameField; 159 JLabel _variableNameLabel = new JLabel(Bundle.getMessage("LabelItemName")); // NOI18N 160 JComboBox<String> _variableCompareOpBox; 161 JComboBox<String> _variableSignalBox; 162 JComboBox<Conditional.Type> _variableCompareTypeBox; 163 JLabel _variableMemoryValueLabel = new JLabel(""); 164 JTextField _variableData1Field; 165 JTextField _variableData2Field; 166 167 // ------------ Components of Edit Action pane ------------ 168 JComboBox<Conditional.ItemType> _actionItemBox; 169 JComboBox<Conditional.Action> _actionTypeBox; 170 JLabel _actionTypeLabel = new JLabel("Type"); // NOI18N 171 JTextField _actionNameField; 172 JLabel _actionNameLabel = new JLabel("Name"); // NOI18N 173 JComboBox<String> _actionBox; 174 JLabel _actionBoxLabel = new JLabel("Box"); // NOI18N 175 JTextField _longActionString; 176 JLabel _longActionLabel = new JLabel("Long"); // NOI18N 177 JTextField _shortActionString; 178 JLabel _shortActionLabel = new JLabel("Short"); // NOI18N 179 JComboBox<String> _actionOptionBox; 180 JButton _actionSetButton; 181 182 // ============ Edit conditionals for the current Logix ============ 183 184 /** 185 * Create the edit logix window. 186 * <p> 187 * The left side contains a tree structure containing the conditionals for 188 * the current Logix. The right side contains detail edit panes based on the 189 * current tree row selection. 190 */ 191 void makeEditLogixWindow() { 192 _editLogixFrame = new JmriJFrame(Bundle.getMessage("TitleEditLogix")); // NOI18N 193 _editLogixFrame.addHelpMenu( 194 "package.jmri.jmrit.conditional.ConditionalTreeEditor", true); // NOI18N 195 Container contentPane = _editLogixFrame.getContentPane(); 196 contentPane.setLayout(new BorderLayout()); 197 198 // ------------ Header ------------ 199 JPanel header = new JPanel(); 200 JPanel logixNames = new JPanel(); 201 logixNames.setLayout(new BoxLayout(logixNames, BoxLayout.X_AXIS)); 202 203 JLabel systemNameLabel = new JLabel(Bundle.getMessage("ColumnSystemName") + ":"); // NOI18N 204 logixNames.add(systemNameLabel); 205 logixNames.add(Box.createHorizontalStrut(5)); 206 207 JLabel fixedSystemName = new JLabel(_curLogix.getSystemName()); 208 logixNames.add(fixedSystemName); 209 logixNames.add(Box.createHorizontalStrut(20)); 210 211 JLabel userNameLabel = new JLabel(Bundle.getMessage("ColumnUserName") + ":"); // NOI18N 212 logixNames.add(userNameLabel); 213 logixNames.add(Box.createHorizontalStrut(5)); 214 215 _editLogixUserName.setText(_curLogix.getUserName()); 216 logixNames.add(_editLogixUserName); 217 _editLogixUserName.setToolTipText(Bundle.getMessage("LogixUserNameHint2")); // NOI18N 218 _editLogixUserName.addActionListener(new ActionListener() { 219 @Override 220 public void actionPerformed(ActionEvent e) { 221 String uName = _editLogixUserName.getText().trim(); 222 if (!(uName.equals(_curLogix.getUserName()))) { 223 // user name has changed - check if already in use 224 if (uName.length() > 0) { 225 Logix p = _logixManager.getByUserName(uName); 226 if (p != null) { 227 // Logix with this user name already exists 228 log.error("Failure to update Logix with Duplicate User Name: {}", uName); // NOI18N 229 JmriJOptionPane.showMessageDialog(_editLogixFrame, 230 Bundle.getMessage("Error6"), Bundle.getMessage("ErrorTitle"), // NOI18N 231 JmriJOptionPane.ERROR_MESSAGE); 232 return; 233 } 234 } 235 // user name is unique, change it 236 logixData.clear(); 237 logixData.put("chgUname", uName); // NOI18N 238 fireLogixEvent(); 239 _showReminder = true; 240 } 241 } 242 }); 243 244 header.add(logixNames); 245 contentPane.add(header, BorderLayout.NORTH); 246 247 // ------------ body - tree (left side) ------------ 248 JTree treeContent = buildConditionalTree(); 249 JScrollPane treeScroll = new JScrollPane(treeContent); 250 251 // ------------ body - detail (right side) ------------ 252 JPanel detailPane = new JPanel(); 253 detailPane.setBorder(BorderFactory.createMatteBorder(0, 2, 0, 0, Color.DARK_GRAY)); 254 detailPane.setLayout(new BoxLayout(detailPane, BoxLayout.Y_AXIS)); 255 256 // ------------ Edit Detail Panel ------------ 257 makeDetailGrid("EmptyGrid"); // NOI18N 258 259 JPanel panel = new JPanel(); 260 panel.setLayout(new BoxLayout(panel, BoxLayout.X_AXIS)); 261 262 _cancelAction = new JButton(Bundle.getMessage("ButtonCancel")); // NOI18N 263 _cancelAction.setToolTipText(Bundle.getMessage("HintCancelButton")); // NOI18N 264 panel.add(_cancelAction); 265 _cancelAction.addActionListener(new ActionListener() { 266 @Override 267 public void actionPerformed(ActionEvent e) { 268 cancelPressed(); 269 } 270 }); 271 panel.add(Box.createHorizontalStrut(10)); 272 273 _updateAction = new JButton(Bundle.getMessage("ButtonUpdate")); // NOI18N 274 _updateAction.setToolTipText(Bundle.getMessage("UpdateButtonHint")); // NOI18N 275 panel.add(_updateAction); 276 _updateAction.addActionListener(new ActionListener() { 277 @Override 278 public void actionPerformed(ActionEvent e) { 279 updatePressed(); 280 } 281 }); 282 _detailFooter.add(panel); 283 284 JPanel detailEdit = new JPanel(new BorderLayout()); 285 detailEdit.add(_detailGrid, BorderLayout.NORTH); 286 detailEdit.add(_detailFooter, BorderLayout.SOUTH); 287 detailPane.add(detailEdit); 288 _editLogixUserName.setEnabled(true); 289 290 JSplitPane bodyPane = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, treeScroll, detailPane); 291 bodyPane.setDividerSize(10); 292 bodyPane.setResizeWeight(.35); 293 bodyPane.setOneTouchExpandable(true); 294 contentPane.add(bodyPane); 295 296 // ------------ footer ------------ 297 JPanel footer = new JPanel(new BorderLayout()); 298 _labelPanel = new JPanel(); 299 _labelPanel.add(_conditionalLabel); 300 _leftButtonBar = new JPanel(); 301 _leftButtonBar.add(_labelPanel); 302 303 // ------------ Add Button ------------ 304 JButton addButton = new JButton(Bundle.getMessage("ButtonAddText")); // NOI18N 305 addButton.setToolTipText(Bundle.getMessage("HintAddButton")); // NOI18N 306 addButton.addActionListener(new ActionListener() { 307 @Override 308 public void actionPerformed(ActionEvent e) { 309 addPressed(); 310 } 311 }); 312 _addButtonPanel = new JPanel(); 313 _addButtonPanel.add(addButton); 314 _leftButtonBar.add(_addButtonPanel); 315 316 // ------------ Help Button ------------ 317 JButton helpButton = new JButton(Bundle.getMessage("ButtonHelp")); // NOI18N 318 helpButton.setToolTipText(Bundle.getMessage("HintHelpButton")); // NOI18N 319 helpButton.addActionListener(new ActionListener() { 320 @Override 321 public void actionPerformed(ActionEvent e) { 322 helpPressed(); 323 } 324 }); 325 _helpButtonPanel = new JPanel(); 326 _helpButtonPanel.add(helpButton); 327 _helpButtonPanel.setVisible(false); 328 _leftButtonBar.add(_helpButtonPanel); 329 330 // ------------ Toggle Button ------------ 331 JButton toggleButton = new JButton(Bundle.getMessage("ButtonToggle")); // NOI18N 332 toggleButton.setToolTipText(Bundle.getMessage("HintToggleButton")); // NOI18N 333 toggleButton.addActionListener(new ActionListener() { 334 @Override 335 public void actionPerformed(ActionEvent e) { 336 togglePressed(); 337 } 338 }); 339 _toggleButtonPanel = new JPanel(); 340 _toggleButtonPanel.add(toggleButton); 341 _toggleButtonPanel.setVisible(false); 342 _leftButtonBar.add(_toggleButtonPanel); 343 344 // ------------ Check Button ------------ 345 JButton checkButton = new JButton(Bundle.getMessage("ButtonCheck")); // NOI18N 346 checkButton.setToolTipText(Bundle.getMessage("HintCheckButton")); // NOI18N 347 checkButton.addActionListener(new ActionListener() { 348 @Override 349 public void actionPerformed(ActionEvent e) { 350 checkPressed(); 351 } 352 }); 353 _checkButtonPanel = new JPanel(); 354 _checkButtonPanel.add(checkButton); 355 _checkButtonPanel.setVisible(true); 356 _leftButtonBar.add(_checkButtonPanel); 357 358 // ------------ Delete Button ------------ 359 JButton deleteButton = new JButton(Bundle.getMessage("ButtonDelete")); // NOI18N 360 deleteButton.setToolTipText(Bundle.getMessage("HintDeleteButton")); // NOI18N 361 deleteButton.addActionListener(new ActionListener() { 362 @Override 363 public void actionPerformed(ActionEvent e) { 364 deletePressed(); 365 } 366 }); 367 _deleteButtonPanel = new JPanel(); 368 _deleteButtonPanel.add(deleteButton); 369 _deleteButtonPanel.setVisible(false); 370 _leftButtonBar.add(_deleteButtonPanel); 371 372 footer.add(_leftButtonBar, BorderLayout.WEST); 373 JPanel rightButtonBar = new JPanel(); 374 375 // ------------ Move Buttons ------------ 376 JLabel moveLabel = new JLabel(Bundle.getMessage("LabelMove")); // NOI18N 377 378 JButton upButton = new JButton(Bundle.getMessage("ButtonUp")); // NOI18N 379 upButton.setToolTipText(Bundle.getMessage("HintUpButton")); // NOI18N 380 JButton downButton = new JButton(Bundle.getMessage("ButtonDown")); // NOI18N 381 downButton.setToolTipText(Bundle.getMessage("HintDownButton")); // NOI18N 382 383 upButton.addActionListener(new ActionListener() { 384 @Override 385 public void actionPerformed(ActionEvent e) { 386 downButton.setEnabled(false); 387 upButton.setEnabled(false); 388 upPressed(); 389 } 390 }); 391 392 downButton.addActionListener(new ActionListener() { 393 @Override 394 public void actionPerformed(ActionEvent e) { 395 upButton.setEnabled(false); 396 downButton.setEnabled(false); 397 downPressed(); 398 } 399 }); 400 401 _moveButtonPanel = new JPanel(); 402 _moveButtonPanel.add(moveLabel); 403 _moveButtonPanel.add(upButton); 404 _moveButtonPanel.add(new JLabel("|")); 405 _moveButtonPanel.add(downButton); 406 _moveButtonPanel.setVisible(false); 407 _leftButtonBar.add(_moveButtonPanel); 408 409 // ------------ Done Button ------------ 410 JButton doneButton = new JButton(Bundle.getMessage("ButtonDone")); // NOI18N 411 doneButton.setToolTipText(Bundle.getMessage("HintDoneButton")); // NOI18N 412 doneButton.addActionListener(new ActionListener() { 413 @Override 414 public void actionPerformed(ActionEvent e) { 415 donePressed(); 416 } 417 }); 418 JPanel doneButtonPanel = new JPanel(); 419 doneButtonPanel.add(doneButton); 420 rightButtonBar.add(doneButtonPanel); 421 422 footer.add(rightButtonBar, BorderLayout.EAST); 423 contentPane.add(footer, BorderLayout.SOUTH); 424 425 _editLogixFrame.addWindowListener(new java.awt.event.WindowAdapter() { 426 @Override 427 public void windowClosing(java.awt.event.WindowEvent e) { 428 donePressed(); 429 } 430 }); 431 _editLogixFrame.setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE); 432 _editLogixFrame.pack(); 433 _editLogixFrame.setVisible(true); 434 } 435 436 /** 437 * Initialize conditional components. 438 */ 439 void buildConditionalComponents() { 440 _editConditionalUserName = new JTextField(20); 441 _editAntecedent = new JTextField(20); 442 _editOperatorMode = new JComboBox<>(); 443 for (Conditional.AntecedentOperator operator : Conditional.AntecedentOperator.values()) { 444 _editOperatorMode.addItem(operator); 445 } 446 } 447 448 // ------------ Create Conditional GridBag panels ------------ 449 450 /** 451 * Build new GridBag content. The grid panel is hidden, emptied, re-built and 452 * made visible. 453 * 454 * @param gridType The type of grid to create 455 */ 456 void makeDetailGrid(String gridType) { 457 _detailGrid.setVisible(false); 458 _detailGrid.removeAll(); 459 _detailFooter.setVisible(true); 460 461 _gridPanel = new JPanel(new GridBagLayout()); 462 GridBagConstraints c = new GridBagConstraints(); 463 c.gridwidth = 1; 464 c.gridheight = 1; 465 c.ipadx = 5; 466 467 switch (gridType) { 468 case "EmptyGrid": // NOI18N 469 makeEmptyGrid(c); 470 _detailFooter.setVisible(false); 471 break; 472 473 // ------------ Conditional Edit Grids ------------ 474 case "Conditional": // NOI18N 475 makeConditionalGrid(c); 476 break; 477 478 case "Antecedent": // NOI18N 479 makeAntecedentGrid(c); 480 break; 481 482 case "LogicType": // NOI18N 483 makeLogicTypeGrid(c); 484 break; 485 486 // ------------ Variable Edit Grids ------------ 487 case "EmptyVariable": // NOI18N 488 makeEmptyVariableGrid(c); 489 break; 490 491 case "StandardVariable": // NOI18N 492 makeStandardVariableGrid(c); 493 break; 494 495 case "SignalAspectVariable": // NOI18N 496 makeSignalAspectVariableGrid(c); 497 break; 498 499 case "ConditionalVariable": // NOI18N 500 makeConditionalVariableGrid(c); 501 break; 502 503 case "MemoryVariable": // NOI18N 504 makeMemoryVariableGrid(c); 505 break; 506 507 case "FastClockVariable": // NOI18N 508 makeFastClockVariableGrid(c); 509 break; 510 511 // ------------ Action Edit Grids ------------ 512 case "EmptyAction": // NOI18N 513 makeEmptyActionGrid(c); 514 break; 515 516 case "NameTypeAction": // NOI18N 517 makeNameTypeActionGrid(c, false); // Skip change/trigger row 518 break; 519 520 case "NameTypeActionFinal": // NOI18N 521 makeNameTypeActionGrid(c, true); // Include change/trigger row 522 break; 523 524 case "TypeAction": // NOI18N 525 makeTypeActionGrid(c, false); // Skip change/trigger row 526 break; 527 528 case "TypeActionFinal": // NOI18N 529 makeTypeActionGrid(c, true); // Include change/trigger row 530 break; 531 532 case "TypeShortAction": // NOI18N 533 makeTypeShortActionGrid(c); 534 break; 535 536 case "StandardAction": // NOI18N 537 makeStandardActionGrid(c, true); // Include change/trigger row 538 break; 539 540 case "ShortFieldAction": // NOI18N 541 makeShortFieldActionGrid(c, true); // Include Action Box 542 break; 543 544 case "ShortFieldNoBoxAction": // NOI18N 545 makeShortFieldActionGrid(c, false); // Skip Action Box 546 break; 547 548 case "FileAction": // NOI18N 549 makeFileActionGrid(c); 550 break; 551 552 default: 553 log.warn("Invalid grid type: '{}'", gridType); // NOI18N 554 makeEmptyGrid(c); 555 } 556 557 _detailGrid.add(_gridPanel); 558 _detailGrid.setVisible(true); 559 } 560 561 /** 562 * This grid is used when there are no edit grids required. 563 * 564 * @param c The constraints object used for the grid construction 565 */ 566 void makeEmptyGrid(GridBagConstraints c) { 567 // Variable type box 568 c.gridy = 0; 569 c.gridx = 0; 570 c.anchor = java.awt.GridBagConstraints.CENTER; 571 JLabel row0Label = new JLabel("This page is intentionally blank"); // NOI18N 572 _gridPanel.add(row0Label, c); 573 } 574 575 /** 576 * This grid is used to edit the Conditional User Name. 577 * 578 * @param c The constraints object used for the grid construction 579 */ 580 void makeConditionalGrid(GridBagConstraints c) { 581 c.gridy = 0; 582 c.gridx = 0; 583 c.anchor = java.awt.GridBagConstraints.EAST; 584 JLabel row0Label = new JLabel(Bundle.getMessage("ConditionalUserName")); // NOI18N 585 row0Label.setToolTipText(Bundle.getMessage("ConditionalUserNameHint")); // NOI18N 586 _gridPanel.add(row0Label, c); 587 c.gridx = 1; 588 c.anchor = java.awt.GridBagConstraints.WEST; 589 _gridPanel.add(_editConditionalUserName, c); 590 } 591 592 /** 593 * This grid is used to edit the Antecedent when the Logic Type is Mixed. 594 * 595 * @param c The constraints object used for the grid construction 596 */ 597 void makeAntecedentGrid(GridBagConstraints c) { 598 c.gridy = 0; 599 c.gridx = 0; 600 c.anchor = java.awt.GridBagConstraints.EAST; 601 JLabel row0Label = new JLabel(Bundle.getMessage("LabelAntecedentHeader")); // NOI18N 602 row0Label.setToolTipText(Bundle.getMessage("LabelAntecedentHint")); // NOI18N 603 _gridPanel.add(row0Label, c); 604 c.gridx = 1; 605 c.anchor = java.awt.GridBagConstraints.WEST; 606 _gridPanel.add(_editAntecedent, c); 607 } 608 609 /** 610 * This grid is used to edit the Logic Type. 611 * 612 * @param c The constraints object used for the grid construction 613 */ 614 void makeLogicTypeGrid(GridBagConstraints c) { 615 c.gridy = 0; 616 c.gridx = 0; 617 c.anchor = java.awt.GridBagConstraints.EAST; 618 JLabel row0Label = new JLabel(Bundle.getMessage("LabelLogicType")); // NOI18N 619 row0Label.setToolTipText(Bundle.getMessage("TypeLogicHint")); // NOI18N 620 _gridPanel.add(row0Label, c); 621 c.gridx = 1; 622 c.anchor = java.awt.GridBagConstraints.WEST; 623 _gridPanel.add(_editOperatorMode, c); 624 } 625 626 // ------------ Process button bar and tree events ------------ 627 628 /** 629 * Add new items: Conditionals, Variables or Actions. 630 */ 631 void addPressed() { 632 if (_curNode == null) { 633 // New conditional with no prior selection 634 _curNodeType = "Conditional"; // NOI18N 635 } 636 637 switch (_curNodeType) { 638 case "Conditional": // NOI18N 639 // make system name for new conditional 640 int num = _curLogix.getNumConditionals() + 1; 641 _curConditional = null; 642 String cName = null; 643 while (_curConditional == null) { 644 cName = _curLogix.getSystemName() + "C" + Integer.toString(num); 645 _curConditional = _conditionalManager.createNewConditional(cName, ""); 646 num++; 647 if (num == 1000) { 648 break; 649 } 650 } 651 if (_curConditional == null) { 652 // should never get here unless there is an assignment conflict 653 log.error("Failure to create Conditional with System Name: {}", cName); // NOI18N 654 return; 655 } 656 // add to Logix at the end of the calculate order 657 _curLogix.addConditional(cName, -1); 658 _actionList = new ArrayList<>(); 659 _variableList = new ArrayList<>(); 660 _curConditional.setAction(_actionList); 661 _curConditional.setStateVariables(_variableList); 662 _showReminder = true; 663 664 // Build tree components 665 Conditional curConditional = _curLogix.getConditional(cName); 666 _curNode = new ConditionalTreeNode(buildNodeText("Conditional", curConditional, 0), "Conditional", cName, // NOI18N 667 _curLogix.getNumConditionals() - 1); 668 _cdlRoot.add(_curNode); 669 _leafNode = new ConditionalTreeNode(buildNodeText("Antecedent", curConditional, 0), "Antecedent", cName, 0); // NOI18N 670 _curNode.add(_leafNode); 671 _varHead = new ConditionalTreeNode(buildNodeText("Variables", curConditional, 0), "Variables", cName, 0); // NOI18N 672 _curNode.add(_varHead); 673 _leafNode = new ConditionalTreeNode(buildNodeText("LogicType", curConditional, 0), "LogicType", cName, 0); // NOI18N 674 _curNode.add(_leafNode); 675 _triggerMode = curConditional.getTriggerOnChange(); 676 _leafNode = new ConditionalTreeNode(buildNodeText("TriggerMode", curConditional, 0), "TriggerMode", cName, 0); // NOI18N 677 _curNode.add(_leafNode); 678 _actHead = new ConditionalTreeNode(buildNodeText("Actions", curConditional, 0), "Actions", cName, 0); // NOI18N 679 _curNode.add(_actHead); 680 _cdlModel.nodeStructureChanged(_cdlRoot); 681 682 // Switch to new node 683 _cdlTree.setSelectionPath(new TreePath(_curNode.getPath())); 684 break; 685 686 case "Variables": // NOI18N 687 newVariable(); 688 break; 689 690 case "Variable": // NOI18N 691 newVariable(); 692 break; 693 694 case "Actions": // NOI18N 695 newAction(); 696 break; 697 698 case "Action": // NOI18N 699 newAction(); 700 break; 701 702 default: 703 log.error("Add called for unsupported node type: '{}'", _curNodeType); // NOI18N 704 } 705 } 706 707 /** 708 * Create a new variable Can be invoked by a Variables or Variable node. 709 */ 710 void newVariable() { 711 if (LRouteTableAction.getLogixInitializer().equals(_curLogix.getSystemName())) { 712 JmriJOptionPane.showMessageDialog(_editLogixFrame, 713 Bundle.getMessage("Error49"), Bundle.getMessage("ErrorTitle"), // NOI18N 714 JmriJOptionPane.ERROR_MESSAGE); 715 return; 716 } 717 718 cancelPressed(); // Make sure that there are no active edit sessions 719 _showReminder = true; 720 _curVariableItem = Conditional.ItemType.NONE; 721 ConditionalVariable variable = new ConditionalVariable(); 722 _variableList.add(variable); 723 _newVariableItem = true; 724 setMoveButtons(); // Buttons will be disabled 725 726 int size = _variableList.size(); 727 _curVariable = _variableList.get(size - 1); 728 // default of operator for postion 0 (row 1) is Conditional.OPERATOR_NONE 729 if (size > 1) { 730 if (_logicType == Conditional.AntecedentOperator.ALL_OR) { 731 _curVariable.setOpern(Conditional.Operator.OR); 732 } else { 733 _curVariable.setOpern(Conditional.Operator.AND); 734 } 735 } 736 appendToAntecedent(); 737 size--; 738 739 // Update tree structure 740 if (_curNodeType.equals("Variables")) { // NOI18N 741 _varHead = _curNode; 742 } else { 743 _varHead = (ConditionalTreeNode) _curNode.getParent(); 744 } 745 _leafNode = new ConditionalTreeNode(buildNodeText("Variable", _curVariable, size), "Variable", _curNodeName, size); // NOI18N 746 _varHead.add(_leafNode); 747 _cdlModel.nodeStructureChanged(_curNode); 748 _varHead.setRow(size + 1); 749 _cdlModel.nodeStructureChanged(_varHead); 750 751 // Switch to new node 752 ConditionalTreeNode tempNode = (ConditionalTreeNode) _varHead.getLastChild(); 753 TreePath newPath = new TreePath(tempNode.getPath()); 754 _cdlTree.setSelectionPath(newPath); 755 _cdlTree.expandPath(newPath); 756 } 757 758 /** 759 * Create a new action Can be invoked by a Actions or Action node. 760 */ 761 void newAction() { 762 cancelPressed(); // Make sure that there are no active edit sessions 763 _showReminder = true; 764 _curActionItem = Conditional.ItemType.NONE; 765 ConditionalAction action = new DefaultConditionalAction(); 766 _actionList.add(action); 767 _newActionItem = true; 768 setMoveButtons(); // Buttons will be disabled 769 770 int size = _actionList.size(); 771 _curAction = _actionList.get(size - 1); 772 size--; 773 774 // Update tree structure 775 if (_curNodeType.equals("Actions")) { // NOI18N 776 _actHead = _curNode; 777 } else { 778 _actHead = (ConditionalTreeNode) _curNode.getParent(); 779 } 780 _leafNode = new ConditionalTreeNode(buildNodeText("Action", _curAction, size), "Action", _curNodeName, size); // NOI18N 781 _actHead.add(_leafNode); 782 _cdlModel.nodeStructureChanged(_curNode); 783 _actHead.setRow(size + 1); 784 _cdlModel.nodeStructureChanged(_actHead); 785 786 // Switch to new node 787 ConditionalTreeNode tempNode = (ConditionalTreeNode) _actHead.getLastChild(); 788 TreePath newPath = new TreePath(tempNode.getPath()); 789 _cdlTree.setSelectionPath(newPath); 790 _cdlTree.expandPath(newPath); 791 } 792 793 /** 794 * Set up the edit environment for the selected node Called from 795 * {@link #treeRowSelected}. This takes the place of an actual button. 796 */ 797 void editPressed() { 798 switch (_curNodeType) { 799 case "Conditional": // NOI18N 800 _editConditionalUserName.setText(_curConditional.getUserName()); 801 makeDetailGrid("Conditional"); // NOI18N 802 break; 803 804 case "Antecedent": // NOI18N 805 Conditional.AntecedentOperator chkLogicType = _curConditional.getLogicType(); 806 if (chkLogicType != Conditional.AntecedentOperator.MIXED) { 807 makeDetailGrid("EmptyGrid"); // NOI18N 808 return; 809 } 810 _labelPanel.add(_antecedentLabel); 811 _helpButtonPanel.setVisible(true); 812 _editAntecedent.setText(translateAntecedent(_curConditional.getAntecedentExpression(), false)); 813 makeDetailGrid("Antecedent"); // NOI18N 814 break; 815 816 case "LogicType": // NOI18N 817 Conditional.AntecedentOperator curLogicType = _curConditional.getLogicType(); 818 _editOperatorMode.setSelectedItem(curLogicType); 819 makeDetailGrid("LogicType"); // NOI18N 820 break; 821 822 case "Variable": // NOI18N 823 _labelPanel.add(_variableLabel); 824 _curVariable = _variableList.get(_curNodeRow); 825 _curVariableItem = _curVariable.getType().getItemType(); 826 initializeStateVariables(); 827 if (_logicType != Conditional.AntecedentOperator.MIXED) { 828 setMoveButtons(); 829 } 830 _oldTargetNames.clear(); 831 loadReferenceNames(_variableList, _oldTargetNames); 832 break; 833 834 case "Action": // NOI18N 835 _labelPanel.add(_actionLabel); 836 _curAction = _actionList.get(_curNodeRow); 837 _actionOptionBox.removeAllItems(); 838 for (int i = 1; i <= Conditional.NUM_ACTION_OPTIONS; i++) { 839 _actionOptionBox.addItem(DefaultConditionalAction.getOptionString(i, _triggerMode)); 840 } 841 _curActionItem = _curAction.getType().getItemType(); 842 initializeActionVariables(); 843 setMoveButtons(); 844 break; 845 846 default: 847 log.error("Edit called for unsupported node type: '{}'", _curNodeType); // NOI18N 848 } 849 } 850 851 /** 852 * Apply the updates to the current node. 853 */ 854 void updatePressed() { 855 switch (_curNodeType) { 856 case "Conditional": // NOI18N 857 userNameChanged(_editConditionalUserName.getText().trim()); 858 break; 859 860 case "Antecedent": // NOI18N 861 antecedentChanged(_editAntecedent.getText().trim()); 862 break; 863 864 case "LogicType": // NOI18N 865 logicTypeChanged(_editOperatorMode.getItemAt(_editOperatorMode.getSelectedIndex())); 866 break; 867 868 case "Variable": // NOI18N 869 updateVariable(); 870 break; 871 872 case "Action": // NOI18N 873 updateAction(); 874 break; 875 876 default: 877 log.warn("Invalid update button press"); // NOI18N 878 } 879 setEditMode(false); 880 _cdlTree.setSelectionPath(_curTreePath); 881 _cdlTree.grabFocus(); 882 } 883 884 /** 885 * Change the conditional user name. 886 * 887 * @param newName The proposed new name 888 */ 889 void userNameChanged(String newName) { 890 // Check if the User Name has been changed 891 if (!newName.equals(_curConditional.getUserName())) { 892 // user name has changed - check if already in use 893 if (!checkConditionalUserName(newName, _curLogix)) { 894 return; 895 } 896 // user name is unique or blank, change it 897 _curConditional.setUserName(newName); 898 _curNode.setText(buildNodeText("Conditional", _curConditional, 0)); // NOI18N 899 _cdlModel.nodeChanged(_curNode); 900 901 // Update any conditional references 902 ArrayList<String> refList = _conditionalManager.getWhereUsed(_curNodeName); 903 if (refList != null) { 904 for (String ref : refList) { 905 Conditional cRef = _conditionalManager.getBySystemName(ref); 906 if (cRef==null){ 907 log.error("Conditional :{}: not found while updating username",ref); 908 continue; 909 } 910 List<ConditionalVariable> varList = cRef.getCopyOfStateVariables(); 911 int idx = 0; 912 for (ConditionalVariable var : varList) { 913 // Find the affected conditional variable 914 if (var.getName().equals(_curNodeName)) { 915 if (newName.length() > 0) { 916 var.setGuiName(newName); 917 } else { 918 var.setGuiName(_curNodeName); 919 } 920 921 // Is the reference (ref) in the same Logix as the target (_curNodeName) 922 // Skip any cross conditional references 923 String varLogixName = _conditionalManager.getParentLogix(ref).getSystemName(); 924 String curLogixSName = _curLogix.getSystemName(); 925 if (varLogixName.equals(curLogixSName)) { 926 // Yes, update the tree node 927 int cdlCount = _cdlRoot.getChildCount(); 928 for (int j = 0; j < cdlCount; j++) { 929 // See if a conditional node contains a reference 930 ConditionalTreeNode cdlNode = (ConditionalTreeNode) _cdlRoot.getChildAt(j); 931 if (cdlNode.getName().equals(ref)) { 932 // The affected variable node will be down 2 levels 933 ConditionalTreeNode variables = (ConditionalTreeNode) cdlNode.getChildAt(1); 934 ConditionalTreeNode variable = (ConditionalTreeNode) variables.getChildAt(idx); 935 variable.setText(buildNodeText("Variable", var, idx)); // NOI18N 936 _cdlModel.nodeChanged(variable); 937 938 } 939 } 940 } 941 } 942 idx++; 943 } 944 // Commit the changes 945 cRef.setStateVariables(varList); 946 // Refresh the local copy in case cRef was a parallel copy 947 _variableList = _curConditional.getCopyOfStateVariables(); 948 } 949 } 950 } 951 } 952 953 /** 954 * Respond to a change of Logic Type in the dialog window by showing/hiding 955 * the _antecedentPanel when Mixed is selected. 956 * 957 * @param newType The selected logic type 958 */ 959 @SuppressFBWarnings(value = "BC_UNCONFIRMED_CAST_OF_RETURN_VALUE", justification = "Except for the root node, all nodes are ConditionalTreeNode") // NOI18N 960 void logicTypeChanged(Conditional.AntecedentOperator newType) { 961 if (_logicType == newType) { 962 return; 963 } 964 965 makeAntecedent(); 966 Operator oper; 967 if (newType != Conditional.AntecedentOperator.MIXED) { 968 oper = Conditional.Operator.OR; 969 if (newType == Conditional.AntecedentOperator.ALL_AND) { 970 oper = Conditional.Operator.AND; 971 } 972 973 // Update the variable list and tree node entries 974 ConditionalTreeNode varHead = (ConditionalTreeNode) _curNode.getPreviousSibling(); 975 for (int i = 1; i < _variableList.size(); i++) { 976 ConditionalVariable curVar = _variableList.get(i); 977 curVar.setOpern(oper); 978 979 ConditionalTreeNode varNode = (ConditionalTreeNode) varHead.getChildAt(i); 980 varNode.setText(buildNodeText("Variable", curVar, i)); 981 _cdlModel.nodeChanged(varNode); 982 } 983 } 984 985 // update LogicType entry and tree node 986 _curConditional.setLogicType(newType, _antecedent); // non-localized string to store Conditional Antecedent 987 _logicType = newType; 988 _curNode.setText(buildNodeText("LogicType", _curConditional, 0)); // NOI18N 989 _cdlModel.nodeChanged(_curNode); 990 991 // update the variables list 992 _curConditional.setStateVariables(_variableList); 993 994 // Update antecedent node text 995 ConditionalTreeNode parentNode = (ConditionalTreeNode) _curNode.getParent(); 996 ConditionalTreeNode antNode = (ConditionalTreeNode) parentNode.getFirstChild(); 997 if (antNode.getType().equals("Antecedent")) { // NOI18N 998 antNode.setText(buildNodeText("Antecedent", _curConditional, 0)); // NOI18N 999 _cdlModel.nodeChanged(antNode); 1000 } else { 1001 log.warn("Unable to find the antecedent node"); // NOI18N 1002 } 1003 } 1004 1005 /** 1006 * Update the antecedent. 1007 * 1008 * @param antecedentText the new antecedent 1009 */ 1010 void antecedentChanged(String antecedentText) { 1011 if (validateAntecedent(antecedentText)) { 1012 _antecedent = translateAntecedent(antecedentText, true); 1013 _curConditional.setLogicType(_logicType, _antecedent); 1014 _curNode.setText(buildNodeText("Antecedent", _curConditional, 0)); 1015 _cdlModel.nodeChanged(_curNode); 1016 } 1017 } 1018 1019 /** 1020 * Build the antecedent statement. 1021 */ 1022 void makeAntecedent() { 1023 _antecedent = makeAntecedent(_variableList); 1024 } 1025 1026 /** 1027 * Add a R# to the antecedent statement. 1028 */ 1029 @SuppressFBWarnings(value = "BC_UNCONFIRMED_CAST_OF_RETURN_VALUE", justification = "Except for the root node, all nodes are ConditionalTreeNode") // NOI18N 1030 void appendToAntecedent() { 1031 _antecedent = appendToAntecedent(_logicType, _variableList.size(), _antecedent); 1032 _curConditional.setLogicType(_logicType, _antecedent); 1033 1034 // Update antecedent node text 1035 ConditionalTreeNode antNode; 1036 if (_curNodeType.equals("Variables")) { // NOI18N 1037 antNode = (ConditionalTreeNode) _curNode.getPreviousSibling(); 1038 } else { 1039 antNode = (ConditionalTreeNode) ((ConditionalTreeNode) _curNode.getParent()).getPreviousSibling(); 1040 } 1041 1042 if (antNode.getType().equals("Antecedent")) { // NOI18N 1043 antNode.setText(buildNodeText("Antecedent", _curConditional, 0)); // localized display text NOI18N 1044 _cdlModel.nodeChanged(antNode); 1045 } else { 1046 log.warn("Unable to find the antecedent node"); // NOI18N 1047 } 1048 } 1049 1050 /** 1051 * Check the antecedent and logic type. 1052 * 1053 * @param antecedentText The user supplied antecedent text 1054 * @return false if antecedent can't be validated 1055 */ 1056 boolean validateAntecedent(String antecedentText) { 1057 return validateAntecedent(_logicType, antecedentText, _variableList, _curConditional); 1058 } 1059 1060 /** 1061 * Update the Actions trigger mode, adjust the Action descriptions. 1062 */ 1063 @SuppressFBWarnings(value = "BC_UNCONFIRMED_CAST_OF_RETURN_VALUE", justification = "Except for the root node, all nodes are ConditionalTreeNode") // NOI18N 1064 void togglePressed() { 1065 // Toggle the trigger mode 1066 _curLogix.deActivateLogix(); 1067 _curConditional.setTriggerOnChange(!_curConditional.getTriggerOnChange()); 1068 _triggerMode = _curConditional.getTriggerOnChange(); 1069 _curLogix.activateLogix(); 1070 1071 // Update node text 1072 _curNode.setText(buildNodeText("TriggerMode", _curConditional, 0)); // NOI18N 1073 _cdlModel.nodeChanged(_curNode); 1074 1075 // refresh the action list to get the updated action descriptions 1076 _actionList = _curConditional.getCopyOfActions(); 1077 // get next sibling and update the children node text 1078 ConditionalTreeNode actionsNode = (ConditionalTreeNode) _curNode.getNextSibling(); 1079 for (int i = 0; i < _actionList.size(); i++) { 1080 ConditionalAction action = _actionList.get(i); 1081 ConditionalTreeNode actNode = (ConditionalTreeNode) actionsNode.getChildAt(i); 1082 actNode.setText(action.description(_triggerMode)); 1083 _cdlModel.nodeChanged(actNode); 1084 } 1085 } 1086 1087 /** 1088 * Refresh the Conditional or Variable state. 1089 */ 1090 void checkPressed() { 1091 if (_curNodeType == null || _curNodeType.equals("Conditional")) { 1092 for (int i = 0; i < _cdlRoot.getChildCount(); i++) { 1093 ConditionalTreeNode cdlNode = (ConditionalTreeNode) _cdlRoot.getChildAt(i); 1094 Conditional cdl = _conditionalManager.getBySystemName(cdlNode.getName()); 1095 cdlNode.setText(buildNodeText("Conditional", cdl, i)); // NOI18N 1096 _cdlModel.nodeChanged(cdlNode); 1097 } 1098 return; 1099 } 1100 1101 if (_curNodeType.equals("Variables")) { // NOI18N 1102 for (int i = 0; i < _variableList.size(); i++) { 1103 ConditionalVariable variable = _variableList.get(i); 1104 ConditionalTreeNode varNode = (ConditionalTreeNode) _curNode.getChildAt(i); 1105 varNode.setText(buildNodeText("Variable", variable, i)); // NOI18N 1106 _cdlModel.nodeChanged(varNode); 1107 } 1108 } 1109 } 1110 1111 /** 1112 * Process the node delete request. 1113 */ 1114 @SuppressFBWarnings(value = "BC_UNCONFIRMED_CAST_OF_RETURN_VALUE", justification = "Except for the root node, all nodes are ConditionalTreeNode") // NOI18N 1115 void deletePressed() { 1116 TreePath parentPath; 1117 ConditionalTreeNode parentNode; 1118 TreeSet<String> oldTargetNames = new TreeSet<>(); 1119 TreeSet<String> newTargetNames = new TreeSet<>(); 1120 setEditMode(false); 1121 1122 // Conditional 1123 switch (_curNodeType) { 1124 case "Conditional": // NOI18N 1125 loadReferenceNames(_variableList, oldTargetNames); 1126 // Delete the conditional. 1127 _curLogix.deActivateLogix(); 1128 String[] msgs = _curLogix.deleteConditional(_curNodeName); 1129 _curLogix.activateLogix(); 1130 if (msgs != null) { 1131 // Unable to delete due to existing conditional references 1132 JmriJOptionPane.showMessageDialog(_editLogixFrame, 1133 Bundle.getMessage("Error11", (Object[]) msgs), // NOI18N 1134 Bundle.getMessage("ErrorTitle"), 1135 JmriJOptionPane.ERROR_MESSAGE); // NOI18N 1136 return; 1137 } 1138 updateWhereUsed(oldTargetNames, newTargetNames, _curNodeName); 1139 _showReminder = true; 1140 1141 // Update the tree 1142 _cdlRoot.remove(_curNodeRow); 1143 _cdlModel.nodeStructureChanged(_cdlRoot); 1144 1145 // Update the row numbers 1146 int childCount = _cdlRoot.getChildCount(); 1147 for (int i = 0; i < childCount; i++) { 1148 _curNode = (ConditionalTreeNode) _cdlRoot.getChildAt(i); 1149 _curNode.setRow(i); 1150 _cdlModel.nodeChanged(_curNode); 1151 } 1152 1153 if (_curLogix.getNumConditionals() < 1 && !_suppressReminder) { 1154 // warning message - last Conditional deleted 1155 JmriJOptionPane.showMessageDialog(_editLogixFrame, 1156 Bundle.getMessage("Warn1"), Bundle.getMessage("WarningTitle"), // NOI18N 1157 JmriJOptionPane.WARNING_MESSAGE); 1158 } 1159 setMoveButtons(); 1160 break; 1161 1162 case "Variable": // NOI18N 1163 loadReferenceNames(_variableList, oldTargetNames); 1164 if (_variableList.size() < 2 && !_suppressReminder) { 1165 // warning message - last State Variable deleted 1166 JmriJOptionPane.showMessageDialog(_editLogixFrame, 1167 Bundle.getMessage("Warn3"), Bundle.getMessage("WarningTitle"), // NOI18N 1168 JmriJOptionPane.WARNING_MESSAGE); 1169 } 1170 1171 // Adjust operator 1172 if (_curNodeRow == 0 && _variableList.size() > 1) { 1173 _variableList.get(1).setOpern(Conditional.Operator.NONE); 1174 } 1175 1176 // Remove the row, update and refresh the Variable list, update references 1177 _variableList.remove(_curNodeRow); 1178 updateVariableList(); 1179 loadReferenceNames(_variableList, newTargetNames); 1180 updateWhereUsed(oldTargetNames, newTargetNames, _curNodeName); 1181 _showReminder = true; 1182 1183 // Update the tree components 1184 parentPath = _curTreePath.getParentPath(); 1185 parentNode = (ConditionalTreeNode) _curNode.getParent(); 1186 parentNode.setRow(_variableList.size()); 1187 _cdlModel.nodeChanged(parentNode); 1188 1189 // Update the antecedent 1190 _curNode = (ConditionalTreeNode) parentNode.getPreviousSibling(); 1191 antecedentChanged(""); 1192 1193 // Update the variable children 1194 parentNode.removeAllChildren(); 1195 for (int v = 0; v < _variableList.size(); v++) { 1196 ConditionalVariable variable = _variableList.get(v); 1197 _leafNode = new ConditionalTreeNode(buildNodeText("Variable", variable, v), // NOI18N 1198 "Variable", _curNodeName, v); // NOI18N 1199 parentNode.add(_leafNode); 1200 } 1201 1202 _curNode = null; 1203 _newVariableItem = false; 1204 cleanUpVariable(); 1205 1206 _cdlModel.nodeStructureChanged(parentNode); 1207 _cdlTree.setSelectionPath(parentPath); 1208 break; 1209 1210 case "Action": // NOI18N 1211 // Remove the row, update and refresh the Action list 1212 removeActionTimers(); 1213 _actionList.remove(_curNodeRow); 1214 updateActionList(); 1215 _showReminder = true; 1216 1217 // Update the tree components 1218 parentPath = _curTreePath.getParentPath(); 1219 parentNode = (ConditionalTreeNode) _curNode.getParent(); 1220 parentNode.setRow(_actionList.size()); 1221 _cdlModel.nodeChanged(parentNode); 1222 parentNode.removeAllChildren(); 1223 for (int a = 0; a < _actionList.size(); a++) { 1224 ConditionalAction action = _actionList.get(a); 1225 _leafNode = new ConditionalTreeNode(buildNodeText("Action", action, a), // NOI18N 1226 "Action", _curNodeName, a); // NOI18N 1227 parentNode.add(_leafNode); 1228 } 1229 1230 _curNode = null; 1231 _newActionItem = false; 1232 cleanUpAction(); 1233 1234 _cdlModel.nodeStructureChanged(parentNode); 1235 _cdlTree.setSelectionPath(parentPath); 1236 break; 1237 1238 default: 1239 log.error("Delete called for unsupported node type: '{}'", _curNodeType); // NOI18N 1240 } 1241 } 1242 1243 /** 1244 * Move a conditional, variable or action row up 1 row. 1245 */ 1246 void upPressed() { 1247 _showReminder = true; 1248 1249 switch (_curNodeType) { 1250 case "Conditional": // NOI18N 1251 // Update Logix index 1252 _curLogix.deActivateLogix(); 1253 _curLogix.swapConditional(_curNodeRow - 1, _curNodeRow); 1254 _curLogix.activateLogix(); 1255 moveTreeNode("Up"); // NOI18N 1256 break; 1257 1258 case "Variable": // NOI18N 1259 ConditionalVariable tempVar = _variableList.get(_curNodeRow); 1260 int newVarRow = _curNodeRow - 1; 1261 _variableList.set(_curNodeRow, _variableList.get(newVarRow)); 1262 _variableList.set(newVarRow, tempVar); 1263 // Adjust operator 1264 if (newVarRow == 0) { 1265 _variableList.get(newVarRow).setOpern(Conditional.Operator.NONE); 1266 Operator newOper = (_logicType == Conditional.AntecedentOperator.ALL_AND) 1267 ? Conditional.Operator.AND : Conditional.Operator.OR; 1268 _variableList.get(_curNodeRow).setOpern(newOper); 1269 } 1270 updateVariableList(); 1271 moveTreeNode("Up"); // NOI18N 1272 break; 1273 1274 case "Action": // NOI18N 1275 ConditionalAction tempAct = _actionList.get(_curNodeRow); 1276 int newActRow = _curNodeRow - 1; 1277 _actionList.set(_curNodeRow, _actionList.get(newActRow)); 1278 _actionList.set(newActRow, tempAct); 1279 removeActionTimers(); 1280 updateActionList(); 1281 moveTreeNode("Up"); // NOI18N 1282 break; 1283 1284 default: 1285 log.warn("Move Up called for unsupported node type: '{}'", _curNodeType); // NOI18N 1286 } 1287 } 1288 1289 /** 1290 * Move a conditional, variable or action row down 1 row. 1291 */ 1292 void downPressed() { 1293 _showReminder = true; 1294 1295 switch (_curNodeType) { 1296 case "Conditional": // NOI18N 1297 _curLogix.deActivateLogix(); 1298 _curLogix.swapConditional(_curNodeRow, _curNodeRow + 1); 1299 _curLogix.activateLogix(); 1300 moveTreeNode("Down"); // NOI18N 1301 break; 1302 1303 case "Variable": // NOI18N 1304 ConditionalVariable tempVar = _variableList.get(_curNodeRow); 1305 int newVarRow = _curNodeRow + 1; 1306 _variableList.set(_curNodeRow, _variableList.get(newVarRow)); 1307 _variableList.set(newVarRow, tempVar); 1308 // Adjust operator 1309 if (_curNodeRow == 0) { 1310 _variableList.get(_curNodeRow).setOpern(Conditional.Operator.NONE); 1311 Operator newOper = (_logicType == Conditional.AntecedentOperator.ALL_AND) 1312 ? Conditional.Operator.AND : Conditional.Operator.OR; 1313 _variableList.get(newVarRow).setOpern(newOper); 1314 } 1315 updateVariableList(); 1316 moveTreeNode("Down"); // NOI18N 1317 break; 1318 1319 case "Action": // NOI18N 1320 ConditionalAction tempAct = _actionList.get(_curNodeRow); 1321 int newActRow = _curNodeRow + 1; 1322 _actionList.set(_curNodeRow, _actionList.get(newActRow)); 1323 _actionList.set(newActRow, tempAct); 1324 removeActionTimers(); 1325 updateActionList(); 1326 moveTreeNode("Down"); // NOI18N 1327 break; 1328 1329 default: 1330 log.warn("Move Down called for unsupported node type: '{}'", _curNodeType); // NOI18N 1331 } 1332 } 1333 1334 /** 1335 * Remove Action timers and listeners before Action list structure changes. 1336 * This relates to moving and deleting rows. New actions at the end are not problem. 1337 * The issue is that the timer listeners are tied to the action row number. 1338 * This can result in orphan timers and listeners that keep running. 1339 * @since 4.11.2 1340 */ 1341 void removeActionTimers() { 1342 // Use the real list, not a copy. 1343 DefaultConditional cdl = (DefaultConditional) _curConditional; 1344 for (ConditionalAction act : cdl.getActionList()) { 1345 if (act.getTimer() != null) { 1346 act.stopTimer(); 1347 act.setTimer(null); 1348 act.setListener(null); 1349 } 1350 } 1351 } 1352 1353 /** 1354 * Move a tree node in response to a up or down request. 1355 * 1356 * @param direction The direction of movement, Up or Down 1357 */ 1358 @SuppressFBWarnings(value = "BC_UNCONFIRMED_CAST_OF_RETURN_VALUE", justification = "Except for the root node, all nodes are ConditionalTreeNode") // NOI18N 1359 void moveTreeNode(String direction) { 1360 // Update the node 1361 int oldRow = _curNodeRow; 1362 if (direction.equals("Up")) { // NOI18N 1363 _curNodeRow -= 1; 1364 } else { 1365 _curNodeRow += 1; 1366 } 1367 _curNode.setRow(_curNodeRow); 1368 if (_curNodeType.equals("Variable")) { // NOI18N 1369 _curNode.setText(buildNodeText("Variable", _variableList.get(_curNodeRow), _curNodeRow)); // NOI18N 1370 } 1371 _cdlModel.nodeChanged(_curNode); 1372 1373 // Update the sibling 1374 ConditionalTreeNode siblingNode; 1375 if (direction.equals("Up")) { // NOI18N 1376 siblingNode = (ConditionalTreeNode) _curNode.getPreviousSibling(); 1377 siblingNode.setRow(siblingNode.getRow() + 1); 1378 } else { 1379 siblingNode = (ConditionalTreeNode) _curNode.getNextSibling(); 1380 siblingNode.setRow(siblingNode.getRow() - 1); 1381 } 1382 if (_curNodeType.equals("Variable")) { // NOI18N 1383 siblingNode.setText(buildNodeText("Variable", _variableList.get(oldRow), oldRow)); // NOI18N 1384 } 1385 _cdlModel.nodeChanged(siblingNode); 1386 1387 // Update the tree 1388 if (_curNodeType.equals("Conditional")) { // NOI18N 1389 _cdlRoot.insert(_curNode, _curNodeRow); 1390 _cdlModel.nodeStructureChanged(_cdlRoot); 1391 } else { 1392 ConditionalTreeNode parentNode = (ConditionalTreeNode) _curNode.getParent(); 1393 parentNode.insert(_curNode, _curNodeRow); 1394 _cdlModel.nodeStructureChanged(parentNode); 1395 } 1396 _cdlTree.setSelectionPath(new TreePath(_curNode.getPath())); 1397 setMoveButtons(); 1398 } 1399 1400 /** 1401 * Enable/Disable the Up and Down buttons based on the postion in the list. 1402 */ 1403 void setMoveButtons() { 1404 if (_curNode == null) { 1405 return; 1406 } 1407 1408 Component[] compList = _moveButtonPanel.getComponents(); 1409 JButton up = (JButton) compList[1]; 1410 JButton down = (JButton) compList[3]; 1411 1412 up.setEnabled(true); 1413 down.setEnabled(true); 1414 1415 int rows; 1416 if (_curNodeType.equals("Conditional")) { // NOI18N 1417 rows = _curLogix.getNumConditionals(); 1418 } else { 1419 ConditionalTreeNode parent = (ConditionalTreeNode) _curNode.getParent(); 1420 rows = parent.getRow(); 1421 } 1422 1423 if (_curNodeRow < 1) { 1424 up.setEnabled(false); 1425 } 1426 if (_curNodeRow >= rows - 1) { 1427 down.setEnabled(false); 1428 } 1429 1430 // Disable move buttons during Variable or Action add or edit processing, or nothing selected 1431 if ((_newVariableItem && _curNodeType.equals("Variable")) // NOI18N 1432 || (_newActionItem && _curNodeType.equals("Action")) 1433 || (_editActive) 1434 || (_cdlTree.getSelectionCount() == 0)) { // NOI18N 1435 up.setEnabled(false); 1436 down.setEnabled(false); 1437 } 1438 1439 _moveButtonPanel.setVisible(true); 1440 } 1441 1442 /** 1443 * Respond to Help button press in the Edit Logix menu bar. Only visible when 1444 * using mixed mode and an antecedent node is selected. 1445 */ 1446 void helpPressed() { 1447 JmriJOptionPane.showMessageDialog(null, 1448 new String[]{ 1449 Bundle.getMessage("ConditionalHelpText1"), // NOI18N 1450 Bundle.getMessage("ConditionalHelpText2"), // NOI18N 1451 Bundle.getMessage("ConditionalHelpText3"), // NOI18N 1452 Bundle.getMessage("ConditionalHelpText4"), // NOI18N 1453 Bundle.getMessage("ConditionalHelpText5"), // NOI18N 1454 Bundle.getMessage("ConditionalHelpText6"), // NOI18N 1455 Bundle.getMessage("ConditionalHelpText7") // NOI18N 1456 }, 1457 Bundle.getMessage("MenuHelp"), JmriJOptionPane.INFORMATION_MESSAGE); // NOI18N 1458 } 1459 1460 /** 1461 * Cancel the current node edit. 1462 */ 1463 void cancelPressed() { 1464 switch (_curNodeType) { 1465 case "Variable": // NOI18N 1466 cancelEditVariable(); 1467 break; 1468 1469 case "Action": // NOI18N 1470 cancelEditAction(); 1471 break; 1472 1473 default: 1474 break; 1475 } 1476 makeDetailGrid("EmptyGrid"); // NOI18N 1477 setEditMode(false); 1478 _cdlTree.setSelectionPath(_curTreePath); 1479 _cdlTree.grabFocus(); 1480 } 1481 1482 /** 1483 * Clean up, notify the parent Logix that edit session is done. 1484 */ 1485 void donePressed() { 1486 showSaveReminder(); 1487 if (_curNodeType != null) { 1488 switch (_curNodeType) { 1489 case "Variable": // NOI18N 1490 cancelEditVariable(); 1491 break; 1492 1493 case "Action": // NOI18N 1494 cancelEditAction(); 1495 break; 1496 1497 default: 1498 break; 1499 } 1500 } 1501 closeSinglePanelPickList(); 1502 if (_pickTables != null) { 1503 _pickTables.dispose(); 1504 _pickTables = null; 1505 } 1506 1507 _editLogixFrame.setVisible(false); 1508 _editLogixFrame.dispose(); 1509 _editLogixFrame = null; 1510 1511 logixData.clear(); 1512 logixData.put("Finish", _curLogix.getSystemName()); // NOI18N 1513 fireLogixEvent(); 1514 } 1515 1516 // ============ Tree Content and Navigation ============ 1517 1518 /** 1519 * Create the conditional tree structure using the current Logix. 1520 * 1521 * @return _cdlTree The tree ddefinition with its content 1522 */ 1523 JTree buildConditionalTree() { 1524 _cdlRoot = new DefaultMutableTreeNode("Root Node"); // NOI18N 1525 _cdlModel = new DefaultTreeModel(_cdlRoot); 1526 _cdlTree = new JTree(_cdlModel); 1527 1528 createConditionalContent(); 1529 1530 // build the tree GUI 1531 _cdlTree.expandPath(new TreePath(_cdlRoot)); 1532 _cdlTree.setRootVisible(false); 1533 _cdlTree.setShowsRootHandles(true); 1534 _cdlTree.setScrollsOnExpand(true); 1535 _cdlTree.setExpandsSelectedPaths(true); 1536 _cdlTree.getSelectionModel().setSelectionMode(DefaultTreeSelectionModel.SINGLE_TREE_SELECTION); 1537 1538 // tree listeners 1539 _cdlTree.addTreeSelectionListener(_cdlListener = new TreeSelectionListener() { 1540 @Override 1541 public void valueChanged(TreeSelectionEvent e) { 1542 if (_editActive) { 1543 if (e.getNewLeadSelectionPath() != _curTreePath) { 1544 _cdlTree.setSelectionPath(e.getOldLeadSelectionPath()); 1545 showNodeEditMessage(); 1546 } 1547 return; 1548 } 1549 1550 _curTreePath = _cdlTree.getSelectionPath(); 1551 if (_curTreePath != null) { 1552 Object chkLast = _curTreePath.getLastPathComponent(); 1553 if (chkLast instanceof ConditionalTreeNode) { 1554 treeRowSelected((ConditionalTreeNode) chkLast); 1555 } 1556 } 1557 } 1558 }); 1559 1560 _cdlTree.addTreeExpansionListener(new TreeExpansionListener() { 1561 @Override 1562 public void treeExpanded(TreeExpansionEvent e) { 1563 ConditionalTreeNode checkNode = (ConditionalTreeNode) e.getPath().getLastPathComponent(); 1564 if (checkNode.getType().equals("Variables")) { // NOI18N 1565 // Include the field descriptions in the node name 1566 checkNode.setText(buildNodeText("Variables", _curConditional, 1)); // NOI18N 1567 _cdlModel.nodeChanged(checkNode); 1568 } 1569 } 1570 1571 @Override 1572 public void treeCollapsed(TreeExpansionEvent e) { 1573 ConditionalTreeNode checkNode = (ConditionalTreeNode) e.getPath().getLastPathComponent(); 1574 if (checkNode.getType().equals("Variables")) { // NOI18N 1575 // Remove the field descriptions from the node name 1576 checkNode.setText(buildNodeText("Variables", _curConditional, 0)); // NOI18N 1577 _cdlModel.nodeChanged(checkNode); 1578 } 1579 1580 if (_cdlTree.getSelectionCount() == 0) { 1581 makeDetailGrid("EmptyGrid"); // NOI18N 1582 } 1583 } 1584 }); 1585 1586 return _cdlTree; 1587 } 1588 1589 /** 1590 * Create the tree content. Level 1 are the conditionals, Level 2 includes the 1591 * antecedent, logic type, trigger mode and parent nodes for Variables and 1592 * Actions, Level 3 contains the detail Variable and Action entries. 1593 */ 1594 void createConditionalContent() { 1595 int numConditionals = _curLogix.getNumConditionals(); 1596 for (int i = 0; i < numConditionals; i++) { 1597 String csName = _curLogix.getConditionalByNumberOrder(i); 1598 Conditional curConditional = _curLogix.getConditional(csName); 1599 _cdlNode = new ConditionalTreeNode(buildNodeText("Conditional", curConditional, 0), "Conditional", csName, i); // NOI18N 1600 _cdlRoot.add(_cdlNode); 1601 1602 _leafNode = new ConditionalTreeNode(buildNodeText("Antecedent", curConditional, 0), "Antecedent", csName, 0); // NOI18N 1603 _cdlNode.add(_leafNode); 1604 1605 _variableList = curConditional.getCopyOfStateVariables(); 1606 int varCount = _variableList.size(); 1607 _varHead = new ConditionalTreeNode(buildNodeText("Variables", _curConditional, 0), "Variables", csName, varCount); // NOI18N 1608 _cdlNode.add(_varHead); 1609 for (int v = 0; v < _variableList.size(); v++) { 1610 ConditionalVariable variable = _variableList.get(v); 1611 _leafNode = new ConditionalTreeNode(buildNodeText("Variable", variable, v), "Variable", csName, v); 1612 _varHead.add(_leafNode); 1613 } 1614 1615 _leafNode = new ConditionalTreeNode(buildNodeText("LogicType", curConditional, 0), "LogicType", csName, 0); // NOI18N 1616 _cdlNode.add(_leafNode); 1617 1618 boolean triggerMode = curConditional.getTriggerOnChange(); 1619 _leafNode = new ConditionalTreeNode(buildNodeText("TriggerMode", curConditional, 0), "TriggerMode", csName, 0); // NOI18N 1620 _cdlNode.add(_leafNode); 1621 1622 _actionList = curConditional.getCopyOfActions(); 1623 int actCount = _actionList.size(); 1624 _actHead = new ConditionalTreeNode("Actions", "Actions", csName, actCount); // NOI18N 1625 _cdlNode.add(_actHead); 1626 for (int a = 0; a < _actionList.size(); a++) { 1627 ConditionalAction action = _actionList.get(a); 1628 _leafNode = new ConditionalTreeNode(action.description(triggerMode), "Action", csName, a); // NOI18N 1629 _actHead.add(_leafNode); 1630 } 1631 } 1632 } 1633 1634 /** 1635 * Change the button row based on the currently selected node type. Invoke 1636 * edit where appropriate. 1637 * 1638 * @param selectedNode The node object 1639 */ 1640 void treeRowSelected(ConditionalTreeNode selectedNode) { 1641 // Set the current node variables 1642 _curNode = selectedNode; 1643 _curNodeName = selectedNode.getName(); 1644 _curNodeType = selectedNode.getType(); 1645 _curNodeText = selectedNode.getText(); 1646 _curNodeRow = selectedNode.getRow(); 1647 1648 // Set the current conditional variables if different conditional 1649 if (!_curConditionalName.equals(_curNodeName)) { 1650 _curConditional = _conditionalManager.getConditional(_curNodeName); 1651 _antecedent = _curConditional.getAntecedentExpression(); 1652 _logicType = _curConditional.getLogicType(); 1653 _triggerMode = _curConditional.getTriggerOnChange(); 1654 _variableList = _curConditional.getCopyOfStateVariables(); 1655 _actionList = _curConditional.getCopyOfActions(); 1656 _curConditionalName = _curNodeName; 1657 } 1658 1659 // Reset button bar 1660 _addButtonPanel.setVisible(false); 1661 _checkButtonPanel.setVisible(false); 1662 _toggleButtonPanel.setVisible(false); 1663 _moveButtonPanel.setVisible(false); 1664 _deleteButtonPanel.setVisible(false); 1665 _helpButtonPanel.setVisible(false); 1666 1667 _labelPanel.removeAll(); 1668 switch (_curNodeType) { 1669 case "Conditional": // NOI18N 1670 _labelPanel.add(_conditionalLabel); 1671 _addButtonPanel.setVisible(true); 1672 _checkButtonPanel.setVisible(true); 1673 _deleteButtonPanel.setVisible(true); 1674 setMoveButtons(); 1675 editPressed(); 1676 break; 1677 1678 case "Antecedent": // NOI18N 1679 editPressed(); 1680 break; 1681 1682 case "LogicType": // NOI18N 1683 editPressed(); 1684 break; 1685 1686 case "TriggerMode": // NOI18N 1687 _labelPanel.add(_triggerModeLabel); 1688 _toggleButtonPanel.setVisible(true); 1689 makeDetailGrid("EmptyGrid"); // NOI18N 1690 break; 1691 1692 case "Variables": // NOI18N 1693 _labelPanel.add(_variablesLabel); 1694 _addButtonPanel.setVisible(true); 1695 _checkButtonPanel.setVisible(true); 1696 makeDetailGrid("EmptyGrid"); // NOI18N 1697 break; 1698 1699 case "Variable": // NOI18N 1700 _labelPanel.add(_variableLabel); 1701 _addButtonPanel.setVisible(true); 1702 _deleteButtonPanel.setVisible(true); 1703 if (_logicType != Conditional.AntecedentOperator.MIXED) { 1704 setMoveButtons(); 1705 } 1706 editPressed(); 1707 break; 1708 1709 case "Actions": // NOI18N 1710 _labelPanel.add(_actionsLabel); 1711 _addButtonPanel.setVisible(true); 1712 makeDetailGrid("EmptyGrid"); // NOI18N 1713 break; 1714 1715 case "Action": // NOI18N 1716 _labelPanel.add(_actionLabel); 1717 _addButtonPanel.setVisible(true); 1718 _deleteButtonPanel.setVisible(true); 1719 setMoveButtons(); 1720 editPressed(); 1721 break; 1722 1723 default: 1724 log.warn("Should not be here"); // NOI18N 1725 } 1726 } 1727 1728 /** 1729 * Create the localized node text display strings based on node type. 1730 * 1731 * @param nodeType The type of the node 1732 * @param component The conditional object or child object 1733 * @param idx Optional index value 1734 * @return nodeText containing the text to display on the node 1735 */ 1736 String buildNodeText(String nodeType, Object component, int idx) { 1737 Conditional cdl; 1738 ConditionalAction act; 1739 ConditionalVariable var; 1740 1741 switch (nodeType) { 1742 case "Conditional": // NOI18N 1743 cdl = (Conditional) component; 1744 String cdlStatus = (cdl.getState() == Conditional.TRUE) 1745 ? Bundle.getMessage("True") // NOI18N 1746 : Bundle.getMessage("False"); // NOI18N 1747 String cdlNames = cdl.getSystemName() + " -- " + cdl.getUserName(); 1748 String cdlFill = StringUtils.repeat(" ", 5); // NOI18N 1749 String cdlLine = "<html>" + cdlNames + cdlFill + "<strong>[ " + cdlStatus + " ]</strong></html>"; // NOI18N 1750 return cdlLine; 1751 1752 case "Antecedent": // NOI18N 1753 cdl = (Conditional) component; 1754 String antecedent = translateAntecedent(cdl.getAntecedentExpression(), false); 1755 if (cdl.getLogicType() != Conditional.AntecedentOperator.MIXED) { 1756 antecedent = "- - - - - - - - -"; 1757 } 1758 return Bundle.getMessage("LogixAntecedent") + " " + antecedent; // NOI18N 1759 1760 case "LogicType": // NOI18N 1761 cdl = (Conditional) component; 1762 Conditional.AntecedentOperator logicType = cdl.getLogicType(); 1763 String logicName; // used for display only 1764 switch (logicType) { 1765 case ALL_AND: 1766 logicName = Bundle.getMessage("LogicAND"); // NOI18N 1767 break; 1768 case ALL_OR: 1769 logicName = Bundle.getMessage("LogicOR"); // NOI18N 1770 break; 1771 case MIXED: 1772 logicName = Bundle.getMessage("LogicMixed"); // NOI18N 1773 break; 1774 default: 1775 logicName = "None"; // only used for invalid LogicType 1776 } 1777 return Bundle.getMessage("LabelLogicTypeActions") + " " + logicName; // NOI18N 1778 1779 case "TriggerMode": // NOI18N 1780 cdl = (Conditional) component; 1781 boolean triggerMode = cdl.getTriggerOnChange(); 1782 String triggerText; 1783 if (triggerMode) { 1784 triggerText = Bundle.getMessage("triggerOnChange"); // NOI18N 1785 } else { 1786 triggerText = Bundle.getMessage("triggerOnAny"); // NOI18N 1787 } 1788 return Bundle.getMessage("LabelTriggerModeActions") + " " + triggerText; // NOI18N 1789 1790 case "Variables": // NOI18N 1791 if (idx == 0) { 1792 // The node is not expanded, return plain content 1793 return Bundle.getMessage("NodeVariablesCollapsed"); // NOI18N 1794 } else { 1795 // The node is expanded, include the field names 1796 return String.format("%s [[ %s || %s || %s ]]", // NOI18N 1797 Bundle.getMessage("NodeVariablesExpanded"), // NOI18N 1798 Bundle.getMessage("ColumnLabelDescription"), // NOI18N 1799 Bundle.getMessage("ColumnLabelTriggersCalculation"), // NOI18N 1800 Bundle.getMessage("ColumnState")); // NOI18N 1801 } 1802 1803 case "Variable": // NOI18N 1804 var = (ConditionalVariable) component; 1805 1806 String rowNum = "R" + (idx + 1) + (idx > 9 ? " " : " "); // NOI18N 1807 String rowOper = var.getOpernString() + " "; 1808 1809 String rowNot = ""; 1810 if (var.isNegated()) { 1811 rowNot = Bundle.getMessage("LogicNOT") + " "; // NOI18N 1812 } 1813 1814 String boldFormat = " || <strong>%s</strong>"; // NOI18N 1815 String rowTrigger = String.format(boldFormat, 1816 (var.doTriggerActions()) ? Bundle.getMessage("ButtonYes") : Bundle.getMessage("ButtonNo")); // NOI18N 1817 String rowStatus = String.format(boldFormat, 1818 (var.evaluate()) ? Bundle.getMessage("True") : Bundle.getMessage("False")); // NOI18N 1819 1820 String varLine = "<html>" + rowNum + rowOper + rowNot + var.toString() + rowTrigger + rowStatus + "</html>"; // NOI18N 1821 return varLine; 1822 1823 case "Actions": // NOI18N 1824 return Bundle.getMessage("NodeActions"); // NOI18N 1825 1826 case "Action": // NOI18N 1827 act = (ConditionalAction) component; 1828 return act.description(_triggerMode); 1829 1830 default: 1831 return "None"; 1832 } 1833 } 1834 1835 /** 1836 * Display reminder to finish a node before starting another. This is a session reminder. 1837 */ 1838 void showNodeEditMessage() { 1839 if (InstanceManager.getNullableDefault(jmri.UserPreferencesManager.class) != null) { 1840 InstanceManager.getDefault(jmri.UserPreferencesManager.class). 1841 showInfoMessage(Bundle.getMessage("NodeEditTitle"), // NOI18N 1842 Bundle.getMessage("NodeEditText"), // NOI18N 1843 getClassName(), 1844 "SkipNodeEditMessage", // NOI18N 1845 true, 1846 false); 1847 } 1848 } 1849 1850 /** 1851 * Focus gained implies intent to make changes, set up for edit. 1852 */ 1853 transient FocusListener detailFocusEvent = new FocusListener() { 1854 @Override 1855 public void focusGained(FocusEvent e) { 1856 if (!_editActive) { 1857 setEditMode(true); 1858 } 1859 } 1860 1861 @Override 1862 public void focusLost(FocusEvent e) { 1863 } 1864 }; 1865 1866 /** 1867 * Add the focus listener to each detail edit field. 1868 */ 1869 void setFocusListeners() { 1870 _editConditionalUserName.addFocusListener(detailFocusEvent); 1871 _editAntecedent.addFocusListener(detailFocusEvent); 1872 _editOperatorMode.addFocusListener(detailFocusEvent); 1873 _variableItemBox.addFocusListener(detailFocusEvent); 1874 _variableOperBox.addFocusListener(detailFocusEvent); 1875 _variableNegated.addFocusListener(detailFocusEvent); 1876 _variableTriggerActions.addFocusListener(detailFocusEvent); 1877 _variableNameField.addFocusListener(detailFocusEvent); 1878 _variableStateBox.addFocusListener(detailFocusEvent); 1879 _variableSignalBox.addFocusListener(detailFocusEvent); 1880 _selectLogixBox.addFocusListener(detailFocusEvent); 1881 _selectConditionalBox.addFocusListener(detailFocusEvent); 1882 _variableCompareOpBox.addFocusListener(detailFocusEvent); 1883 _variableCompareTypeBox.addFocusListener(detailFocusEvent); 1884 _variableData1Field.addFocusListener(detailFocusEvent); 1885 _variableData2Field.addFocusListener(detailFocusEvent); 1886 _actionItemBox.addFocusListener(detailFocusEvent); 1887 _actionNameField.addFocusListener(detailFocusEvent); 1888 _actionTypeBox.addFocusListener(detailFocusEvent); 1889 _actionBox.addFocusListener(detailFocusEvent); 1890 _shortActionString.addFocusListener(detailFocusEvent); 1891 _longActionString.addFocusListener(detailFocusEvent); 1892 _actionSetButton.addFocusListener(detailFocusEvent); 1893 _actionOptionBox.addFocusListener(detailFocusEvent); 1894 } 1895 1896 /** 1897 * Enable/disable buttons based on edit state. 1898 * Open pick lists based on the current SelectionMode. 1899 * The edit state controls the ability to select tree nodes. 1900 * 1901 * @param active True to make edit active, false to make edit inactive 1902 */ 1903 void setEditMode(boolean active) { 1904 _editActive = active; 1905 _cancelAction.setEnabled(active); 1906 _updateAction.setEnabled(active); 1907 Component delButton = _deleteButtonPanel.getComponent(0); 1908 if (delButton instanceof JButton) { 1909 delButton.setEnabled(!active); 1910 } 1911 Component addButton = _addButtonPanel.getComponent(0); 1912 if (addButton instanceof JButton) { 1913 addButton.setEnabled(!active); 1914 } 1915 if (_curNodeType != null) { 1916 if (_curNodeType.equals("Conditional") || _curNodeType.equals("Variable") || _curNodeType.equals("Action")) { // NOI18N 1917 setMoveButtons(); 1918 } 1919 } 1920 if (active) { 1921 setPickWindow("Activate", Conditional.ItemType.NONE); // NOI18N 1922 } else { 1923 setPickWindow("Deactivate", Conditional.ItemType.NONE); // NOI18N 1924 } 1925 } 1926 1927 /** 1928 * Ceate tabbed Pick Taba;e or Pick Single based on Selection Mode. 1929 * Called by {@link #setEditMode} when edit mode becomes active. 1930 * Called by {@link #variableTypeChanged} and {@link #actionItemChanged} when item type changes. 1931 * 1932 * @param cmd The source or action to be performed. 1933 * @param item The item type for Variable or Action or zero 1934 */ 1935 void setPickWindow(String cmd, Conditional.ItemType item) { 1936 if (_selectionMode == SelectionMode.USECOMBO) { 1937 return; 1938 } 1939 // Save the item information 1940 if (cmd.equals("Variable") || cmd.equals("Action")) { // NOI18N 1941 _pickCommand = cmd; 1942 _pickItem = item; 1943 if (_editActive) { 1944 if (_selectionMode == SelectionMode.USEMULTI) { 1945 doPickList(); 1946 } else { 1947 doPickSingle(); 1948 } 1949 } 1950 } 1951 if (cmd.equals("Activate")) { // NOI18N 1952 if (_curNodeType.equals("Variable") || _curNodeType.equals("Action")) { // NOI18N 1953 // Open the appropriate window based on the save values 1954 if (_selectionMode == SelectionMode.USEMULTI) { 1955 doPickList(); 1956 } else { 1957 doPickSingle(); 1958 } 1959 } 1960 } 1961 if (cmd.equals("Deactivate")) { // NOI18N 1962 // Close/dispose the pick window 1963 hidePickListTable(); 1964 closeSinglePanelPickList(); 1965 } 1966 } 1967 1968 /** 1969 * Create a Variable or Action based tabbed PickList with appropriate tab selected. 1970 */ 1971 void doPickList() { 1972 if (_pickItem == Conditional.ItemType.NONE) { 1973 return; 1974 } 1975 if (_pickTables == null) { 1976 openPickListTable(); 1977 } 1978 if (_pickCommand.equals("Variable")) { 1979 setPickListTab(_pickItem, false); 1980 } else if (_pickCommand.equals("Action")) { 1981 setPickListTab(_pickItem, true); 1982 } 1983 } 1984 1985 /** 1986 * Create a Variable or Action based single pane PickList. 1987 */ 1988 void doPickSingle() { 1989 if (_pickCommand.equals("Variable")) { 1990 createSinglePanelPickList(_pickItem, new PickSingleListener(_variableNameField, _pickItem), false); 1991 } else if (_pickCommand.equals("Action")) { 1992 createSinglePanelPickList(_pickItem, new PickSingleListener(_actionNameField, _pickItem), true); 1993 } 1994 } 1995 1996 // ============ Edit Variable Section ============ 1997 1998 /** 1999 * Called once during class initialization to define the GUI objects. Where 2000 * possible, the combo box content is loaded. 2001 */ 2002 void buildVariableComponents() { 2003 // Item Type 2004 _variableItemBox = new JComboBox<>(); 2005 for (Conditional.ItemType itemType : Conditional.ItemType.getStateVarList()) { 2006 _variableItemBox.addItem(itemType); 2007 } 2008 JComboBoxUtil.setupComboBoxMaxRows(_variableItemBox); 2009 _variableItemBox.addActionListener(new ActionListener() { 2010 @Override 2011 public void actionPerformed(ActionEvent e) { 2012 Conditional.ItemType newVariableItem = _variableItemBox.getItemAt(_variableItemBox.getSelectedIndex()); 2013 if (log.isDebugEnabled()) { 2014 log.debug("_variableItemBox Listener: new = {}, curr = {}, row = {}", // NOI18N 2015 newVariableItem, _curVariableItem, _curNodeRow); 2016 } 2017 if (newVariableItem != _curVariableItem) { 2018 if (_curNodeRow >= 0) { 2019 _curVariable = new ConditionalVariable(); 2020 _variableList.set(_curNodeRow, _curVariable); 2021 } 2022 _curVariableItem = newVariableItem; 2023 } 2024 variableTypeChanged(newVariableItem); 2025 } 2026 }); 2027 2028 // Oper type 2029 _variableOperBox = new JComboBox<String>(); 2030 _variableOperBox.addItem(Bundle.getMessage("LogicAND")); // NOI18N 2031 _variableOperBox.addItem(Bundle.getMessage("LogicOR")); // NOI18N 2032 2033 // Negation 2034 _variableNegated = new JCheckBox(); 2035 2036 // trigger 2037 _variableTriggerActions = new JCheckBox(); 2038 2039 // Item Name 2040 _variableNameField = new JTextField(20); 2041 2042 // Combo box section for selecting conditional reference 2043 // First box selects the Logix, the second selects the conditional within the logix 2044 _selectLogixBox.addItem("XXXXXXXXXXXXXXXXXXXXX"); // NOI18N 2045 _selectConditionalBox.addItem("XXXXXXXXXXXXXXXXXXXXX"); // NOI18N 2046 _selectLogixBox.addActionListener(selectLogixBoxListener); 2047 _selectConditionalBox.addActionListener(selectConditionalBoxListener); 2048 2049 // State Box 2050 _variableStateBox = new JComboBox<>(); 2051 _variableStateBox.addItem(Conditional.Type.XXXXXXX); // NOI18N 2052 2053 // Aspects 2054 _variableSignalBox = new JComboBox<>(); 2055 _variableSignalBox.addItem("XXXXXXXXX"); // NOI18N 2056 2057 // Compare operator 2058 _variableCompareOpBox = new JComboBox<>(); 2059 for (int i = 1; i <= ConditionalVariable.NUM_COMPARE_OPERATIONS; i++) { 2060 _variableCompareOpBox.addItem(ConditionalVariable.getCompareOperationString(i)); 2061 } 2062 2063 // Compare type 2064 _variableCompareTypeBox = new JComboBox<>(); 2065 for (Conditional.Type type : Conditional.Type.getMemoryItems()) { 2066 _variableCompareTypeBox.addItem(type); 2067 } 2068 _variableCompareTypeBox.addActionListener(compareTypeBoxListener); 2069 2070 // Data 1 2071 _variableData1Field = new JTextField(10); 2072 2073 // Data 2 2074 _variableData2Field = new JTextField(10); 2075 } 2076 2077 // ------------ Make Variable Edit Grid Panels ------------ 2078 2079 /** 2080 * Create a one row grid with just the Variable Type box. This is the base 2081 * for larger grids as well as the initial grid for new State Variables. 2082 * 2083 * @param c the constraints object used for the grid construction 2084 */ 2085 void makeEmptyVariableGrid(GridBagConstraints c) { 2086 // Variable type box 2087 c.gridy = 0; 2088 c.gridx = 0; 2089 c.anchor = java.awt.GridBagConstraints.EAST; 2090 JLabel row0Label = new JLabel(Bundle.getMessage("LabelVariableType")); // NOI18N 2091 row0Label.setToolTipText(Bundle.getMessage("VariableTypeHint")); // NOI18N 2092 _gridPanel.add(row0Label, c); 2093 c.gridx = 1; 2094 c.anchor = java.awt.GridBagConstraints.WEST; 2095 _gridPanel.add(_variableItemBox, c); 2096 } 2097 2098 /* 2099 * Create the Oper, Not and Trigger rows. 2100 * 2101 * @param c The constraints object used for the grid construction 2102 */ 2103 void makeOptionsVariableGrid(GridBagConstraints c) { 2104 makeEmptyVariableGrid(c); 2105 2106 // Oper Select 2107 c.gridy = 1; 2108 c.gridx = 0; 2109 c.anchor = java.awt.GridBagConstraints.EAST; 2110 JLabel row1Label = new JLabel(Bundle.getMessage("ColumnLabelOperator")); // NOI18N 2111 row1Label.setToolTipText(Bundle.getMessage("VariableOperHint")); // NOI18N 2112 _gridPanel.add(row1Label, c); 2113 c.gridx = 1; 2114 c.anchor = java.awt.GridBagConstraints.WEST; 2115 _gridPanel.add(_variableOperBox, c); 2116 2117 // Not Select 2118 c.gridy = 2; 2119 c.gridx = 0; 2120 c.anchor = java.awt.GridBagConstraints.EAST; 2121 JLabel row2Label = new JLabel(Bundle.getMessage("ColumnLabelNot")); // NOI18N 2122 row2Label.setToolTipText(Bundle.getMessage("VariableNotHint")); // NOI18N 2123 _gridPanel.add(row2Label, c); 2124 c.gridx = 1; 2125 c.anchor = java.awt.GridBagConstraints.WEST; 2126 _gridPanel.add(_variableNegated, c); 2127 2128 // Trigger Select 2129 c.gridy = 3; 2130 c.gridx = 0; 2131 c.anchor = java.awt.GridBagConstraints.EAST; 2132 JLabel row3Label = new JLabel(Bundle.getMessage("ColumnLabelTriggersCalculation")); // NOI18N 2133 row3Label.setToolTipText(Bundle.getMessage("VariableTriggerHint")); // NOI18N 2134 _gridPanel.add(row3Label, c); 2135 c.gridx = 1; 2136 c.anchor = java.awt.GridBagConstraints.WEST; 2137 _gridPanel.add(_variableTriggerActions, c); 2138 } 2139 2140 /** 2141 * Create the standard Name and State rows. 2142 * The name field will be either a text field or a combo box. 2143 * The name field label is a variable to support run time changes. 2144 * 2145 * @param c The constraints object used for the grid construction 2146 */ 2147 void makeStandardVariableGrid(GridBagConstraints c) { 2148 makeOptionsVariableGrid(c); 2149 2150 // Name Field 2151 c.gridy = 4; 2152 c.gridx = 0; 2153 c.anchor = java.awt.GridBagConstraints.EAST; 2154 _gridPanel.add(_variableNameLabel, c); 2155 c.gridx = 1; 2156 c.anchor = java.awt.GridBagConstraints.WEST; 2157 if (_selectionMode == SelectionMode.USECOMBO) { 2158 _gridPanel.add(_comboNameBox, c); 2159 } else { 2160 _gridPanel.add(_variableNameField, c); 2161 } 2162 2163 // State Box 2164 c.gridy = 5; 2165 c.gridx = 0; 2166 c.anchor = java.awt.GridBagConstraints.EAST; 2167 JLabel row5Label = new JLabel(Bundle.getMessage("LabelVariableState")); // NOI18N 2168 row5Label.setToolTipText(Bundle.getMessage("VariableStateHint")); // NOI18N 2169 _gridPanel.add(row5Label, c); 2170 c.gridx = 1; 2171 c.anchor = java.awt.GridBagConstraints.WEST; 2172 _gridPanel.add(_variableStateBox, c); 2173 } 2174 2175 /** 2176 * Add the Aspect field for signal heads and signal masts. 2177 * 2178 * @param c The constraints object used for the grid construction 2179 */ 2180 void makeSignalAspectVariableGrid(GridBagConstraints c) { 2181 makeStandardVariableGrid(c); 2182 2183 // Mast Aspect Box 2184 c.gridy = 6; 2185 c.gridx = 0; 2186 c.anchor = java.awt.GridBagConstraints.EAST; 2187 JLabel row5Label = new JLabel(Bundle.getMessage("LabelVariableAspect")); // NOI18N 2188 row5Label.setToolTipText(Bundle.getMessage("VariableAspectHint")); // NOI18N 2189 _gridPanel.add(row5Label, c); 2190 c.gridx = 1; 2191 c.anchor = java.awt.GridBagConstraints.WEST; 2192 _gridPanel.add(_variableSignalBox, c); 2193 } 2194 2195 /** 2196 * Create the Logix and Conditional rows and the State row. 2197 * 2198 * @param c The constraints object used for the grid construction 2199 */ 2200 void makeConditionalVariableGrid(GridBagConstraints c) { 2201 makeOptionsVariableGrid(c); 2202 2203 // Logix Selection ComboBox 2204 c.gridy = 4; 2205 c.gridx = 0; 2206 c.anchor = java.awt.GridBagConstraints.EAST; 2207 JLabel row4Label = new JLabel(Bundle.getMessage("SelectLogix")); // NOI18N 2208 row4Label.setToolTipText(Bundle.getMessage("VariableLogixHint")); // NOI18N 2209 _gridPanel.add(row4Label, c); 2210 c.gridx = 1; 2211 c.anchor = java.awt.GridBagConstraints.WEST; 2212 _gridPanel.add(_selectLogixBox, c); 2213 2214 // Conditional Selection ComboBox 2215 c.gridy = 5; 2216 c.gridx = 0; 2217 c.anchor = java.awt.GridBagConstraints.EAST; 2218 JLabel row5Label = new JLabel(Bundle.getMessage("SelectConditional")); // NOI18N 2219 row5Label.setToolTipText(Bundle.getMessage("VariableConditionalHint")); // NOI18N 2220 _gridPanel.add(row5Label, c); 2221 c.gridx = 1; 2222 c.anchor = java.awt.GridBagConstraints.WEST; 2223 _gridPanel.add(_selectConditionalBox, c); 2224 2225 // State Box 2226 c.gridy = 6; 2227 c.gridx = 0; 2228 c.anchor = java.awt.GridBagConstraints.EAST; 2229 JLabel row6Label = new JLabel(Bundle.getMessage("LabelVariableState")); // NOI18N 2230 row6Label.setToolTipText(Bundle.getMessage("VariableStateHint")); // NOI18N 2231 _gridPanel.add(row6Label, c); 2232 c.gridx = 1; 2233 c.anchor = java.awt.GridBagConstraints.WEST; 2234 _gridPanel.add(_variableStateBox, c); 2235 } 2236 2237 /** 2238 * Create the Memory specific rows. 2239 * 2240 * @param c The constraints object used for the grid construction 2241 */ 2242 void makeMemoryVariableGrid(GridBagConstraints c) { 2243 makeOptionsVariableGrid(c); 2244 2245 // Name Field 2246 c.gridy = 4; 2247 c.gridx = 0; 2248 c.anchor = java.awt.GridBagConstraints.EAST; 2249 JLabel row4Label = new JLabel(Bundle.getMessage("LabelItemName")); // NOI18N 2250 row4Label.setToolTipText(Bundle.getMessage("NameHintMemory")); // NOI18N 2251 _gridPanel.add(row4Label, c); 2252 c.gridx = 1; 2253 c.anchor = java.awt.GridBagConstraints.WEST; 2254 if (_selectionMode == SelectionMode.USECOMBO) { 2255 _gridPanel.add(_comboNameBox, c); 2256 } else { 2257 _gridPanel.add(_variableNameField, c); 2258 } 2259 2260 // Comparison Operator 2261 c.gridy = 5; 2262 c.gridx = 0; 2263 c.anchor = java.awt.GridBagConstraints.EAST; 2264 JLabel row5Label = new JLabel(Bundle.getMessage("LabelCompareOp")); // NOI18N 2265 row5Label.setToolTipText(Bundle.getMessage("CompareHintMemory")); // NOI18N 2266 _gridPanel.add(row5Label, c); 2267 c.gridx = 1; 2268 c.anchor = java.awt.GridBagConstraints.WEST; 2269 _gridPanel.add(_variableCompareOpBox, c); 2270 2271 // Compare As 2272 c.gridy = 6; 2273 c.gridx = 0; 2274 c.anchor = java.awt.GridBagConstraints.EAST; 2275 JLabel row6Label = new JLabel(Bundle.getMessage("LabelCompareType")); // NOI18N 2276 row6Label.setToolTipText(Bundle.getMessage("CompareTypeHint")); // NOI18N 2277 _gridPanel.add(row6Label, c); 2278 c.gridx = 1; 2279 c.anchor = java.awt.GridBagConstraints.WEST; 2280 _gridPanel.add(_variableCompareTypeBox, c); 2281 2282 // Literal Value (default) / Memory Value (name) 2283 c.gridy = 7; 2284 c.gridx = 0; 2285 c.anchor = java.awt.GridBagConstraints.EAST; 2286 _gridPanel.add(_variableMemoryValueLabel, c); 2287 c.gridx = 1; 2288 c.anchor = java.awt.GridBagConstraints.WEST; 2289 _gridPanel.add(_variableData1Field, c); 2290 } 2291 2292 /** 2293 * Create the Fast Clock start and end time rows. 2294 * 2295 * @param c The constraints object used for the grid construction 2296 */ 2297 void makeFastClockVariableGrid(GridBagConstraints c) { 2298 makeOptionsVariableGrid(c); 2299 2300 // Start Time Field 2301 c.gridy = 4; 2302 c.gridx = 0; 2303 c.anchor = java.awt.GridBagConstraints.EAST; 2304 JLabel row4Label = new JLabel(Bundle.getMessage("LabelStartTime")); // NOI18N 2305 row4Label.setToolTipText(Bundle.getMessage("DataHintTime")); // NOI18N 2306 _gridPanel.add(row4Label, c); 2307 c.gridx = 1; 2308 c.anchor = java.awt.GridBagConstraints.WEST; 2309 _gridPanel.add(_variableData1Field, c); 2310 2311 // End Time Field 2312 c.gridy = 5; 2313 c.gridx = 0; 2314 c.anchor = java.awt.GridBagConstraints.EAST; 2315 JLabel row5Label = new JLabel(Bundle.getMessage("LabelEndTime")); // NOI18N 2316 row5Label.setToolTipText(Bundle.getMessage("DataHintTime")); // NOI18N 2317 _gridPanel.add(row5Label, c); 2318 c.gridx = 1; 2319 c.anchor = java.awt.GridBagConstraints.WEST; 2320 _gridPanel.add(_variableData2Field, c); 2321 } 2322 2323 // ------------ Main Variable methods ------------ 2324 2325 /** 2326 * Set display to show current state variable (curVariable) parameters. 2327 */ 2328 void initializeStateVariables() { 2329 Conditional.Type testType = _curVariable.getType(); 2330 if (log.isDebugEnabled()) { 2331 log.debug("initializeStateVariables: testType= {}", testType); // NOI18N 2332 } 2333 Conditional.ItemType itemType = testType.getItemType(); 2334 log.debug("initializeStateVariables: itemType= {}, testType= {}", itemType, testType); // NOI18N 2335 if (itemType == _variableItemBox.getSelectedItem()) { 2336 // Force a refresh of variableTypeChanged 2337 variableTypeChanged(itemType); 2338 } 2339 _variableItemBox.setSelectedItem(itemType); 2340 _variableOperBox.setSelectedItem(_curVariable.getOpernString()); 2341 _variableNegated.setSelected(_curVariable.isNegated()); 2342 _variableTriggerActions.setSelected(_curVariable.doTriggerActions()); 2343 2344 switch (itemType) { 2345 case NONE: 2346 _variableNameField.setText(""); 2347 break; 2348 2349 case SENSOR: 2350 case TURNOUT: 2351 case LIGHT: 2352 case CONDITIONAL: 2353 case WARRANT: 2354 _variableStateBox.setSelectedItem(testType); 2355 _variableNameField.setText(_curVariable.getName()); 2356 break; 2357 2358 case SIGNALHEAD: 2359 _variableStateBox.setSelectedItem(testType); 2360 _variableNameField.setText(_curVariable.getName()); 2361 if (Conditional.Type.isSignalHeadApperance(testType)) { 2362 _variableStateBox.setSelectedItem(Conditional.Type.SIGNAL_HEAD_APPEARANCE_EQUALS); 2363 _variableSignalBox.setSelectedItem(_curVariable.getType()); 2364 } 2365 break; 2366 2367 case SIGNALMAST: 2368 // set display to show current state variable (curVariable) parameters 2369 _variableStateBox.setSelectedItem(testType); 2370 _variableNameField.setText(_curVariable.getName()); 2371 if (testType == Conditional.Type.SIGNAL_MAST_ASPECT_EQUALS) { 2372 _variableSignalBox.setSelectedItem(_curVariable.getDataString()); 2373 } 2374 break; 2375 2376 case MEMORY: 2377 _variableCompareTypeBox.setSelectedIndex( 2378 Conditional.Type.getIndexInList(Conditional.Type.getMemoryItems(), testType)); 2379 _variableNameField.setText(_curVariable.getName()); 2380 int num1 = _curVariable.getNum1() - 1; 2381 if (num1 == -1) { // former code was only equals 2382 num1 = ConditionalVariable.EQUAL - 1; 2383 } 2384 _variableCompareOpBox.setSelectedIndex(num1); 2385 _variableData1Field.setText(_curVariable.getDataString()); 2386 break; 2387 2388 case CLOCK: 2389 int time = _curVariable.getNum1(); 2390 _variableData1Field.setText(formatTime(time / 60, time - ((time / 60) * 60))); 2391 time = _curVariable.getNum2(); 2392 _variableData2Field.setText(formatTime(time / 60, time - ((time / 60) * 60))); 2393 _variableNameField.setText(""); 2394 break; 2395 2396 case OBLOCK: 2397 _variableNameField.setText(_curVariable.getName()); 2398 //_variableStateBox.removeAllItems(); 2399 for (Conditional.Type type : Conditional.Type.getOBlockItems()) { 2400 _variableStateBox.addItem(type); 2401 if (type.toString().equals(OBlock.getLocalStatusName(_curVariable.getDataString()))) { 2402 _variableStateBox.setSelectedItem(type); 2403 } 2404 } 2405// Iterator<String> names = OBlock.getLocalStatusNames(); 2406// while (names.hasNext()) { 2407// _variableStateBox.addItem(names.next()); 2408// } 2409// _variableStateBox.setSelectedItem(OBlock.getLocalStatusName(_curVariable.getDataString())); 2410 break; 2411 2412 case ENTRYEXIT: 2413 _variableNameField.setText(_curVariable.getBean().getUserName()); 2414 _variableStateBox.setSelectedItem(testType); 2415 break; 2416 2417 default: 2418 break; 2419 } 2420 _detailGrid.setVisible(true); 2421 } 2422 2423 /** 2424 * Respond to change in variable type chosen in the State Variable combo box. 2425 * 2426 * @param itemType value representing the newly selected Conditional type, 2427 * i.e. ITEM_TYPE_SENSOR 2428 */ 2429 private void variableTypeChanged(Conditional.ItemType itemType) { 2430 Conditional.Type testType = _curVariable.getType(); 2431 log.debug("variableTypeChanged: itemType= {}, testType= {}", itemType, testType); // NOI18N 2432 _variableStateBox.removeAllItems(); 2433 _variableNameField.removeActionListener(variableSignalHeadNameListener); 2434 _variableNameField.removeActionListener(variableSignalMastNameListener); 2435 _variableStateBox.removeActionListener(variableSignalTestStateListener); 2436 _detailGrid.setVisible(false); 2437 2438 if (_comboNameBox != null) { 2439 for (ActionListener item : _comboNameBox.getActionListeners()) { 2440 _comboNameBox.removeActionListener(item); 2441 } 2442 _comboNameBox.removeFocusListener(detailFocusEvent); 2443 } 2444 setPickWindow("Variable", itemType); // NOI18N 2445 2446 _variableOperBox.setSelectedItem(_curVariable.getOpernString()); 2447 _variableNegated.setSelected(_curVariable.isNegated()); 2448 _variableTriggerActions.setSelected(_curVariable.doTriggerActions()); 2449 2450 switch (itemType) { 2451 case NONE: 2452 makeDetailGrid("EmptyVariable"); // NOI18N 2453 break; 2454 2455 case SENSOR: 2456 _variableNameLabel.setToolTipText(Bundle.getMessage("NameHintSensor")); // NOI18N 2457 for (Conditional.Type type : Conditional.Type.getSensorItems()) { 2458 _variableStateBox.addItem(type); 2459 } 2460 setVariableNameBox(itemType); 2461 makeDetailGrid("StandardVariable"); // NOI18N 2462 break; 2463 2464 case TURNOUT: 2465 _variableNameLabel.setToolTipText(Bundle.getMessage("NameHintTurnout")); // NOI18N 2466 for (Conditional.Type type : Conditional.Type.getTurnoutItems()) { 2467 _variableStateBox.addItem(type); 2468 } 2469 setVariableNameBox(itemType); 2470 makeDetailGrid("StandardVariable"); // NOI18N 2471 break; 2472 2473 case LIGHT: 2474 _variableNameLabel.setToolTipText(Bundle.getMessage("NameHintLight")); // NOI18N 2475 for (Conditional.Type type : Conditional.Type.getLightItems()) { 2476 _variableStateBox.addItem(type); 2477 } 2478 setVariableNameBox(itemType); 2479 makeDetailGrid("StandardVariable"); // NOI18N 2480 break; 2481 2482 case SIGNALHEAD: 2483 _variableNameLabel.setToolTipText(Bundle.getMessage("NameHintSignal")); // NOI18N 2484 loadJComboBoxWithHeadAppearances(_variableSignalBox, _variableNameField.getText().trim()); 2485 2486 for (Conditional.Type type : Conditional.Type.getSignalHeadStateMachineItems()) { 2487 _variableStateBox.addItem(type); 2488 } 2489 2490 setVariableNameBox(itemType); 2491 if (testType == Conditional.Type.SIGNAL_HEAD_APPEARANCE_EQUALS) { 2492 makeDetailGrid("SignalAspectVariable"); // NOI18N 2493 } else { 2494 makeDetailGrid("StandardVariable"); // NOI18N 2495 } 2496 2497 _variableNameField.addActionListener(variableSignalHeadNameListener); 2498 _variableStateBox.addActionListener(variableSignalTestStateListener); 2499 break; 2500 2501 case SIGNALMAST: 2502 _variableNameLabel.setToolTipText(Bundle.getMessage("NameHintSignalMast")); // NOI18N 2503 _variableNameField.addActionListener(variableSignalMastNameListener); 2504 _variableStateBox.addActionListener(variableSignalTestStateListener); 2505 loadJComboBoxWithMastAspects(_variableSignalBox, _variableNameField.getText().trim()); 2506 2507 for (Conditional.Type type : Conditional.Type.getSignalMastItems()) { 2508 _variableStateBox.addItem(type); 2509 } 2510 setVariableNameBox(itemType); 2511 if (testType == Conditional.Type.SIGNAL_MAST_ASPECT_EQUALS) { 2512 makeDetailGrid("SignalAspectVariable"); // NOI18N 2513 } else { 2514 makeDetailGrid("StandardVariable"); // NOI18N 2515 } 2516 break; 2517 2518 case MEMORY: 2519 _variableNameLabel.setToolTipText(Bundle.getMessage("NameHintMemory")); // NOI18N 2520 setVariableNameBox(itemType); 2521 makeDetailGrid("MemoryVariable"); // NOI18N 2522 compareTypeChanged(testType); // Force the label update 2523 break; 2524 2525 case CONDITIONAL: 2526 for (Conditional.Type type : Conditional.Type.getConditionalItems()) { 2527 _variableStateBox.addItem(type); 2528 } 2529 loadSelectLogixBox(); 2530 makeDetailGrid("ConditionalVariable"); // NOI18N 2531 _selectLogixBox.addActionListener(selectLogixBoxListener); 2532 _selectConditionalBox.addActionListener(selectConditionalBoxListener); 2533 break; 2534 2535 case WARRANT: 2536 _variableNameLabel.setToolTipText(Bundle.getMessage("NameHintWarrant")); // NOI18N 2537 for (Conditional.Type type : Conditional.Type.getWarrantItems()) { 2538 _variableStateBox.addItem(type); 2539 } 2540 setVariableNameBox(itemType); 2541 makeDetailGrid("StandardVariable"); // NOI18N 2542 break; 2543 2544 case CLOCK: 2545 makeDetailGrid("FastClockVariable"); // NOI18N 2546 break; 2547 2548 case OBLOCK: 2549 _variableNameLabel.setToolTipText(Bundle.getMessage("NameHintOBlock")); // NOI18N 2550 _variableStateBox.removeAllItems(); 2551 for (Conditional.Type type : Conditional.Type.getOBlockItems()) { 2552 _variableStateBox.addItem(type); 2553 } 2554// Iterator<String> names = OBlock.getLocalStatusNames(); 2555// while (names.hasNext()) { 2556// _variableStateBox.addItem(names.next()); 2557// } 2558 setVariableNameBox(itemType); 2559 makeDetailGrid("StandardVariable"); // NOI18N 2560 break; 2561 2562 case ENTRYEXIT: 2563 _variableNameLabel.setToolTipText(Bundle.getMessage("NameHintEntryExit")); // NOI18N 2564 _variableNameField.setText(_curVariable.getName()); 2565 for (Conditional.Type type : Conditional.Type.getEntryExitItems()) { 2566 _variableStateBox.addItem(type); 2567 } 2568 setVariableNameBox(itemType); 2569 makeDetailGrid("StandardVariable"); // NOI18N 2570 break; 2571 2572 default: 2573 break; 2574 } 2575 } 2576 2577 /** 2578 * Update the name combo box selection based on the current contents of the 2579 * name field. Called by variableItemChanged. 2580 * 2581 * @since 4.7.3 2582 * @param itemType The item type, such as sensor or turnout. 2583 */ 2584 void setVariableNameBox(Conditional.ItemType itemType) { 2585 if (_selectionMode != SelectionMode.USECOMBO) { 2586 return; 2587 } 2588 _comboNameBox = createNameBox(itemType); 2589 if (_comboNameBox == null) { 2590 return; 2591 } 2592 // Select the current entry, add the listener 2593 _comboNameBox.setSelectedItemByName(_curVariable.getName()); 2594 _comboNameBox.addActionListener(new NameBoxListener(_variableNameField)); 2595 _comboNameBox.addFocusListener(detailFocusEvent); 2596 } 2597 2598 // ------------ Variable detail methods ------------ 2599 2600 /** 2601 * Respond to Cancel variable button 2602 */ 2603 void cancelEditVariable() { 2604 if (_newVariableItem) { 2605 _newVariableItem = false; 2606 deletePressed(); 2607 } 2608 cleanUpVariable(); 2609 } 2610 2611 /** 2612 * Respond to Update Variable button in the Edit Variable pane. 2613 */ 2614 void updateVariable() { 2615 if (!validateVariable()) { 2616 return; 2617 } 2618 _newVariableItem = false; 2619 _curConditional.setStateVariables(_variableList); 2620 2621 // Update conditional references 2622 TreeSet<String> newTargetNames = new TreeSet<>(); 2623 loadReferenceNames(_variableList, newTargetNames); 2624 updateWhereUsed(_oldTargetNames, newTargetNames, _curNodeName); 2625 2626 // Update the tree nodeChanged 2627 _curNode.setText(buildNodeText("Variable", _curVariable, _curNodeRow)); // NOI18N 2628 _cdlModel.nodeChanged(_curNode); 2629 cleanUpVariable(); 2630 } 2631 2632 /** 2633 * Clean up: Cancel, Update and Delete Variable buttons. 2634 */ 2635 void cleanUpVariable() { 2636 if (_logicType != Conditional.AntecedentOperator.MIXED) { 2637 setMoveButtons(); 2638 } 2639 } 2640 2641 /** 2642 * Load the Logix selection box. Set the selection to the current Logix. 2643 * 2644 * @since 4.7.4 2645 */ 2646 void loadSelectLogixBox() { 2647 // Get the current Logix name for selecting the current combo box row 2648 String cdlName = _curVariable.getName(); 2649 String lgxName; 2650 if (cdlName.length() == 0 || (_curVariable.getType() != Conditional.Type.CONDITIONAL_TRUE 2651 && _curVariable.getType() != Conditional.Type.CONDITIONAL_FALSE)) { 2652 // Use the current logix name for "add" state variable 2653 lgxName = _curLogix.getSystemName(); 2654 } else { 2655 Logix x = _conditionalManager.getParentLogix(cdlName); 2656 if (x == null) { 2657 log.error("Unable to find the Logix for {}, using the current Logix", cdlName); // NOI18N 2658 lgxName = _curLogix.getSystemName(); 2659 } else { 2660 lgxName = x.getSystemName(); 2661 } 2662 } 2663 2664 _selectLogixBox.removeAllItems(); 2665 _selectLogixMap.clear(); 2666 2667 String itemKey = ""; 2668 for (Logix lgx : _logixManager.getNamedBeanSet()) { 2669 String sName = lgx.getSystemName(); 2670 if (sName.equals("SYS")) { // NOI18N 2671 // Cannot refer to sensor name groups 2672 continue; 2673 } 2674 String uName = lgx.getUserName(); 2675 String itemName = ""; 2676 if (uName == null || uName.length() < 1) { 2677 itemName = sName; 2678 } else { 2679 itemName = uName + " ( " + sName + " )"; 2680 } 2681 _selectLogixMap.put(itemName, sName); 2682 if (lgxName.equals(sName)) { 2683 itemKey = itemName; 2684 } 2685 } 2686 2687 // Load the combo box 2688 for (String item : _selectLogixMap.keySet()) { 2689 _selectLogixBox.addItem(item); 2690 } 2691 2692 JComboBoxUtil.setupComboBoxMaxRows(_selectLogixBox); 2693 _selectLogixBox.setSelectedItem(itemKey); 2694 loadSelectConditionalBox(lgxName); 2695 } 2696 2697 /** 2698 * Load the Conditional selection box. The first row is a prompt. 2699 * 2700 * @since 4.7.4 2701 * @param logixName The Logix system name for selecting the owned 2702 * Conditionals 2703 */ 2704 void loadSelectConditionalBox(String logixName) { 2705 // Get the current Conditional name for selecting the current combo box row 2706 String cdlName = _curVariable.getName(); 2707 2708 _selectConditionalBox.removeAllItems(); 2709 _selectConditionalList.clear(); 2710 2711 // Create the first row 2712 String itemKey = Bundle.getMessage("SelectFirstRow"); // NOI18N 2713 _selectConditionalBox.addItem(itemKey); 2714 _selectConditionalList.add("-None-"); // NOI18N 2715 2716 Logix x = _logixManager.getBySystemName(logixName); 2717 if (x == null) { 2718 log.error("Logix '{}' not found while building the conditional list", logixName); // NOI18N 2719 return; 2720 } 2721 if (x.getNumConditionals() == 0) { 2722 return; 2723 } 2724 for (String cName : _conditionalManager.getSystemNameListForLogix(x)) { 2725 Conditional c = _conditionalManager.getConditional(cName); 2726 if (_curConditional.getSystemName().equals(c.getSystemName())) { 2727 // Don't add myself to the list 2728 continue; 2729 } 2730 String uName = c.getUserName(); 2731 String itemName = ""; 2732 if (uName == null || uName.length() < 1) { 2733 itemName = cName; 2734 } else { 2735 itemName = uName + " ( " + cName + " )"; 2736 } 2737 _selectConditionalBox.addItem(itemName); 2738 _selectConditionalList.add(cName); 2739 if (cdlName.equals(cName)) { 2740 itemKey = itemName; 2741 } 2742 } 2743 JComboBoxUtil.setupComboBoxMaxRows(_selectConditionalBox); 2744 _selectConditionalBox.setSelectedItem(itemKey); 2745 } 2746 2747 /** 2748 * Check if Memory type in a Conditional was changed by the user. 2749 * <p> 2750 * Update GUI if it has. 2751 * 2752 * @param testType One of the four types 2753 */ 2754 private void compareTypeChanged(Conditional.Type testType) { 2755 if ((testType == Conditional.Type.MEMORY_COMPARE) 2756 || (testType == Conditional.Type.MEMORY_COMPARE_INSENSITIVE)) { 2757 _variableMemoryValueLabel.setText(Bundle.getMessage("LabelMemoryValue")); // NOI18N 2758 _variableMemoryValueLabel.setToolTipText(Bundle.getMessage("DataHintMemory")); // NOI18N 2759 } else { 2760 _variableMemoryValueLabel.setText(Bundle.getMessage("LabelLiteralValue")); // NOI18N 2761 _variableMemoryValueLabel.setToolTipText(Bundle.getMessage("DataHintValue")); // NOI18N 2762 } 2763 } 2764 2765 /** 2766 * Fetch valid localized appearances for a given Signal Head. 2767 * <p> 2768 * Warn if head is not found. 2769 * 2770 * @param box the comboBox on the setup pane to fill 2771 * @param signalHeadName user or system name of the Signal Head 2772 */ 2773 void loadJComboBoxWithHeadAppearances(JComboBox<String> box, String signalHeadName) { 2774 box.removeAllItems(); 2775 log.debug("loadJComboBoxWithSignalHeadAppearances called with name: {}", signalHeadName); // NOI18N 2776 SignalHead h = InstanceManager.getDefault(jmri.SignalHeadManager.class).getSignalHead(signalHeadName); 2777 if (h == null) { 2778 box.addItem(Bundle.getMessage("PromptLoadHeadName")); // NOI18N 2779 } else { 2780 String[] v = h.getValidStateNames(); 2781 for (int i = 0; i < v.length; i++) { 2782 box.addItem(v[i]); 2783 } 2784 box.setSelectedItem(h.getAppearanceName()); 2785 } 2786 } 2787 2788 /** 2789 * Fetch valid aspects for a given Signal Mast. 2790 * <p> 2791 * Warn if mast is not found. 2792 * 2793 * @param box the comboBox on the setup pane to fill 2794 * @param mastName user or system name of the Signal Mast 2795 */ 2796 void loadJComboBoxWithMastAspects(JComboBox<String> box, String mastName) { 2797 box.removeAllItems(); 2798 SignalMast m = InstanceManager.getDefault(jmri.SignalMastManager.class).getSignalMast(mastName); 2799 if (m == null) { 2800 box.addItem(Bundle.getMessage("PromptLoadMastName")); // NOI18N 2801 } else { 2802 java.util.Vector<String> v = m.getValidAspects(); 2803 for (int i = 0; i < v.size(); i++) { 2804 box.addItem(v.get(i)); 2805 } 2806 box.setSelectedItem(m.getAspect()); 2807 } 2808 } 2809 2810 // ------------ Variable update processes ------------ 2811 2812 /** 2813 * Validate Variable data from Edit Variable panel, and transfer it to 2814 * current variable object as appropriate. 2815 * <p> 2816 * Messages are sent to the user for any errors found. This routine returns 2817 * false immediately after finding the first error, even if there might be 2818 * more errors. 2819 * 2820 * @return true if all data checks out OK, otherwise false 2821 */ 2822 boolean validateVariable() { 2823 String name = _variableNameField.getText().trim(); 2824 _variableNameField.setText(name); 2825 _curVariable.setDataString(""); 2826 _curVariable.setNum1(0); 2827 _curVariable.setNum2(0); 2828 2829 updateVariableOperator(); 2830 updateVariableNegation(); 2831 _curVariable.setTriggerActions(_variableTriggerActions.isSelected()); 2832 2833 Conditional.ItemType itemType = _variableItemBox.getItemAt(_variableItemBox.getSelectedIndex()); 2834 if (!checkIsAction(name, itemType) ) { 2835 return false; 2836 } 2837 Conditional.Type testType = Conditional.Type.NONE; 2838 switch (itemType) { 2839 case SENSOR: 2840 case TURNOUT: 2841 case LIGHT: 2842 case SIGNALHEAD: 2843 case SIGNALMAST: 2844 case CONDITIONAL: 2845 case WARRANT: 2846 case ENTRYEXIT: 2847 testType = _variableStateBox.getItemAt(_variableStateBox.getSelectedIndex()); 2848 break; 2849 case MEMORY: 2850 testType = _variableCompareTypeBox.getItemAt(_variableCompareTypeBox.getSelectedIndex()); 2851 break; 2852 case CLOCK: 2853 testType = Conditional.Type.FAST_CLOCK_RANGE; 2854 break; 2855 case OBLOCK: 2856 testType = Conditional.Type.BLOCK_STATUS_EQUALS; 2857 break; 2858 default: 2859 JmriJOptionPane.showMessageDialog(_editLogixFrame, 2860 Bundle.getMessage("ErrorVariableType"), Bundle.getMessage("ErrorTitle"), // NOI18N 2861 JmriJOptionPane.ERROR_MESSAGE); 2862 return false; 2863 } 2864 _curVariable.setType(testType); 2865 log.debug("validateVariable: itemType= {}, testType= {}", itemType, testType); // NOI18N 2866 switch (itemType) { 2867 case SENSOR: 2868 name = validateSensorReference(name); 2869 if (name == null) { 2870 return false; 2871 } 2872 break; 2873 case TURNOUT: 2874 name = validateTurnoutReference(name); 2875 if (name == null) { 2876 return false; 2877 } 2878 break; 2879 case CONDITIONAL: 2880 name = validateConditionalReference(name); 2881 if (name == null) { 2882 return false; 2883 } 2884 _curVariable.setName(name); 2885 Conditional c = _conditionalManager.getBySystemName(name); 2886 if (c == null) { 2887 return false; 2888 } 2889 String uName = c.getUserName(); 2890 if (uName == null || uName.isEmpty()) { 2891 _curVariable.setGuiName(c.getSystemName()); 2892 } else { 2893 _curVariable.setGuiName(uName); 2894 } 2895 break; 2896 case LIGHT: 2897 name = validateLightReference(name); 2898 if (name == null) { 2899 return false; 2900 } 2901 break; 2902 case MEMORY: 2903 name = validateMemoryReference(name); 2904 if (name == null) { 2905 return false; 2906 } 2907 String name2 = _variableData1Field.getText(); 2908 if ((testType == Conditional.Type.MEMORY_COMPARE) 2909 || (testType == Conditional.Type.MEMORY_COMPARE_INSENSITIVE)) { 2910 name2 = validateMemoryReference(name2); 2911 if (name2 == null) { 2912 return false; 2913 } 2914 } 2915 _curVariable.setDataString(name2); 2916 _curVariable.setNum1(_variableCompareOpBox.getSelectedIndex() + 1); 2917 break; 2918 case CLOCK: 2919 int beginTime = parseTime(_variableData1Field.getText()); 2920 if (beginTime < 0) { 2921 // parse error occurred - message has been sent 2922 return (false); 2923 } 2924 int endTime = parseTime(_variableData2Field.getText()); 2925 if (endTime < 0) { 2926 return (false); 2927 } 2928 // set beginning and end time (minutes since midnight) 2929 _curVariable.setNum1(beginTime); 2930 _curVariable.setNum2(endTime); 2931 name = "Clock"; // NOI18N 2932 break; 2933 case SIGNALHEAD: 2934 name = validateSignalHeadReference(name); 2935 if (name == null) { 2936 return false; 2937 } 2938 if (testType == Conditional.Type.SIGNAL_HEAD_APPEARANCE_EQUALS) { 2939 String appStr = (String) _variableSignalBox.getSelectedItem(); 2940 if (appStr != null) { 2941 Conditional.Type type = ConditionalVariable.stringToVariableTest(appStr); 2942 if (type == Conditional.Type.ERROR) { 2943 JmriJOptionPane.showMessageDialog(_editLogixFrame, Bundle.getMessage("ErrorAppearance"), Bundle.getMessage("ErrorTitle"), // NOI18N 2944 JmriJOptionPane.ERROR_MESSAGE); 2945 return false; 2946 } 2947 _curVariable.setType(type); 2948 _curVariable.setDataString(appStr); 2949 log.debug("SignalHead \"{}\"of type '{}' _variableSignalBox.getSelectedItem()= {}", name, testType, _variableSignalBox.getSelectedItem()); // NOI18N 2950 } else { 2951 log.warn("null selection in _variableSignalBox"); 2952 } 2953 } 2954 break; 2955 case SIGNALMAST: 2956 name = validateSignalMastReference(name); 2957 if (name == null) { 2958 return false; 2959 } 2960 if (testType == Conditional.Type.SIGNAL_MAST_ASPECT_EQUALS) { 2961 if (_variableSignalBox.getSelectedIndex() < 0) { 2962 JmriJOptionPane.showMessageDialog(_editLogixFrame, 2963 Bundle.getMessage("ErrorAspect"), Bundle.getMessage("ErrorTitle"), // NOI18N 2964 JmriJOptionPane.ERROR_MESSAGE); 2965 return false; 2966 } 2967 // save the selected aspect for comparison 2968 _curVariable.setDataString((String) _variableSignalBox.getSelectedItem()); 2969 // _curVariable.setType(ConditionalVariable.stringToVariableTest(appStr)); 2970 } 2971 break; 2972 case WARRANT: 2973 name = validateWarrantReference(name); 2974 if (name == null) { 2975 return false; 2976 } 2977 break; 2978 case OBLOCK: 2979 name = validateOBlockReference(name); 2980 if (name == null) { 2981 return false; 2982 } 2983 String stri18n = (String) _variableStateBox.getSelectedItem(); 2984 if (stri18n != null) { 2985 _curVariable.setDataString(OBlock.getSystemStatusName(stri18n)); 2986 log.debug("OBlock \"{}\"of type '{}' _variableSignalBox.getSelectedItem()= {}", name, testType, _variableSignalBox.getSelectedItem()); // NOI18N 2987 } 2988 break; 2989 case ENTRYEXIT: 2990 name = validateEntryExitReference(name); 2991 if (name == null) { 2992 return false; 2993 } 2994 break; 2995 default: 2996 JmriJOptionPane.showMessageDialog(_editLogixFrame, 2997 Bundle.getMessage("ErrorVariableType"), Bundle.getMessage("ErrorTitle"), // NOI18N 2998 JmriJOptionPane.ERROR_MESSAGE); 2999 return false; 3000 } 3001 _curVariable.setName(name); 3002 boolean result = _curVariable.evaluate(); 3003 log.debug("State Variable \"{}\" of type '{}' state= {} type= {}", 3004 name, testType.getTestTypeString(), 3005 result, _curVariable.getType()); // NOI18N 3006 if (_curVariable.getType() == Conditional.Type.NONE) { 3007 JmriJOptionPane.showMessageDialog(_editLogixFrame, 3008 Bundle.getMessage("ErrorVariableState"), Bundle.getMessage("ErrorTitle"), // NOI18N 3009 JmriJOptionPane.ERROR_MESSAGE); 3010 return false; 3011 } 3012 return (true); 3013 } 3014 3015 /** 3016 * Update the variable operation. If a change has occurred, also update the 3017 * antecedent and antecedent tree node. 3018 */ 3019 @SuppressFBWarnings(value = "BC_UNCONFIRMED_CAST_OF_RETURN_VALUE", justification = "Except for the root node, all nodes are ConditionalTreeNode") // NOI18N 3020 void updateVariableOperator() { 3021 Operator oldOper = _curVariable.getOpern(); 3022 if (_curNodeRow > 0) { 3023 if (_variableOperBox.getSelectedIndex() == 0) { 3024 _curVariable.setOpern(Conditional.Operator.AND); 3025 } else { 3026 _curVariable.setOpern(Conditional.Operator.OR); 3027 } 3028 } else { 3029 _curVariable.setOpern(Conditional.Operator.NONE); 3030 } 3031 if (_curVariable.getOpern() != oldOper) { 3032 makeAntecedent(); 3033 _curConditional.setLogicType(_logicType, _antecedent); // non-localized 3034 ConditionalTreeNode antLeaf = (ConditionalTreeNode) ((ConditionalTreeNode) _curNode.getParent()).getPreviousSibling(); 3035 antLeaf.setText(buildNodeText("Antecedent", _curConditional, 0)); // NOI18N 3036 _cdlModel.nodeChanged(antLeaf); 3037 } 3038 } 3039 3040 /** 3041 * Update the variable negation. If a change has occurred, also update the 3042 * antecedent and antecedent tree node. 3043 */ 3044 @SuppressFBWarnings(value = "BC_UNCONFIRMED_CAST_OF_RETURN_VALUE", justification = "Except for the root node, all nodes are ConditionalTreeNode") // NOI18N 3045 void updateVariableNegation() { 3046 boolean state = _curVariable.isNegated(); 3047 if (_variableNegated.isSelected()) { 3048 _curVariable.setNegation(true); 3049 } else { 3050 _curVariable.setNegation(false); 3051 } 3052 if (_curVariable.isNegated() != state) { 3053 makeAntecedent(); 3054 _curConditional.setLogicType(_logicType, _antecedent); // non-localized 3055 ConditionalTreeNode antLeaf = (ConditionalTreeNode) ((ConditionalTreeNode) _curNode.getParent()).getPreviousSibling(); 3056 antLeaf.setText(buildNodeText("Antecedent", _curConditional, 0)); 3057 _cdlModel.nodeChanged(antLeaf); 3058 } 3059 } 3060 3061 /** 3062 * Update the conditional variable list and refresh the local copy. 3063 * The parent Logix is de-activated and re-activated. This ensures 3064 * that listeners are properly handled. 3065 * @since 4.11.2 3066 */ 3067 void updateVariableList() { 3068 _curLogix.deActivateLogix(); 3069 _curConditional.setStateVariables(_variableList); 3070 _variableList = _curConditional.getCopyOfStateVariables(); 3071 _curLogix.activateLogix(); 3072 } 3073 3074 // ------------ Variable detail listeners ------------ 3075 3076 transient ActionListener variableSignalHeadNameListener = new ActionListener() { 3077 @Override 3078 public void actionPerformed(ActionEvent e) { 3079 // fired when signal head name changes, but only 3080 // while in signal head mode 3081 log.debug("variableSignalHeadNameListener fires; _variableNameField : {}", _variableNameField.getText().trim()); // NOI18N 3082 loadJComboBoxWithHeadAppearances(_variableSignalBox, _variableNameField.getText().trim()); 3083 } 3084 }; 3085 3086 transient ActionListener variableSignalMastNameListener = new ActionListener() { 3087 @Override 3088 public void actionPerformed(ActionEvent e) { 3089 // fired when signal mast name changes, but only 3090 // while in signal mast mode 3091 log.debug("variableSignalMastNameListener fires; _variableNameField : {}", _variableNameField.getText().trim()); // NOI18N 3092 loadJComboBoxWithMastAspects(_variableSignalBox, _variableNameField.getText().trim()); 3093 } 3094 }; 3095 3096 transient ActionListener variableSignalTestStateListener = new ActionListener() { 3097 @Override 3098 public void actionPerformed(ActionEvent e) { 3099 log.debug("variableSignalTestStateListener fires; _variableItemBox.getSelectedIndex()= \"{}\" _variableStateBox.getSelectedIndex()= \"{}\"", // NOI18N 3100 _variableItemBox.getSelectedIndex(), 3101 _variableStateBox.getSelectedIndex()); 3102 3103 Conditional.ItemType itemType = _variableItemBox.getItemAt(_variableItemBox.getSelectedIndex()); 3104 3105 if (_variableStateBox.getSelectedIndex() == 1) { 3106 if (itemType == Conditional.ItemType.SIGNALHEAD) { 3107 loadJComboBoxWithHeadAppearances(_variableSignalBox, _variableNameField.getText().trim()); 3108 _detailGrid.setVisible(false); 3109 makeDetailGrid("SignalAspectVariable"); // NOI18N 3110 } else if (itemType == Conditional.ItemType.SIGNALMAST) { 3111 loadJComboBoxWithMastAspects(_variableSignalBox, _variableNameField.getText().trim()); 3112 _detailGrid.setVisible(false); 3113 makeDetailGrid("SignalAspectVariable"); // NOI18N 3114 } else { 3115 _detailGrid.setVisible(false); 3116 makeDetailGrid("StandardVariable"); // NOI18N 3117 } 3118 } else { 3119 _detailGrid.setVisible(false); 3120 makeDetailGrid("StandardVariable"); // NOI18N 3121 } 3122 } 3123 }; 3124 3125 transient ActionListener selectLogixBoxListener = new ActionListener() { 3126 @Override 3127 public void actionPerformed(ActionEvent e) { 3128 String lgxItem = (String) _selectLogixBox.getSelectedItem(); 3129 if (lgxItem != null) { 3130 String lgxName = _selectLogixMap.get(lgxItem); 3131 if (lgxName != null) { 3132 loadSelectConditionalBox(lgxName); 3133 } 3134 } 3135 } 3136 }; 3137 3138 transient ActionListener selectConditionalBoxListener = new ActionListener() { 3139 @Override 3140 public void actionPerformed(ActionEvent e) { 3141 int cdlIndex = _selectConditionalBox.getSelectedIndex(); 3142 if (cdlIndex > 0 && cdlIndex < _selectConditionalList.size()) { 3143 String cdlName = _selectConditionalList.get(cdlIndex); 3144 _variableNameField.setText(cdlName); 3145 } 3146 } 3147 }; 3148 3149 transient ActionListener compareTypeBoxListener = new ActionListener() { 3150 @Override 3151 public void actionPerformed(ActionEvent e) { 3152 int selection = _variableCompareTypeBox.getSelectedIndex(); 3153 compareTypeChanged(Conditional.Type.getMemoryItems().get(selection)); 3154 } 3155 }; 3156 3157 // ============ Edit Action Section ============ 3158 3159 /** 3160 * Called once during class initialization to define the GUI objects. Where 3161 * possible, the combo box content is loaded. 3162 */ 3163 void buildActionComponents() { 3164 // Item Type 3165 _actionItemBox = new JComboBox<>(); 3166 for (Conditional.ItemType itemType : Conditional.ItemType.values()) { 3167 _actionItemBox.addItem(itemType); 3168 } 3169 JComboBoxUtil.setupComboBoxMaxRows(_actionItemBox); 3170 _actionItemBox.addActionListener(new ActionListener() { 3171 @Override 3172 public void actionPerformed(ActionEvent e) { 3173 Conditional.ItemType newActionItem = 3174 _actionItemBox.getItemAt(_actionItemBox.getSelectedIndex()); 3175 if (log.isDebugEnabled()) { 3176 log.debug("_actionItemBox Listener: new = {}, curr = {}, row = {}", // NOI18N 3177 newActionItem, _curActionItem, _curNodeRow); 3178 } 3179 if (newActionItem != _curActionItem) { 3180 if (_curNodeRow >= 0) { 3181 _curAction = new DefaultConditionalAction(); 3182 _actionList.set(_curNodeRow, _curAction); 3183 } 3184 _curActionItem = newActionItem; 3185 } 3186 actionItemChanged(newActionItem); 3187 } 3188 }); 3189 3190 // Item Name 3191 _actionNameField = new JTextField(20); 3192 3193 // Action Type Box 3194 _actionTypeBox = new JComboBox<>(); 3195 JComboBoxUtil.setupComboBoxMaxRows(_actionTypeBox); 3196 _actionTypeBox.addItem(Conditional.Action.NONE); 3197 3198 // Action State Box 3199 _actionBox = new JComboBox<String>(); 3200 _actionBox.addItem(""); 3201 3202 // Short strings: Delay time, memory value/copy target 3203 _shortActionString = new JTextField(15); 3204 3205 // On Change / Trigger options 3206 _actionOptionBox = new JComboBox<String>(); 3207 3208 // File Selector 3209 _actionSetButton = new JButton("..."); // "File" replaced by ... 3210 _actionSetButton.addActionListener(new ActionListener() { 3211 @Override 3212 public void actionPerformed(ActionEvent e) { 3213 validateAction(); 3214 setFileLocation(e); 3215 } 3216 }); 3217 3218 // File names, etc. 3219 _longActionString = new JTextField(30); 3220 } 3221 3222 // ------------ Make Action Edit Grid Panels ------------ 3223 3224 /** 3225 * Create a one row grid with just the Action Item box. This is the base for 3226 * larger grids as well as the initial grid for new Actions. 3227 * 3228 * @param c the constraints object used for the grid construction 3229 */ 3230 void makeEmptyActionGrid(GridBagConstraints c) { 3231 // Action item box 3232 c.gridy = 0; 3233 c.gridx = 0; 3234 c.anchor = java.awt.GridBagConstraints.EAST; 3235 JLabel row0Label = new JLabel(Bundle.getMessage("LabelActionItem")); // NOI18N 3236 row0Label.setToolTipText(Bundle.getMessage("ActionItemHint")); // NOI18N 3237 _gridPanel.add(row0Label, c); 3238 c.gridx = 1; 3239 c.anchor = java.awt.GridBagConstraints.WEST; 3240 _gridPanel.add(_actionItemBox, c); 3241 } 3242 3243 /** 3244 * Create the standard Name and Type rows. 3245 * The name field will be either a text field or a combo box. 3246 * The name field label is a variable to support run time changes. 3247 * 3248 * @param c The constraints object used for the grid construction 3249 * @param finalRow Controls whether the tigger combo box is included 3250 */ 3251 void makeNameTypeActionGrid(GridBagConstraints c, boolean finalRow) { 3252 makeEmptyActionGrid(c); 3253 3254 Conditional.Action actionType = _curAction.getType(); 3255 Conditional.ItemType itemType = actionType.getItemType(); 3256 3257 // Name Field 3258 c.gridy = 1; 3259 c.gridx = 0; 3260 c.anchor = java.awt.GridBagConstraints.EAST; 3261 _gridPanel.add(_actionNameLabel, c); 3262 c.gridx = 1; 3263 c.anchor = java.awt.GridBagConstraints.WEST; 3264 if ((_selectionMode == SelectionMode.USECOMBO) 3265 && (itemType != Conditional.ItemType.AUDIO)) { 3266 _gridPanel.add(_comboNameBox, c); 3267 } else { 3268 _gridPanel.add(_actionNameField, c); 3269 } 3270 3271 // Action Type Box 3272 c.gridy = 2; 3273 c.gridx = 0; 3274 c.anchor = java.awt.GridBagConstraints.EAST; 3275 JLabel row5Label = new JLabel(Bundle.getMessage("LabelActionType")); // NOI18N 3276 row5Label.setToolTipText(Bundle.getMessage("ActionTypeHint")); // NOI18N 3277 _gridPanel.add(row5Label, c); 3278 c.gridx = 1; 3279 c.anchor = java.awt.GridBagConstraints.WEST; 3280 _gridPanel.add(_actionTypeBox, c); 3281 3282 if (itemType == Conditional.ItemType.NONE) { 3283 // Skip the change/trigger section for new Actions 3284 return; 3285 } 3286 3287 if (finalRow) { 3288 makeChangeTriggerActionGrid(c); 3289 } 3290 } 3291 3292 /** 3293 * Create the standard Type row. 3294 * 3295 * @param c The constraints object used for the grid construction 3296 * @param finalRow Controls whether the tigger combo box is included 3297 */ 3298 void makeTypeActionGrid(GridBagConstraints c, boolean finalRow) { 3299 makeEmptyActionGrid(c); 3300 3301 Conditional.Action actionType = _curAction.getType(); 3302 Conditional.ItemType itemType = actionType.getItemType(); 3303 3304 // Action Type Box 3305 c.gridy = 1; 3306 c.gridx = 0; 3307 c.anchor = java.awt.GridBagConstraints.EAST; 3308 JLabel row5Label = new JLabel(Bundle.getMessage("LabelActionType")); // NOI18N 3309 row5Label.setToolTipText(Bundle.getMessage("ActionTypeHint")); // NOI18N 3310 _gridPanel.add(row5Label, c); 3311 c.gridx = 1; 3312 c.anchor = java.awt.GridBagConstraints.WEST; 3313 _gridPanel.add(_actionTypeBox, c); 3314 3315 if (itemType == Conditional.ItemType.NONE) { 3316 // Skip the change/trigger section for new Actions 3317 return; 3318 } 3319 3320 if (finalRow) { 3321 makeChangeTriggerActionGrid(c); 3322 } 3323 } 3324 3325 /** 3326 * Add the action box to the grid. 3327 * 3328 * @param c The constraints object used for the grid construction 3329 * @param finalRow Controls whether the tigger combo box is included 3330 */ 3331 void makeStandardActionGrid(GridBagConstraints c, boolean finalRow) { 3332 makeNameTypeActionGrid(c, false); 3333 3334 // Action Box 3335 c.gridy = 3; 3336 c.gridx = 0; 3337 c.anchor = java.awt.GridBagConstraints.EAST; 3338 _gridPanel.add(_actionBoxLabel, c); 3339 c.gridx = 1; 3340 c.anchor = java.awt.GridBagConstraints.WEST; 3341 _gridPanel.add(_actionBox, c); 3342 3343 if (finalRow) { 3344 makeChangeTriggerActionGrid(c); 3345 } 3346 } 3347 3348 /** 3349 * Add the short name field to the grid. 3350 * 3351 * @param c The constraints object used for the grid construction 3352 * @param includeBox Controls whether the normal action type combo box is 3353 * included 3354 */ 3355 void makeShortFieldActionGrid(GridBagConstraints c, boolean includeBox) { 3356 if (includeBox) { 3357 makeStandardActionGrid(c, false); 3358 } else { 3359 makeNameTypeActionGrid(c, false); 3360 } 3361 3362 // Add the short text field 3363 c.gridy = 4; 3364 c.gridx = 0; 3365 c.anchor = java.awt.GridBagConstraints.EAST; 3366 _gridPanel.add(_shortActionLabel, c); 3367 c.gridx = 1; 3368 c.anchor = java.awt.GridBagConstraints.WEST; 3369 _gridPanel.add(_shortActionString, c); 3370 3371 makeChangeTriggerActionGrid(c); 3372 } 3373 3374 /** 3375 * Just a short text field, no name field. Used by set clock and jython 3376 * command. 3377 * 3378 * @param c The constraints object used for the grid construction 3379 */ 3380 void makeTypeShortActionGrid(GridBagConstraints c) { 3381 makeTypeActionGrid(c, false); 3382 3383 // Add the short text field 3384 c.gridy = 2; 3385 c.gridx = 0; 3386 c.anchor = java.awt.GridBagConstraints.EAST; 3387 _gridPanel.add(_shortActionLabel, c); 3388 c.gridx = 1; 3389 c.anchor = java.awt.GridBagConstraints.WEST; 3390 _gridPanel.add(_shortActionString, c); 3391 3392 makeChangeTriggerActionGrid(c); 3393 } 3394 3395 /** 3396 * Add the file selection components. 3397 * 3398 * @param c The constraints object used for the grid construction 3399 */ 3400 void makeFileActionGrid(GridBagConstraints c) { 3401 makeTypeActionGrid(c, false); 3402 3403 // Add the file selecttor 3404 c.gridy = 2; 3405 c.gridx = 0; 3406 c.anchor = java.awt.GridBagConstraints.EAST; 3407 _gridPanel.add(_shortActionLabel, c); 3408 c.gridx = 1; 3409 c.anchor = java.awt.GridBagConstraints.WEST; 3410 _gridPanel.add(_actionSetButton, c); 3411 3412 c.gridwidth = 2; // span both columns 3413 // Add the long text field 3414 c.gridy = 3; 3415 c.gridx = 0; 3416 c.anchor = java.awt.GridBagConstraints.CENTER; 3417 _gridPanel.add(_longActionString, c); 3418 c.gridwidth = 1; 3419 3420 makeChangeTriggerActionGrid(c); 3421 } 3422 3423 /** 3424 * Add the change/trigger box the grid. This is the last item in an Action 3425 * and is usually called from one of the other entry points. 3426 * 3427 * @param c The constraints object used for the grid construction 3428 */ 3429 void makeChangeTriggerActionGrid(GridBagConstraints c) { 3430 // Action item box 3431 c.gridy = 9; 3432 c.gridx = 0; 3433 c.anchor = java.awt.GridBagConstraints.EAST; 3434 JLabel row0Label = new JLabel(Bundle.getMessage("LabelActionOption")); // NOI18N 3435 row0Label.setToolTipText(Bundle.getMessage("ActionOptionHint")); // NOI18N 3436 _gridPanel.add(row0Label, c); 3437 c.gridx = 1; 3438 c.anchor = java.awt.GridBagConstraints.WEST; 3439 _gridPanel.add(_actionOptionBox, c); 3440 } 3441 3442 // ------------ Main Action methods ------------ 3443 3444 /** 3445 * Set display to show current action (curAction) parameters. 3446 */ 3447 void initializeActionVariables() { 3448 Conditional.Action actionType = _curAction.getType(); 3449 Conditional.ItemType itemType = actionType.getItemType(); 3450 log.debug("initializeActionVariables: itemType= {}, actionType= {}", itemType, actionType); // NOI18N 3451 _actionItemBox.setSelectedItem(itemType); 3452 _actionNameField.setText(_curAction.getDeviceName()); 3453 switch (itemType) { 3454 case NONE: 3455 _actionNameField.setText(""); 3456 break; 3457 3458 case SENSOR: 3459 _actionTypeBox.setSelectedItem(actionType); 3460 if ((actionType == Conditional.Action.RESET_DELAYED_SENSOR) 3461 || (actionType == Conditional.Action.DELAYED_SENSOR)) { 3462 _shortActionString.setText(_curAction.getActionString()); 3463 } 3464 if (actionType == Conditional.Action.SET_SENSOR 3465 || actionType == Conditional.Action.DELAYED_SENSOR 3466 || actionType == Conditional.Action.RESET_DELAYED_SENSOR) { 3467 if (_curAction.getActionData() == Sensor.ACTIVE) { 3468 _actionBox.setSelectedIndex(0); 3469 } else if (_curAction.getActionData() == Sensor.INACTIVE) { 3470 _actionBox.setSelectedIndex(1); 3471 } else if (_curAction.getActionData() == Route.TOGGLE) { 3472 _actionBox.setSelectedIndex(2); 3473 } 3474 } 3475 break; 3476 3477 case TURNOUT: 3478 _actionTypeBox.setSelectedItem(actionType); 3479 if ((actionType == Conditional.Action.RESET_DELAYED_TURNOUT) 3480 || (actionType == Conditional.Action.DELAYED_TURNOUT)) { 3481 _shortActionString.setText(_curAction.getActionString()); 3482 } 3483 if ((actionType == Conditional.Action.SET_TURNOUT) 3484 || (actionType == Conditional.Action.RESET_DELAYED_TURNOUT) 3485 || (actionType == Conditional.Action.DELAYED_TURNOUT)) { 3486 if (_curAction.getActionData() == Turnout.CLOSED) { 3487 _actionBox.setSelectedIndex(0); 3488 } else if (_curAction.getActionData() == Turnout.THROWN) { 3489 _actionBox.setSelectedIndex(1); 3490 } else if (_curAction.getActionData() == Route.TOGGLE) { 3491 _actionBox.setSelectedIndex(2); 3492 } 3493 } else if (actionType == Conditional.Action.LOCK_TURNOUT) { 3494 if (_curAction.getActionData() == Turnout.UNLOCKED) { 3495 _actionBox.setSelectedIndex(0); 3496 } else if (_curAction.getActionData() == Turnout.LOCKED) { 3497 _actionBox.setSelectedIndex(1); 3498 } else if (_curAction.getActionData() == Route.TOGGLE) { 3499 _actionBox.setSelectedIndex(2); 3500 } 3501 } 3502 break; 3503 3504 case LIGHT: 3505 _actionTypeBox.setSelectedItem(actionType); 3506 if (actionType == Conditional.Action.SET_LIGHT) { 3507 if (_curAction.getActionData() == Light.ON) { 3508 _actionBox.setSelectedIndex(0); 3509 } else if (_curAction.getActionData() == Light.OFF) { 3510 _actionBox.setSelectedIndex(1); 3511 } else if (_curAction.getActionData() == Route.TOGGLE) { 3512 _actionBox.setSelectedIndex(2); 3513 } 3514 } else if ((actionType == Conditional.Action.SET_LIGHT_INTENSITY) 3515 || (actionType == Conditional.Action.SET_LIGHT_TRANSITION_TIME)) { 3516 _shortActionString.setText(_curAction.getActionString()); 3517 } 3518 break; 3519 3520 case SIGNALHEAD: 3521 _actionTypeBox.setSelectedItem(actionType); 3522 if (actionType == Conditional.Action.SET_SIGNAL_APPEARANCE) { 3523 loadJComboBoxWithHeadAppearances(_actionBox, _actionNameField.getText().trim()); 3524 } 3525 break; 3526 3527 case CLOCK: 3528 _actionTypeBox.setSelectedItem(actionType); 3529 if (actionType == Conditional.Action.SET_FAST_CLOCK_TIME) { 3530 int time = _curAction.getActionData(); 3531 _longActionString.setText(formatTime(time / 60, time - ((time / 60) * 60))); 3532 _actionNameField.setText(""); 3533 } 3534 break; 3535 3536 case MEMORY: 3537 _actionTypeBox.setSelectedItem(actionType); 3538 _shortActionString.setText(_curAction.getActionString()); 3539 break; 3540 3541 case WARRANT: 3542 _actionTypeBox.setSelectedItem(actionType); 3543 if (actionType == Conditional.Action.CONTROL_TRAIN) { 3544 switch (_curAction.getActionData()) { 3545 case Warrant.HALT: 3546 _actionBox.setSelectedIndex(0); 3547 break; 3548 case Warrant.RESUME: 3549 _actionBox.setSelectedIndex(1); 3550 break; 3551 case Warrant.RETRY_FWD: 3552 _actionBox.setSelectedIndex(2); 3553 break; 3554 case Warrant.SPEED_UP: 3555 _actionBox.setSelectedIndex(3); 3556 break; 3557 case Warrant.STOP: 3558 _actionBox.setSelectedIndex(4); 3559 break; 3560 case Warrant.ESTOP: 3561 _actionBox.setSelectedIndex(5); 3562 break; 3563 case Warrant.ABORT: 3564 _actionBox.setSelectedIndex(6); 3565 break; 3566 default: 3567 log.warn("Unexpected _curAction.getActionData() of {}", _curAction.getActionData()); // NOI18N 3568 } 3569 } else if (actionType == Conditional.Action.SET_TRAIN_ID 3570 || actionType == Conditional.Action.SET_TRAIN_NAME) { 3571 _shortActionString.setText(_curAction.getActionString()); 3572 } 3573 break; 3574 3575 case OBLOCK: 3576 _actionTypeBox.setSelectedItem(actionType); 3577 if (actionType == Conditional.Action.SET_BLOCK_VALUE 3578 || actionType == Conditional.Action.SET_TRAIN_NAME 3579 || actionType == Conditional.Action.GET_TRAIN_LOCATION) { 3580 _shortActionString.setText(_curAction.getActionString()); 3581 } 3582 break; 3583 3584 case ENTRYEXIT: 3585 _actionNameField.setText(_curAction.getBean().getUserName()); 3586 _actionTypeBox.setSelectedItem(actionType); 3587 break; 3588 3589 case AUDIO: 3590 _actionTypeBox.setSelectedItem(actionType); 3591 if (actionType == Conditional.Action.PLAY_SOUND) { 3592 _longActionString.setText(_curAction.getActionString()); 3593 } else if (actionType == Conditional.Action.CONTROL_AUDIO) { 3594 switch (_curAction.getActionData()) { 3595 case Audio.CMD_PLAY: 3596 _actionBox.setSelectedIndex(0); 3597 break; 3598 case Audio.CMD_STOP: 3599 _actionBox.setSelectedIndex(1); 3600 break; 3601 case Audio.CMD_PLAY_TOGGLE: 3602 _actionBox.setSelectedIndex(2); 3603 break; 3604 case Audio.CMD_PAUSE: 3605 _actionBox.setSelectedIndex(3); 3606 break; 3607 case Audio.CMD_RESUME: 3608 _actionBox.setSelectedIndex(4); 3609 break; 3610 case Audio.CMD_PAUSE_TOGGLE: 3611 _actionBox.setSelectedIndex(5); 3612 break; 3613 case Audio.CMD_REWIND: 3614 _actionBox.setSelectedIndex(6); 3615 break; 3616 case Audio.CMD_FADE_IN: 3617 _actionBox.setSelectedIndex(7); 3618 break; 3619 case Audio.CMD_FADE_OUT: 3620 _actionBox.setSelectedIndex(8); 3621 break; 3622 case Audio.CMD_RESET_POSITION: 3623 _actionBox.setSelectedIndex(9); 3624 break; 3625 default: 3626 log.warn("Unexpected _curAction.getActionData() of {}", _curAction.getActionData()); // NOI18N 3627 break; 3628 } 3629 } 3630 break; 3631 3632 case SCRIPT: 3633 _actionTypeBox.setSelectedItem(actionType); 3634 if (actionType == Conditional.Action.RUN_SCRIPT) { 3635 _longActionString.setText(_curAction.getActionString()); 3636 } else if (actionType == Conditional.Action.JYTHON_COMMAND) { 3637 _shortActionString.setText(_curAction.getActionString()); 3638 } 3639 break; 3640 3641 case SIGNALMAST: 3642 case LOGIX: 3643 case OTHER: // ACTION_TRIGGER_ROUTE 3644 _actionTypeBox.setSelectedItem(actionType); 3645 break; 3646 3647 default: 3648 log.error("Unhandled type: {}", itemType); // NOI18N 3649 break; 3650 } 3651 _actionOptionBox.setSelectedIndex(_curAction.getOption() - 1); 3652 } 3653 3654 /** 3655 * Respond to a change in an Action Type comboBox. 3656 * <p> 3657 * Set components visible for the selected type. 3658 * 3659 * @param type index of the newly selected Action type 3660 */ 3661 void actionItemChanged(Conditional.ItemType type) { 3662 Conditional.Action actionType = _curAction.getType(); 3663 log.debug("actionItemChanged: itemType= {}, actionType= {}", type, actionType); // NOI18N 3664 _detailGrid.setVisible(false); 3665 _actionTypeBox.removeActionListener(_actionTypeListener); 3666 _shortActionString.setText(""); 3667 _longActionString.setText(""); 3668 _actionTypeBox.removeAllItems(); 3669 _actionTypeBox.addItem(Conditional.Action.NONE); 3670 _actionBox.removeAllItems(); 3671 Conditional.ItemType itemType = actionType.getItemType(); 3672 if (type != Conditional.ItemType.NONE) { // actionItem listener choice overrides current item 3673 itemType = type; 3674 } 3675 if (itemType != actionType.getItemType()) { 3676 actionType = Conditional.Action.NONE; // chosen item type does not support action type 3677 } 3678 3679 _actionNameField.removeActionListener(actionSignalHeadNameListener); 3680 _actionNameField.removeActionListener(actionSignalMastNameListener); 3681 3682 if (_comboNameBox != null) { 3683 for (ActionListener item : _comboNameBox.getActionListeners()) { 3684 _comboNameBox.removeActionListener(item); 3685 } 3686 _comboNameBox.removeFocusListener(detailFocusEvent); 3687 } 3688 setPickWindow("Action", itemType); // NOI18N 3689 3690 switch (itemType) { 3691 case NONE: 3692 makeDetailGrid("EmptyAction"); // NOI18N 3693 break; 3694 3695 case TURNOUT: 3696 _actionNameLabel.setToolTipText(Bundle.getMessage("NameHintTurnout")); // NOI18N 3697 String turnoutGrid = "NameTypeAction"; // NOI18N 3698 boolean delayTurnout = false; 3699 3700 for (Conditional.Action action : Conditional.Action.getTurnoutItems()) { 3701 _actionTypeBox.addItem(action); 3702 } 3703 3704 if ((actionType == Conditional.Action.RESET_DELAYED_TURNOUT) 3705 || (actionType == Conditional.Action.DELAYED_TURNOUT)) { 3706 delayTurnout = true; 3707 _shortActionLabel.setText(Bundle.getMessage("LabelDelayTime")); // NOI18N 3708 _shortActionLabel.setToolTipText(Bundle.getMessage("DataHintDelayedTurnout")); // NOI18N 3709 } 3710 if ((actionType == Conditional.Action.SET_TURNOUT) 3711 || (actionType == Conditional.Action.RESET_DELAYED_TURNOUT) 3712 || (actionType == Conditional.Action.DELAYED_TURNOUT)) { 3713 turnoutGrid = (delayTurnout) ? "ShortFieldAction" : "StandardAction"; // NOI18N 3714 _actionBoxLabel.setText(Bundle.getMessage("LabelActionTurnout")); // NOI18N 3715 _actionBoxLabel.setToolTipText(Bundle.getMessage("TurnoutSetHint")); // NOI18N 3716 _actionBox.addItem(Bundle.getMessage("TurnoutStateClosed")); // NOI18N 3717 _actionBox.addItem(Bundle.getMessage("TurnoutStateThrown")); // NOI18N 3718 _actionBox.addItem(Bundle.getMessage("Toggle")); // NOI18N 3719 } else if (actionType == Conditional.Action.LOCK_TURNOUT) { 3720 turnoutGrid = (delayTurnout) ? "ShortFieldAction" : "StandardAction"; // NOI18N 3721 _actionBoxLabel.setText(Bundle.getMessage("LabelActionLock")); // NOI18N 3722 _actionBoxLabel.setToolTipText(Bundle.getMessage("LockSetHint")); // NOI18N 3723 _actionBox.addItem(Bundle.getMessage("TurnoutUnlock")); // NOI18N 3724 _actionBox.addItem(Bundle.getMessage("TurnoutLock")); // NOI18N 3725 _actionBox.addItem(Bundle.getMessage("Toggle")); // NOI18N 3726 } else if ((actionType == Conditional.Action.CANCEL_TURNOUT_TIMERS) 3727 || (actionType == Conditional.Action.NONE)) { 3728 turnoutGrid = "NameTypeActionFinal"; // NOI18N 3729 } 3730 3731 setActionNameBox(itemType); 3732 makeDetailGrid(turnoutGrid); 3733 break; 3734 3735 case SENSOR: 3736 _actionNameLabel.setToolTipText(Bundle.getMessage("NameHintSensor")); // NOI18N 3737 String sensorGrid = "NameTypeAction"; // NOI18N 3738 boolean delaySensor = false; 3739 3740 for (Conditional.Action action : Conditional.Action.getSensorItems()) { 3741 _actionTypeBox.addItem(action); 3742 } 3743 if ((actionType == Conditional.Action.RESET_DELAYED_SENSOR) 3744 || (actionType == Conditional.Action.DELAYED_SENSOR)) { 3745 delaySensor = true; 3746 _shortActionLabel.setText(Bundle.getMessage("LabelDelayTime")); // NOI18N 3747 _shortActionLabel.setToolTipText(Bundle.getMessage("DataHintDelayedSensor")); // NOI18N 3748 } 3749 if ((actionType == Conditional.Action.SET_SENSOR) 3750 || (actionType == Conditional.Action.RESET_DELAYED_SENSOR) 3751 || (actionType == Conditional.Action.DELAYED_SENSOR)) { 3752 sensorGrid = (delaySensor) ? "ShortFieldAction" : "StandardAction"; // NOI18N 3753 _actionBoxLabel.setText(Bundle.getMessage("LabelActionSensor")); // NOI18N 3754 _actionBoxLabel.setToolTipText(Bundle.getMessage("SensorSetHint")); // NOI18N 3755 _actionBox.addItem(Bundle.getMessage("SensorStateActive")); // NOI18N 3756 _actionBox.addItem(Bundle.getMessage("SensorStateInactive")); // NOI18N 3757 _actionBox.addItem(Bundle.getMessage("Toggle")); // NOI18N 3758 } else if ((actionType == Conditional.Action.CANCEL_SENSOR_TIMERS) 3759 || (actionType == Conditional.Action.NONE)) { 3760 sensorGrid = "NameTypeActionFinal"; // NOI18N 3761 } 3762 3763 setActionNameBox(itemType); 3764 makeDetailGrid(sensorGrid); 3765 break; 3766 3767 case SIGNALHEAD: 3768 _actionNameLabel.setToolTipText(Bundle.getMessage("NameHintSignal")); // NOI18N 3769 String signalHeadGrid = "NameTypeAction"; // NOI18N 3770 _actionNameField.addActionListener(actionSignalHeadNameListener); 3771 3772 for (Conditional.Action action : Conditional.Action.getSignalHeadItems()) { 3773 _actionTypeBox.addItem(action); 3774 } 3775 3776 if (actionType == Conditional.Action.SET_SIGNAL_APPEARANCE) { 3777 signalHeadGrid = "StandardAction"; // NOI18N 3778 _actionBoxLabel.setText(Bundle.getMessage("LabelActionSignal")); // NOI18N 3779 _actionBoxLabel.setToolTipText(Bundle.getMessage("SignalSetHint")); // NOI18N 3780 loadJComboBoxWithHeadAppearances(_actionBox, _actionNameField.getText().trim()); 3781 _actionBox.setSelectedItem(_curAction.getActionDataString()); 3782 } else if (actionType != Conditional.Action.NONE) { 3783 signalHeadGrid = "NameTypeActionFinal"; // NOI18N 3784 } 3785 3786 setActionNameBox(itemType); 3787 makeDetailGrid(signalHeadGrid); 3788 break; 3789 3790 case SIGNALMAST: 3791 _actionNameLabel.setToolTipText(Bundle.getMessage("NameHintSignalMast")); // NOI18N 3792 String signalMastGrid = "NameTypeAction"; // NOI18N 3793 _actionNameField.addActionListener(actionSignalMastNameListener); 3794 3795 for (Conditional.Action action : Conditional.Action.getSignalMastItems()) { 3796 _actionTypeBox.addItem(action); 3797 } 3798 3799 if (actionType == Conditional.Action.SET_SIGNALMAST_ASPECT) { 3800 signalMastGrid = "StandardAction"; // NOI18N 3801 _actionBoxLabel.setText(Bundle.getMessage("LabelSignalAspect")); // NOI18N 3802 _actionBoxLabel.setToolTipText(Bundle.getMessage("SignalMastSetHint")); // NOI18N 3803 loadJComboBoxWithMastAspects(_actionBox, _actionNameField.getText().trim()); 3804 _actionBox.setSelectedItem(_curAction.getActionDataString()); 3805 } else if (actionType != Conditional.Action.NONE) { 3806 signalMastGrid = "NameTypeActionFinal"; // NOI18N 3807 } 3808 3809 setActionNameBox(itemType); 3810 makeDetailGrid(signalMastGrid); 3811 break; 3812 3813 case LIGHT: 3814 _actionNameLabel.setToolTipText(Bundle.getMessage("NameHintLight")); // NOI18N 3815 String lightGrid = "NameTypeAction"; // NOI18N 3816 3817 for (Conditional.Action action : Conditional.Action.getLightItems()) { 3818 _actionTypeBox.addItem(action); 3819 } 3820 3821 if (actionType == Conditional.Action.SET_LIGHT_INTENSITY) { 3822 lightGrid = "ShortFieldNoBoxAction"; // NOI18N 3823 _shortActionLabel.setText(Bundle.getMessage("LabelLightIntensity")); // NOI18N 3824 _shortActionLabel.setToolTipText(Bundle.getMessage("DataHintLightIntensity")); // NOI18N 3825 } else if (actionType == Conditional.Action.SET_LIGHT_TRANSITION_TIME) { 3826 lightGrid = "ShortFieldNoBoxAction"; // NOI18N 3827 _shortActionLabel.setText(Bundle.getMessage("LabelTransitionTime")); // NOI18N 3828 _shortActionLabel.setToolTipText(Bundle.getMessage("DataHintLightTransitionTime")); // NOI18N 3829 } else if (actionType == Conditional.Action.SET_LIGHT) { 3830 lightGrid = "StandardAction"; // NOI18N 3831 _actionBoxLabel.setText(Bundle.getMessage("LabelActionLight")); // NOI18N 3832 _actionBoxLabel.setToolTipText(Bundle.getMessage("LightSetHint")); // NOI18N 3833 _actionBox.addItem(Bundle.getMessage("LightOn")); // NOI18N 3834 _actionBox.addItem(Bundle.getMessage("LightOff")); // NOI18N 3835 _actionBox.addItem(Bundle.getMessage("Toggle")); // NOI18N 3836 } 3837 3838 setActionNameBox(itemType); 3839 makeDetailGrid(lightGrid); 3840 break; 3841 3842 case MEMORY: 3843 _actionNameLabel.setToolTipText(Bundle.getMessage("NameHintMemory")); // NOI18N 3844 String memoryGrid = "NameTypeAction"; // NOI18N 3845 3846 for (Conditional.Action action : Conditional.Action.getMemoryItems()) { 3847 _actionTypeBox.addItem(action); 3848 } 3849 3850 if (actionType == Conditional.Action.COPY_MEMORY) { 3851 memoryGrid = "ShortFieldNoBoxAction"; // NOI18N 3852 _shortActionLabel.setText(Bundle.getMessage("LabelMemoryLocation")); // NOI18N 3853 _shortActionLabel.setToolTipText(Bundle.getMessage("DataHintToMemory")); // NOI18N 3854 } else if (actionType == Conditional.Action.SET_MEMORY) { 3855 memoryGrid = "ShortFieldNoBoxAction"; // NOI18N 3856 _shortActionLabel.setText(Bundle.getMessage("LabelValue")); // NOI18N 3857 _shortActionLabel.setToolTipText(Bundle.getMessage("DataHintMemory")); // NOI18N 3858 } 3859 3860 setActionNameBox(itemType); 3861 makeDetailGrid(memoryGrid); 3862 break; 3863 3864 case CLOCK: 3865 String clockGrid = "TypeAction"; // NOI18N 3866 3867 for (Conditional.Action action : Conditional.Action.getClockItems()) { 3868 _actionTypeBox.addItem(action); 3869 } 3870 3871 if (actionType == Conditional.Action.SET_FAST_CLOCK_TIME) { 3872 clockGrid = "TypeShortAction"; // NOI18N 3873 _shortActionLabel.setText(Bundle.getMessage("LabelSetTime")); // NOI18N 3874 _shortActionLabel.setToolTipText(Bundle.getMessage("DataHintTime")); // NOI18N 3875 } else if ((actionType == Conditional.Action.START_FAST_CLOCK) 3876 || (actionType == Conditional.Action.STOP_FAST_CLOCK)) { 3877 clockGrid = "TypeActionFinal"; // NOI18N 3878 } 3879 3880 makeDetailGrid(clockGrid); 3881 break; 3882 3883 case LOGIX: 3884 _actionNameLabel.setToolTipText(Bundle.getMessage("NameHintLogix")); // NOI18N 3885 String logixGrid = "NameTypeAction"; // NOI18N 3886 3887 for (Conditional.Action action : Conditional.Action.getLogixItems()) { 3888 _actionTypeBox.addItem(action); 3889 } 3890 3891 if ((actionType == Conditional.Action.ENABLE_LOGIX) 3892 || (actionType == Conditional.Action.DISABLE_LOGIX)) { 3893 logixGrid = "NameTypeActionFinal"; // NOI18N 3894 } 3895 3896 setActionNameBox(itemType); 3897 makeDetailGrid(logixGrid); 3898 break; 3899 3900 case WARRANT: 3901 _actionNameLabel.setToolTipText(Bundle.getMessage("NameHintWarrant")); // NOI18N 3902 String warrantGrid = "NameTypeAction"; // NOI18N 3903 3904 for (Conditional.Action action : Conditional.Action.getWarrantItems()) { 3905 _actionTypeBox.addItem(action); 3906 } 3907 3908 if (actionType == Conditional.Action.CONTROL_TRAIN) { 3909 warrantGrid = "StandardAction"; // NOI18N 3910 _actionBoxLabel.setText(Bundle.getMessage("LabelControlTrain")); // NOI18N 3911 _actionBoxLabel.setToolTipText(Bundle.getMessage("DataHintTrainControl")); // NOI18N 3912 _actionBox.addItem(Bundle.getMessage("WarrantHalt")); 3913 _actionBox.addItem(Bundle.getMessage("WarrantResume")); 3914 _actionBox.addItem(Bundle.getMessage("WarrantMoveToNext")); 3915 _actionBox.addItem(Bundle.getMessage("WarrantSpeedUp")); 3916 _actionBox.addItem(Bundle.getMessage("WarrantStop")); 3917 _actionBox.addItem(Bundle.getMessage("WarantEStop")); 3918 _actionBox.addItem(Bundle.getMessage("WarrantAbort")); 3919 } else if (actionType == Conditional.Action.SET_TRAIN_ID 3920 || actionType == Conditional.Action.SET_TRAIN_NAME 3921 || actionType == Conditional.Action.GET_TRAIN_LOCATION) { 3922 warrantGrid = "ShortFieldNoBoxAction"; // NOI18N 3923 if (actionType == Conditional.Action.SET_TRAIN_ID) { 3924 _shortActionLabel.setText(Bundle.getMessage("LabelTrainId")); // NOI18N 3925 _shortActionLabel.setToolTipText(Bundle.getMessage("DataHintTrainId")); // NOI18N 3926 } else if (actionType == Conditional.Action.SET_TRAIN_NAME) { 3927 _shortActionLabel.setText(Bundle.getMessage("LabelTrainName")); // NOI18N 3928 _shortActionLabel.setToolTipText(Bundle.getMessage("DataHintTrainName")); // NOI18N 3929 } else if (actionType == Conditional.Action.GET_TRAIN_LOCATION) { 3930 _shortActionLabel.setText(Bundle.getMessage("LabelMemoryLocation")); // NOI18N 3931 _shortActionLabel.setToolTipText(Bundle.getMessage("DataHintToMemory")); // NOI18N 3932 } 3933 } 3934 setActionNameBox(itemType); 3935 makeDetailGrid(warrantGrid); 3936 break; 3937 3938 case OBLOCK: 3939 _actionNameLabel.setToolTipText(Bundle.getMessage("NameHintOBlock")); // NOI18N 3940 String oblockGrid = "NameTypeAction"; // NOI18N 3941 3942 for (Conditional.Action action : Conditional.Action.getOBlockItems()) { 3943 _actionTypeBox.addItem(action); 3944 } 3945 if (actionType == Conditional.Action.SET_BLOCK_VALUE) { 3946 _shortActionLabel.setText(Bundle.getMessage("LabelBlockValue")); // NOI18N 3947 _shortActionLabel.setToolTipText(Bundle.getMessage("DataHintBlockValue")); // NOI18N 3948 oblockGrid = "ShortFieldNoBoxAction"; // NOI18N 3949 } else if(actionType == Conditional.Action.GET_BLOCK_TRAIN_NAME 3950 || actionType == Conditional.Action.GET_BLOCK_WARRANT) { 3951 _shortActionLabel.setText(Bundle.getMessage("LabelMemoryLocation")); // NOI18N 3952 _shortActionLabel.setToolTipText(Bundle.getMessage("DataHintToMemory")); // NOI18N 3953 oblockGrid = "ShortFieldNoBoxAction"; // NOI18N 3954 } else { 3955 oblockGrid = "NameTypeActionFinal"; // NOI18N 3956 } 3957 3958 setActionNameBox(itemType); 3959 makeDetailGrid(oblockGrid); 3960 break; 3961 3962 case ENTRYEXIT: 3963 for (Conditional.Action action : Conditional.Action.getEntryExitItems()) { 3964 _actionTypeBox.addItem(action); 3965 } 3966 setActionNameBox(itemType); 3967 makeDetailGrid("NameTypeActionFinal"); 3968 break; 3969 3970 case AUDIO: 3971 _actionNameLabel.setToolTipText(Bundle.getMessage("NameHintOBlock")); // NOI18N 3972 String audioGrid = "TypeAction"; // NOI18N 3973 3974 for (Conditional.Action action : Conditional.Action.getAudioItems()) { 3975 _actionTypeBox.addItem(action); 3976 } 3977 3978 if (actionType == Conditional.Action.PLAY_SOUND) { 3979 audioGrid = "FileAction"; // NOI18N 3980 _shortActionLabel.setText(Bundle.getMessage("LabelSelectFile")); // NOI18N 3981 _actionSetButton.setToolTipText(Bundle.getMessage("SetHintSound")); // NOI18N 3982 } else if (actionType == Conditional.Action.CONTROL_AUDIO) { 3983 audioGrid = "StandardAction"; // NOI18N 3984 _actionNameLabel.setToolTipText(Bundle.getMessage("NameHintAudio")); // NOI18N 3985 _actionBoxLabel.setText(Bundle.getMessage("LabelActionAudio")); // NOI18N 3986 _actionBoxLabel.setToolTipText(Bundle.getMessage("SetHintAudio")); // NOI18N 3987 _actionBox.addItem(Bundle.getMessage("AudioSourcePlay")); // NOI18N 3988 _actionBox.addItem(Bundle.getMessage("AudioSourceStop")); // NOI18N 3989 _actionBox.addItem(Bundle.getMessage("AudioSourcePlayToggle")); // NOI18N 3990 _actionBox.addItem(Bundle.getMessage("AudioSourcePause")); // NOI18N 3991 _actionBox.addItem(Bundle.getMessage("AudioSourceResume")); // NOI18N 3992 _actionBox.addItem(Bundle.getMessage("AudioSourcePauseToggle")); // NOI18N 3993 _actionBox.addItem(Bundle.getMessage("AudioSourceRewind")); // NOI18N 3994 _actionBox.addItem(Bundle.getMessage("AudioSourceFadeIn")); // NOI18N 3995 _actionBox.addItem(Bundle.getMessage("AudioSourceFadeOut")); // NOI18N 3996 _actionBox.addItem(Bundle.getMessage("AudioResetPosition")); // NOI18N 3997 } 3998 3999 makeDetailGrid(audioGrid); 4000 break; 4001 4002 case SCRIPT: 4003 String scriptGrid = "TypeAction"; // NOI18N 4004 4005 for (Conditional.Action action : Conditional.Action.getScriptItems()) { 4006 _actionTypeBox.addItem(action); 4007 } 4008 4009 if (actionType == Conditional.Action.RUN_SCRIPT) { 4010 scriptGrid = "FileAction"; // NOI18N 4011 _shortActionLabel.setText(Bundle.getMessage("LabelSelectFile")); // NOI18N 4012 _actionSetButton.setToolTipText(Bundle.getMessage("SetHintScript")); // NOI18N 4013 } else if (actionType == Conditional.Action.JYTHON_COMMAND) { 4014 scriptGrid = "TypeShortAction"; // NOI18N 4015 _shortActionLabel.setText(Bundle.getMessage("LabelScriptCommand")); // NOI18N 4016 _shortActionLabel.setToolTipText(Bundle.getMessage("SetHintJythonCmd")); // NOI18N 4017 } 4018 4019 makeDetailGrid(scriptGrid); 4020 break; 4021 4022 case OTHER: 4023 String otherGrid = "TypeAction"; // NOI18N 4024 4025 for (Conditional.Action action : Conditional.Action.getOtherItems()) { 4026 _actionTypeBox.addItem(action); 4027 } 4028 4029 if (actionType == Conditional.Action.TRIGGER_ROUTE) { 4030 otherGrid = "NameTypeActionFinal"; // NOI18N 4031 _actionNameLabel.setToolTipText(Bundle.getMessage("NameHintRoute")); // NOI18N 4032 } 4033 4034 setActionNameBox(itemType); 4035 makeDetailGrid(otherGrid); 4036 break; 4037 4038 default: 4039 break; 4040 } 4041 _actionTypeListener.setItemType(itemType); 4042 _actionTypeBox.addActionListener(_actionTypeListener); 4043 } 4044 4045 /** 4046 * Update the name combo box selection based on the current contents of the 4047 * name field. 4048 * 4049 * @since 4.7.3 4050 * @param itemType The item type, such as sensor or turnout. 4051 */ 4052 void setActionNameBox(Conditional.ItemType itemType) { 4053 if (_selectionMode != SelectionMode.USECOMBO) { 4054 return; 4055 } 4056 _comboNameBox = createNameBox(itemType); 4057 if (_comboNameBox == null) { 4058 return; 4059 } 4060 // Select the current entry 4061 _comboNameBox.setSelectedItemByName(_curAction.getDeviceName()); 4062 _comboNameBox.addActionListener(new NameBoxListener(_actionNameField)); 4063 _comboNameBox.addFocusListener(detailFocusEvent); 4064 } 4065 4066 // ------------ Action detail methods ------------ 4067 4068 /** 4069 * Respond to Cancel action button and window closer of the Edit Action 4070 * window. 4071 * <p> 4072 * Also does cleanup of Update and Delete buttons. 4073 */ 4074 void cancelEditAction() { 4075 if (_newActionItem) { 4076 _newActionItem = false; 4077 deletePressed(); 4078 } 4079 cleanUpAction(); 4080 } 4081 4082 /** 4083 * Respond to Update button. 4084 */ 4085 void updateAction() { 4086 if (!validateAction()) { 4087 return; 4088 } 4089 _newActionItem = false; 4090 updateActionList(); 4091 4092 // Update the Action node 4093 _curNode.setText(_curAction.description(_triggerMode)); 4094 _cdlModel.nodeChanged(_curNode); 4095 cleanUpAction(); 4096 } 4097 4098 /** 4099 * Clean up Update and Delete Action buttons. 4100 */ 4101 void cleanUpAction() { 4102 setMoveButtons(); 4103 } 4104 4105 /*.* 4106 * Convert user setting in Conditional Action configuration pane to integer 4107 * for processing. 4108 * 4109 * @param itemType value for current item type 4110 * @param actionTypeSelection index of selected item in configuration 4111 * comboBox 4112 * @return integer representing the selected action 4113 */ 4114/* static Conditional.Action getActionTypeFromBox(Conditional.ItemType itemType, int actionTypeSelection) { 4115// if (itemType < 0 || actionTypeSelection < 0) { 4116// return Conditional.Action.NONE; 4117// } 4118 if (actionTypeSelection < 0) { 4119 return Conditional.Action.NONE; 4120 } 4121 switch (itemType) { 4122 case SENSOR: 4123 return Conditional.Action.getSensorItems().get(actionTypeSelection); 4124 case TURNOUT: 4125 return Conditional.Action.getTurnoutItems().get(actionTypeSelection); 4126 case LIGHT: 4127 return Conditional.Action.getLightItems().get(actionTypeSelection); 4128 case SIGNALHEAD: 4129 return Conditional.Action.getSignalHeadItems().get(actionTypeSelection); 4130 case SIGNALMAST: 4131 return Conditional.Action.getSignalMastItems().get(actionTypeSelection); 4132 case MEMORY: 4133 return Conditional.Action.getMemoryItems().get(actionTypeSelection); 4134 case LOGIX: 4135 return Conditional.Action.getLogixItems().get(actionTypeSelection); 4136 case WARRANT: 4137 return Conditional.Action.getWarrantItems().get(actionTypeSelection); 4138 case OBLOCK: 4139 return Conditional.Action.getOBlockItems().get(actionTypeSelection); 4140 case CLOCK: 4141 return Conditional.Action.getClockItems().get(actionTypeSelection); 4142 case AUDIO: 4143 return Conditional.Action.getAudioItems().get(actionTypeSelection); 4144 case SCRIPT: 4145 return Conditional.Action.getScriptItems().get(actionTypeSelection); 4146 case OTHER: 4147 return Conditional.Action.getOtherItems().get(actionTypeSelection); 4148 case ENTRYEXIT: 4149 return Conditional.Action.getEntryExitItems().get(actionTypeSelection); 4150 default: 4151 // fall through 4152 break; 4153 } 4154 return Conditional.Action.NONE; 4155 } 4156*/ 4157 JFileChooser sndFileChooser = null; 4158 ScriptFileChooser scriptFileChooser = null; 4159 JFileChooser defaultFileChooser = null; 4160 4161 /** 4162 * Respond to the [...] button in the Edit Action window action section. 4163 * <p> 4164 * Ask user to select an audio or python script file on disk. 4165 * 4166 * @param e the event heard 4167 */ 4168 void setFileLocation(ActionEvent e) { 4169 ConditionalAction action = _actionList.get(_curNodeRow); 4170 JFileChooser currentChooser; 4171 Conditional.Action actionType = action.getType(); 4172 if (actionType == Conditional.Action.PLAY_SOUND) { 4173 if (sndFileChooser == null) { 4174 sndFileChooser = new jmri.util.swing.JmriJFileChooser(System.getProperty("user.dir") // NOI18N 4175 + java.io.File.separator + "resources" // NOI18N 4176 + java.io.File.separator + "sounds"); // NOI18N 4177 sndFileChooser.setFileFilter(new FileNameExtensionFilter("wav sound files", "wav")); // NOI18N 4178 } 4179 currentChooser = sndFileChooser; 4180 } else if (actionType == Conditional.Action.RUN_SCRIPT) { 4181 if (scriptFileChooser == null) { 4182 scriptFileChooser = new ScriptFileChooser(FileUtil.getScriptsPath()); 4183 } 4184 currentChooser = scriptFileChooser; 4185 } else { 4186 log.warn("Unexpected actionType[{}] = {}", actionType.name(), actionType); // NOI18N 4187 if (defaultFileChooser == null) { 4188 defaultFileChooser = new jmri.util.swing.JmriJFileChooser(FileUtil.getUserFilesPath()); 4189 defaultFileChooser.setFileFilter(new jmri.util.NoArchiveFileFilter()); 4190 } 4191 currentChooser = defaultFileChooser; 4192 } 4193 4194 currentChooser.rescanCurrentDirectory(); 4195 int retVal = currentChooser.showOpenDialog(null); 4196 // handle selection or cancel 4197 if (retVal == JFileChooser.APPROVE_OPTION) { 4198 // set selected file location in data string 4199 try { 4200 _longActionString.setText(FileUtil.getPortableFilename(currentChooser.getSelectedFile().getCanonicalPath())); 4201 } catch (java.io.IOException ex) { 4202 if (log.isDebugEnabled()) { 4203 log.error("exception setting file location: ", ex); // NOI18N 4204 } 4205 _longActionString.setText(""); 4206 } 4207 } 4208 } 4209 4210 // ------------ Action update processes ------------ 4211 4212 /** 4213 * Validate Action data from Edit Action Window, and transfer it to current 4214 * action object as appropriate. 4215 * <p> 4216 * Messages are sent to the user for any errors found. This routine returns 4217 * false immediately after finding an error, even if there might be more 4218 * errors. 4219 * 4220 * @return true if all data checks out OK, otherwise false. 4221 */ 4222 boolean validateAction() { 4223 Conditional.ItemType itemType = _actionItemBox.getItemAt(_actionItemBox.getSelectedIndex()); 4224 Conditional.Action actionType = Conditional.Action.NONE; 4225 Conditional.Action selection = _actionTypeBox.getItemAt(_actionTypeBox.getSelectedIndex()); 4226 if (selection == Conditional.Action.NONE) { 4227 JmriJOptionPane.showMessageDialog( 4228 _editLogixFrame, Bundle.getMessage("makeSelection"), 4229 Bundle.getMessage("WarningTitle"), JmriJOptionPane.WARNING_MESSAGE); 4230 return false; 4231 } 4232 String name = _actionNameField.getText().trim(); 4233 String actionString = _shortActionString.getText().trim(); 4234 _curAction.setActionString(""); 4235 _curAction.setActionData(-1); 4236 boolean referenceByMemory = false; 4237 if (name.length() > 0 && name.charAt(0) == '@') { 4238 String memName = name.substring(1); 4239 if (!confirmIndirectMemory(memName)) { 4240 return false; 4241 } 4242 memName = validateMemoryReference(memName); 4243 if (memName == null) { 4244 return false; 4245 } 4246 referenceByMemory = true; 4247 } 4248 if (!checkIsVariable(name, itemType) ) { 4249 return false; 4250 } 4251 switch (itemType) { 4252 case SENSOR: 4253 if (!referenceByMemory) { 4254 name = validateSensorReference(name); 4255 if (name == null) { 4256 return false; 4257 } 4258 } 4259 actionType = selection; 4260 if ((actionType == Conditional.Action.RESET_DELAYED_SENSOR) 4261 || (actionType == Conditional.Action.DELAYED_SENSOR)) { 4262 if (!validateTimeReference(actionType, actionString)) { 4263 return (false); 4264 } 4265 _curAction.setActionString(actionString); 4266 } 4267 if ((actionType == Conditional.Action.SET_SENSOR) 4268 || (actionType == Conditional.Action.RESET_DELAYED_SENSOR) 4269 || (actionType == Conditional.Action.DELAYED_SENSOR)) { 4270 if (_actionBox.getSelectedIndex() == 0) { 4271 _curAction.setActionData(Sensor.ACTIVE); 4272 } else if (_actionBox.getSelectedIndex() == 1) { 4273 _curAction.setActionData(Sensor.INACTIVE); 4274 } else { 4275 _curAction.setActionData(Route.TOGGLE); 4276 } 4277 } 4278 _actionNameField.setText(name); 4279 _curAction.setDeviceName(name); 4280 break; 4281 case TURNOUT: 4282 if (!referenceByMemory) { 4283 name = validateTurnoutReference(name); 4284 if (name == null) { 4285 return false; 4286 } 4287 } 4288 actionType = selection; 4289 if ((actionType == Conditional.Action.RESET_DELAYED_TURNOUT) 4290 || (actionType == Conditional.Action.DELAYED_TURNOUT)) { 4291 if (!validateTimeReference(actionType, actionString)) { 4292 return (false); 4293 } 4294 _curAction.setActionString(actionString); 4295 } 4296 if ((actionType == Conditional.Action.SET_TURNOUT) 4297 || (actionType == Conditional.Action.RESET_DELAYED_TURNOUT) 4298 || (actionType == Conditional.Action.DELAYED_TURNOUT)) { 4299 if (_actionBox.getSelectedIndex() == 0) { 4300 _curAction.setActionData(Turnout.CLOSED); 4301 } else if (_actionBox.getSelectedIndex() == 1) { 4302 _curAction.setActionData(Turnout.THROWN); 4303 } else { 4304 _curAction.setActionData(Route.TOGGLE); 4305 } 4306 } else if (actionType == Conditional.Action.LOCK_TURNOUT) { 4307 if (_actionBox.getSelectedIndex() == 0) { 4308 _curAction.setActionData(Turnout.UNLOCKED); 4309 } else if (_actionBox.getSelectedIndex() == 1) { 4310 _curAction.setActionData(Turnout.LOCKED); 4311 } else { 4312 _curAction.setActionData(Route.TOGGLE); 4313 } 4314 } 4315 _actionNameField.setText(name); 4316 _curAction.setDeviceName(name); 4317 break; 4318 case LIGHT: 4319 if (!referenceByMemory) { 4320 name = validateLightReference(name); 4321 if (name == null) { 4322 return false; 4323 } 4324 } 4325 actionType = selection; 4326 if (actionType == Conditional.Action.SET_LIGHT_INTENSITY) { 4327 Light lgtx = getLight(name); 4328 // check if light user name was entered 4329 if (lgtx == null) { 4330 return false; 4331 } 4332 if (!(lgtx instanceof VariableLight)) { 4333 JmriJOptionPane.showMessageDialog(_editLogixFrame, 4334 Bundle.getMessage("Error45", name), // NOI18N 4335 Bundle.getMessage("ErrorTitle"), 4336 JmriJOptionPane.ERROR_MESSAGE); // NOI18N 4337 return (false); 4338 } 4339 if (!validateIntensityReference(actionType, actionString)) { 4340 return (false); 4341 } 4342 _curAction.setActionString(actionString); 4343 } else if (actionType == Conditional.Action.SET_LIGHT_TRANSITION_TIME) { 4344 Light lgtx = getLight(name); 4345 // check if light user name was entered 4346 if (lgtx == null) { 4347 return false; 4348 } 4349 if ( !(lgtx instanceof VariableLight) 4350 || !((VariableLight)lgtx).isTransitionAvailable()) { 4351 JmriJOptionPane.showMessageDialog(_editLogixFrame, 4352 Bundle.getMessage("Error40", name), // NOI18N 4353 Bundle.getMessage("ErrorTitle"), 4354 JmriJOptionPane.ERROR_MESSAGE); // NOI18N 4355 return (false); 4356 } 4357 if (!validateTimeReference(actionType, actionString)) { 4358 return (false); 4359 } 4360 _curAction.setActionString(actionString); 4361 } else if (actionType == Conditional.Action.SET_LIGHT) { 4362 if (_actionBox.getSelectedIndex() == 0) { 4363 _curAction.setActionData(Light.ON); 4364 } else if (_actionBox.getSelectedIndex() == 1) { 4365 _curAction.setActionData(Light.OFF); 4366 } else { 4367 _curAction.setActionData(Route.TOGGLE); 4368 } 4369 } 4370 _actionNameField.setText(name); 4371 _curAction.setDeviceName(name); 4372 break; 4373 case SIGNALHEAD: 4374 if (!referenceByMemory) { 4375 name = validateSignalHeadReference(name); 4376 if (name == null) { 4377 return false; 4378 } 4379 } 4380 actionType = selection; 4381 if (actionType == Conditional.Action.SET_SIGNAL_APPEARANCE) { 4382 String appStr = (String) _actionBox.getSelectedItem(); 4383 _curAction.setActionData(DefaultConditionalAction.stringToActionData(appStr)); 4384 _curAction.setActionString(appStr); 4385 } 4386 _actionNameField.setText(name); 4387 _curAction.setDeviceName(name); 4388 break; 4389 case SIGNALMAST: 4390 if (!referenceByMemory) { 4391 name = validateSignalMastReference(name); 4392 if (name == null) { 4393 return false; 4394 } 4395 } 4396 actionType = selection; 4397 if (actionType == Conditional.Action.SET_SIGNALMAST_ASPECT) { 4398 _curAction.setActionString((String) _actionBox.getSelectedItem()); 4399 } 4400 _actionNameField.setText(name); 4401 _curAction.setDeviceName(name); 4402 break; 4403 case MEMORY: 4404 if (referenceByMemory) { 4405 JmriJOptionPane.showMessageDialog(_editLogixFrame, Bundle.getMessage("Warn6"), Bundle.getMessage("WarningTitle"), // NOI18N 4406 JmriJOptionPane.WARNING_MESSAGE); 4407 return false; 4408 } 4409 name = validateMemoryReference(name); 4410 if (name == null) { 4411 return false; 4412 } 4413 actionType = selection; 4414 if (actionType == Conditional.Action.COPY_MEMORY) { 4415 actionString = validateMemoryReference(actionString); 4416 if (actionString == null) { 4417 return false; 4418 } 4419 } 4420 _actionNameField.setText(name); 4421 _curAction.setDeviceName(name); 4422 _curAction.setActionString(actionString); 4423 break; 4424 case LOGIX: 4425 if (!referenceByMemory) { 4426 name = validateLogixReference(name); 4427 if (name == null) { 4428 return false; 4429 } 4430 } 4431 actionType = selection; 4432 _actionNameField.setText(name); 4433 _curAction.setDeviceName(name); 4434 break; 4435 case WARRANT: 4436 if (!referenceByMemory) { 4437 name = validateWarrantReference(name); 4438 if (name == null) { 4439 return false; 4440 } 4441 } 4442 actionType = selection; 4443 _actionNameField.setText(name); 4444 _curAction.setDeviceName(name); 4445 if (actionType == Conditional.Action.CONTROL_TRAIN) { 4446 switch (_actionBox.getSelectedIndex()) { 4447 case 0: 4448 _curAction.setActionData(Warrant.HALT); 4449 break; 4450 case 1: 4451 _curAction.setActionData(Warrant.RESUME); 4452 break; 4453 case 2: 4454 _curAction.setActionData(Warrant.RETRY_FWD); 4455 break; 4456 case 3: 4457 _curAction.setActionData(Warrant.SPEED_UP); 4458 break; 4459 case 4: 4460 _curAction.setActionData(Warrant.STOP); 4461 break; 4462 case 5: 4463 _curAction.setActionData(Warrant.ESTOP); 4464 break; 4465 case 6: 4466 _curAction.setActionData(Warrant.ABORT); 4467 break; 4468 default: 4469 log.warn("Unexpected _actionBox.getSelectedIndex() of {}", _actionBox.getSelectedIndex()); // NOI18N 4470 break; 4471 } 4472 } else if (actionType == Conditional.Action.SET_TRAIN_ID 4473 || actionType == Conditional.Action.SET_TRAIN_NAME 4474 || actionType == Conditional.Action.GET_TRAIN_LOCATION) { 4475 _curAction.setActionString(actionString); 4476 } 4477 break; 4478 case OBLOCK: 4479 if (!referenceByMemory) { 4480 name = validateOBlockReference(name); 4481 if (name == null) { 4482 return false; 4483 } 4484 } 4485 actionType = selection; 4486 _actionNameField.setText(name); 4487 _curAction.setDeviceName(name); 4488 if (actionType == Conditional.Action.SET_BLOCK_VALUE 4489 || actionType == Conditional.Action.SET_TRAIN_NAME 4490 || actionType == Conditional.Action.GET_TRAIN_LOCATION) { 4491 _curAction.setActionString(actionString); 4492 } 4493 break; 4494 case ENTRYEXIT: 4495 if (!referenceByMemory) { 4496 name = validateEntryExitReference(name); 4497 if (name == null) { 4498 return false; 4499 } 4500 } 4501 actionType = selection; 4502 _actionNameField.setText(name); 4503 _curAction.setDeviceName(name); 4504 break; 4505 case CLOCK: 4506 actionType = selection; 4507 if (actionType == Conditional.Action.SET_FAST_CLOCK_TIME) { 4508 int time = parseTime(_shortActionString.getText().trim()); 4509 if (time < 0) { 4510 return (false); 4511 } 4512 _curAction.setActionData(time); 4513 } 4514 break; 4515 case AUDIO: 4516 actionType = selection; 4517 if (actionType == Conditional.Action.PLAY_SOUND) { 4518 _curAction.setActionString(_longActionString.getText().trim()); 4519 } else if (actionType == Conditional.Action.CONTROL_AUDIO) { 4520 if (!referenceByMemory) { 4521 name = validateAudioReference(name); 4522 if (name == null) { 4523 return false; 4524 } 4525 } 4526 _actionNameField.setText(name); 4527 _curAction.setDeviceName(name); 4528 switch (_actionBox.getSelectedIndex()) { 4529 case 0: 4530 _curAction.setActionData(Audio.CMD_PLAY); 4531 break; 4532 case 1: 4533 _curAction.setActionData(Audio.CMD_STOP); 4534 break; 4535 case 2: 4536 _curAction.setActionData(Audio.CMD_PLAY_TOGGLE); 4537 break; 4538 case 3: 4539 _curAction.setActionData(Audio.CMD_PAUSE); 4540 break; 4541 case 4: 4542 _curAction.setActionData(Audio.CMD_RESUME); 4543 break; 4544 case 5: 4545 _curAction.setActionData(Audio.CMD_PAUSE_TOGGLE); 4546 break; 4547 case 6: 4548 _curAction.setActionData(Audio.CMD_REWIND); 4549 break; 4550 case 7: 4551 _curAction.setActionData(Audio.CMD_FADE_IN); 4552 break; 4553 case 8: 4554 _curAction.setActionData(Audio.CMD_FADE_OUT); 4555 break; 4556 case 9: 4557 _curAction.setActionData(Audio.CMD_RESET_POSITION); 4558 break; 4559 default: 4560 log.warn("Unexpected _actionBox.getSelectedIndex() of {}", _actionBox.getSelectedIndex()); // NOI18N 4561 break; 4562 } 4563 } 4564 break; 4565 case SCRIPT: 4566 actionType = selection; 4567 if (actionType == Conditional.Action.RUN_SCRIPT) { 4568 _curAction.setActionString(_longActionString.getText().trim()); 4569 } else if (actionType == Conditional.Action.JYTHON_COMMAND) { 4570 _curAction.setActionString(_shortActionString.getText().trim()); 4571 } 4572 break; 4573 case OTHER: 4574 actionType = selection; 4575 if (actionType == Conditional.Action.TRIGGER_ROUTE) { 4576 if (!referenceByMemory) { 4577 name = validateRouteReference(name); 4578 if (name == null) { 4579 return false; 4580 } 4581 } 4582 _actionNameField.setText(name); 4583 _curAction.setDeviceName(name); 4584 } 4585 break; 4586 default: 4587 break; 4588 } 4589 _curAction.setType(actionType); 4590 if (actionType != Conditional.Action.NONE) { 4591 _curAction.setOption(_actionOptionBox.getSelectedIndex() + 1); 4592 } else { 4593 _curAction.setOption(0); 4594 } 4595 return (true); 4596 } 4597 4598 /** 4599 * Update the conditional action list and refresh the local copy. 4600 * The parent Logix is de-activated and re-activated. This ensures 4601 * that listeners are properly handled, specifically the delayed sensor 4602 * and turnout options. 4603 * @since 4.11.2 4604 */ 4605 void updateActionList() { 4606 _curLogix.deActivateLogix(); 4607 _curConditional.setAction(_actionList); 4608 _actionList = _curConditional.getCopyOfActions(); 4609 _curLogix.activateLogix(); 4610 } 4611 4612 /** 4613 * Check that a state variable is not also used as an action 4614 * 4615 * @param name of the state variable 4616 * @param itemType item type of the state variable 4617 * @return true if variable is not an action of if the user OK's 4618 * its use as an action also. 4619 */ 4620 boolean checkIsAction(String name, Conditional.ItemType itemType) { 4621 String actionName = null; 4622 for (ConditionalAction action : _actionList) { 4623 Conditional.ItemType actionType = action.getType().getItemType(); 4624 if (itemType == actionType) { 4625 if (name.equals(action.getDeviceName())) { 4626 actionName = action.getDeviceName(); 4627 } else { 4628 NamedBean bean = action.getBean(); 4629 if (bean != null && 4630 (name.equals(bean.getSystemName()) || 4631 name.equals(bean.getUserName()))) { 4632 actionName = action.getDeviceName(); 4633 } 4634 } 4635 } 4636 if (actionName != null) { 4637 return confirmActionAsVariable(actionName, name); 4638 } 4639 } 4640 return true; 4641 } 4642 4643 /** 4644 * Check that an action is not also used as a state variable 4645 * 4646 * @param name of the action 4647 * @param itemType item type of the action 4648 * @return true if action is not a state variable of if the user OK's 4649 * its use as such. 4650 */ 4651 boolean checkIsVariable(String name, Conditional.ItemType itemType) { 4652 String varName = null; 4653 for (ConditionalVariable var : _variableList) { 4654 Conditional.ItemType varType = var.getType().getItemType(); 4655 if (itemType == varType) { 4656 if (name.equals(var.getName())) { 4657 varName = var.getName(); 4658 } else { 4659 NamedBean bean = var.getBean(); 4660 if (bean != null && 4661 (name.equals(bean.getSystemName()) || 4662 name.equals(bean.getUserName()))) { 4663 varName = var.getName(); 4664 } 4665 } 4666 } 4667 if (varName != null) { 4668 return confirmActionAsVariable(name, varName); 4669 } 4670 } 4671 return true; 4672 } 4673 4674 // ------------ Action detail listeners ------------ 4675 4676 /** 4677 * Listener for _actionTypeBox. 4678 */ 4679 class ActionTypeListener implements ActionListener { 4680 4681 Conditional.ItemType _itemType; 4682 4683 @Override 4684 public void actionPerformed(ActionEvent e) { 4685 Conditional.ItemType select1 = _actionItemBox.getItemAt(_actionItemBox.getSelectedIndex()); 4686 Conditional.Action select2 = _actionTypeBox.getItemAt(_actionTypeBox.getSelectedIndex()); 4687 if (log.isDebugEnabled()) { 4688 log.debug("ActionTypeListener: itemType = {}, local itemType = {}, actionType = {}", // NOI18N 4689 select1, _itemType, select2); 4690 } 4691 if (select1 != _itemType) { 4692 log.error("ActionTypeListener actionItem selection ({}) != expected actionItem ({})", // NOI18N 4693 select1, _itemType); 4694 } 4695 if (_curAction != null) { 4696 if (select1 != Conditional.ItemType.NONE && _itemType == select1) { 4697 _curAction.setType(select2); 4698 if (select1 == _itemType) { 4699 String text = _actionNameField.getText(); 4700 if (text != null && text.length() > 0) { 4701 _curAction.setDeviceName(text); 4702 } 4703 } 4704 actionItemChanged(_itemType); 4705 initializeActionVariables(); 4706 } 4707 } 4708 } 4709 4710 public void setItemType(Conditional.ItemType type) { 4711 _itemType = type; 4712 } 4713 } 4714 4715 ActionTypeListener _actionTypeListener = new ActionTypeListener(); 4716 4717 transient ActionListener actionSignalHeadNameListener = new ActionListener() { 4718 @Override 4719 public void actionPerformed(ActionEvent e) { 4720 // fired when signal head name changes, but only 4721 // while in signal head mode 4722 log.debug("actionSignalHeadNameListener fires; _actionNameField : {}", _actionNameField.getText().trim()); // NOI18N 4723 loadJComboBoxWithHeadAppearances(_actionBox, _actionNameField.getText().trim()); 4724 } 4725 }; 4726 4727 transient ActionListener actionSignalMastNameListener = new ActionListener() { 4728 @Override 4729 public void actionPerformed(ActionEvent e) { 4730 // fired when signal mast name changes, but only 4731 // while in signal mast mode 4732 log.debug("actionSignalMastNameListener fires; _actionNameField : {}", _actionNameField.getText().trim()); // NOI18N 4733 loadJComboBoxWithMastAspects(_actionBox, _actionNameField.getText().trim()); 4734 } 4735 }; 4736 4737 /** 4738 * Conditional Tree Node Definition. 4739 */ 4740 static class ConditionalTreeNode extends DefaultMutableTreeNode { 4741 4742 private String cdlText; 4743 private String cdlType; 4744 private String cdlName; 4745 private int cdlRow; 4746 4747 public ConditionalTreeNode(String nameText, String type, String sysName, int row) { 4748 this.cdlText = nameText; 4749 this.cdlType = type; 4750 this.cdlName = sysName; 4751 this.cdlRow = row; 4752 } 4753 4754 public String getType() { 4755 return cdlType; 4756 } 4757 4758 public String getName() { 4759 return cdlName; 4760 } 4761 4762 public void setName(String newName) { 4763 cdlName = newName; 4764 } 4765 4766 public int getRow() { 4767 return cdlRow; 4768 } 4769 4770 public void setRow(int newRow) { 4771 cdlRow = newRow; 4772 } 4773 4774 public String getText() { 4775 return cdlText; 4776 } 4777 4778 public void setText(String newText) { 4779 cdlText = newText; 4780 } 4781 4782 @Override 4783 public String toString() { 4784 return cdlText; 4785 } 4786 } 4787 4788 @Override 4789 protected String getClassName() { 4790 return ConditionalTreeEdit.class.getName(); 4791 } 4792 4793 private static final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(ConditionalTreeEdit.class); 4794 4795}