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 if (_curNodeType != null) { 1487 switch (_curNodeType) { 1488 case "Variable": // NOI18N 1489 cancelEditVariable(); 1490 break; 1491 1492 case "Action": // NOI18N 1493 cancelEditAction(); 1494 break; 1495 1496 default: 1497 break; 1498 } 1499 } 1500 closeSinglePanelPickList(); 1501 if (_pickTables != null) { 1502 _pickTables.dispose(); 1503 _pickTables = null; 1504 } 1505 1506 _editLogixFrame.setVisible(false); 1507 _editLogixFrame.dispose(); 1508 _editLogixFrame = null; 1509 1510 logixData.clear(); 1511 logixData.put("Finish", _curLogix.getSystemName()); // NOI18N 1512 fireLogixEvent(); 1513 } 1514 1515 // ============ Tree Content and Navigation ============ 1516 1517 /** 1518 * Create the conditional tree structure using the current Logix. 1519 * 1520 * @return _cdlTree The tree ddefinition with its content 1521 */ 1522 JTree buildConditionalTree() { 1523 _cdlRoot = new DefaultMutableTreeNode("Root Node"); // NOI18N 1524 _cdlModel = new DefaultTreeModel(_cdlRoot); 1525 _cdlTree = new JTree(_cdlModel); 1526 1527 createConditionalContent(); 1528 1529 // build the tree GUI 1530 _cdlTree.expandPath(new TreePath(_cdlRoot)); 1531 _cdlTree.setRootVisible(false); 1532 _cdlTree.setShowsRootHandles(true); 1533 _cdlTree.setScrollsOnExpand(true); 1534 _cdlTree.setExpandsSelectedPaths(true); 1535 _cdlTree.getSelectionModel().setSelectionMode(DefaultTreeSelectionModel.SINGLE_TREE_SELECTION); 1536 1537 // tree listeners 1538 _cdlTree.addTreeSelectionListener(_cdlListener = new TreeSelectionListener() { 1539 @Override 1540 public void valueChanged(TreeSelectionEvent e) { 1541 if (_editActive) { 1542 if (e.getNewLeadSelectionPath() != _curTreePath) { 1543 _cdlTree.setSelectionPath(e.getOldLeadSelectionPath()); 1544 showNodeEditMessage(); 1545 } 1546 return; 1547 } 1548 1549 _curTreePath = _cdlTree.getSelectionPath(); 1550 if (_curTreePath != null) { 1551 Object chkLast = _curTreePath.getLastPathComponent(); 1552 if (chkLast instanceof ConditionalTreeNode) { 1553 treeRowSelected((ConditionalTreeNode) chkLast); 1554 } 1555 } 1556 } 1557 }); 1558 1559 _cdlTree.addTreeExpansionListener(new TreeExpansionListener() { 1560 @Override 1561 public void treeExpanded(TreeExpansionEvent e) { 1562 ConditionalTreeNode checkNode = (ConditionalTreeNode) e.getPath().getLastPathComponent(); 1563 if (checkNode.getType().equals("Variables")) { // NOI18N 1564 // Include the field descriptions in the node name 1565 checkNode.setText(buildNodeText("Variables", _curConditional, 1)); // NOI18N 1566 _cdlModel.nodeChanged(checkNode); 1567 } 1568 } 1569 1570 @Override 1571 public void treeCollapsed(TreeExpansionEvent e) { 1572 ConditionalTreeNode checkNode = (ConditionalTreeNode) e.getPath().getLastPathComponent(); 1573 if (checkNode.getType().equals("Variables")) { // NOI18N 1574 // Remove the field descriptions from the node name 1575 checkNode.setText(buildNodeText("Variables", _curConditional, 0)); // NOI18N 1576 _cdlModel.nodeChanged(checkNode); 1577 } 1578 1579 if (_cdlTree.getSelectionCount() == 0) { 1580 makeDetailGrid("EmptyGrid"); // NOI18N 1581 } 1582 } 1583 }); 1584 1585 return _cdlTree; 1586 } 1587 1588 /** 1589 * Create the tree content. Level 1 are the conditionals, Level 2 includes the 1590 * antecedent, logic type, trigger mode and parent nodes for Variables and 1591 * Actions, Level 3 contains the detail Variable and Action entries. 1592 */ 1593 void createConditionalContent() { 1594 int numConditionals = _curLogix.getNumConditionals(); 1595 for (int i = 0; i < numConditionals; i++) { 1596 String csName = _curLogix.getConditionalByNumberOrder(i); 1597 Conditional curConditional = _curLogix.getConditional(csName); 1598 _cdlNode = new ConditionalTreeNode(buildNodeText("Conditional", curConditional, 0), "Conditional", csName, i); // NOI18N 1599 _cdlRoot.add(_cdlNode); 1600 1601 _leafNode = new ConditionalTreeNode(buildNodeText("Antecedent", curConditional, 0), "Antecedent", csName, 0); // NOI18N 1602 _cdlNode.add(_leafNode); 1603 1604 _variableList = curConditional.getCopyOfStateVariables(); 1605 int varCount = _variableList.size(); 1606 _varHead = new ConditionalTreeNode(buildNodeText("Variables", _curConditional, 0), "Variables", csName, varCount); // NOI18N 1607 _cdlNode.add(_varHead); 1608 for (int v = 0; v < _variableList.size(); v++) { 1609 ConditionalVariable variable = _variableList.get(v); 1610 _leafNode = new ConditionalTreeNode(buildNodeText("Variable", variable, v), "Variable", csName, v); 1611 _varHead.add(_leafNode); 1612 } 1613 1614 _leafNode = new ConditionalTreeNode(buildNodeText("LogicType", curConditional, 0), "LogicType", csName, 0); // NOI18N 1615 _cdlNode.add(_leafNode); 1616 1617 boolean triggerMode = curConditional.getTriggerOnChange(); 1618 _leafNode = new ConditionalTreeNode(buildNodeText("TriggerMode", curConditional, 0), "TriggerMode", csName, 0); // NOI18N 1619 _cdlNode.add(_leafNode); 1620 1621 _actionList = curConditional.getCopyOfActions(); 1622 int actCount = _actionList.size(); 1623 _actHead = new ConditionalTreeNode("Actions", "Actions", csName, actCount); // NOI18N 1624 _cdlNode.add(_actHead); 1625 for (int a = 0; a < _actionList.size(); a++) { 1626 ConditionalAction action = _actionList.get(a); 1627 _leafNode = new ConditionalTreeNode(action.description(triggerMode), "Action", csName, a); // NOI18N 1628 _actHead.add(_leafNode); 1629 } 1630 } 1631 } 1632 1633 /** 1634 * Change the button row based on the currently selected node type. Invoke 1635 * edit where appropriate. 1636 * 1637 * @param selectedNode The node object 1638 */ 1639 void treeRowSelected(ConditionalTreeNode selectedNode) { 1640 // Set the current node variables 1641 _curNode = selectedNode; 1642 _curNodeName = selectedNode.getName(); 1643 _curNodeType = selectedNode.getType(); 1644 _curNodeText = selectedNode.getText(); 1645 _curNodeRow = selectedNode.getRow(); 1646 1647 // Set the current conditional variables if different conditional 1648 if (!_curConditionalName.equals(_curNodeName)) { 1649 _curConditional = _conditionalManager.getConditional(_curNodeName); 1650 _antecedent = _curConditional.getAntecedentExpression(); 1651 _logicType = _curConditional.getLogicType(); 1652 _triggerMode = _curConditional.getTriggerOnChange(); 1653 _variableList = _curConditional.getCopyOfStateVariables(); 1654 _actionList = _curConditional.getCopyOfActions(); 1655 _curConditionalName = _curNodeName; 1656 } 1657 1658 // Reset button bar 1659 _addButtonPanel.setVisible(false); 1660 _checkButtonPanel.setVisible(false); 1661 _toggleButtonPanel.setVisible(false); 1662 _moveButtonPanel.setVisible(false); 1663 _deleteButtonPanel.setVisible(false); 1664 _helpButtonPanel.setVisible(false); 1665 1666 _labelPanel.removeAll(); 1667 switch (_curNodeType) { 1668 case "Conditional": // NOI18N 1669 _labelPanel.add(_conditionalLabel); 1670 _addButtonPanel.setVisible(true); 1671 _checkButtonPanel.setVisible(true); 1672 _deleteButtonPanel.setVisible(true); 1673 setMoveButtons(); 1674 editPressed(); 1675 break; 1676 1677 case "Antecedent": // NOI18N 1678 editPressed(); 1679 break; 1680 1681 case "LogicType": // NOI18N 1682 editPressed(); 1683 break; 1684 1685 case "TriggerMode": // NOI18N 1686 _labelPanel.add(_triggerModeLabel); 1687 _toggleButtonPanel.setVisible(true); 1688 makeDetailGrid("EmptyGrid"); // NOI18N 1689 break; 1690 1691 case "Variables": // NOI18N 1692 _labelPanel.add(_variablesLabel); 1693 _addButtonPanel.setVisible(true); 1694 _checkButtonPanel.setVisible(true); 1695 makeDetailGrid("EmptyGrid"); // NOI18N 1696 break; 1697 1698 case "Variable": // NOI18N 1699 _labelPanel.add(_variableLabel); 1700 _addButtonPanel.setVisible(true); 1701 _deleteButtonPanel.setVisible(true); 1702 if (_logicType != Conditional.AntecedentOperator.MIXED) { 1703 setMoveButtons(); 1704 } 1705 editPressed(); 1706 break; 1707 1708 case "Actions": // NOI18N 1709 _labelPanel.add(_actionsLabel); 1710 _addButtonPanel.setVisible(true); 1711 makeDetailGrid("EmptyGrid"); // NOI18N 1712 break; 1713 1714 case "Action": // NOI18N 1715 _labelPanel.add(_actionLabel); 1716 _addButtonPanel.setVisible(true); 1717 _deleteButtonPanel.setVisible(true); 1718 setMoveButtons(); 1719 editPressed(); 1720 break; 1721 1722 default: 1723 log.warn("Should not be here"); // NOI18N 1724 } 1725 } 1726 1727 /** 1728 * Create the localized node text display strings based on node type. 1729 * 1730 * @param nodeType The type of the node 1731 * @param component The conditional object or child object 1732 * @param idx Optional index value 1733 * @return nodeText containing the text to display on the node 1734 */ 1735 String buildNodeText(String nodeType, Object component, int idx) { 1736 Conditional cdl; 1737 ConditionalAction act; 1738 ConditionalVariable var; 1739 1740 switch (nodeType) { 1741 case "Conditional": // NOI18N 1742 cdl = (Conditional) component; 1743 String cdlStatus = (cdl.getState() == Conditional.TRUE) 1744 ? Bundle.getMessage("True") // NOI18N 1745 : Bundle.getMessage("False"); // NOI18N 1746 String cdlNames = cdl.getSystemName() + " -- " + cdl.getUserName(); 1747 String cdlFill = StringUtils.repeat(" ", 5); // NOI18N 1748 String cdlLine = "<html>" + cdlNames + cdlFill + "<strong>[ " + cdlStatus + " ]</strong></html>"; // NOI18N 1749 return cdlLine; 1750 1751 case "Antecedent": // NOI18N 1752 cdl = (Conditional) component; 1753 String antecedent = translateAntecedent(cdl.getAntecedentExpression(), false); 1754 if (cdl.getLogicType() != Conditional.AntecedentOperator.MIXED) { 1755 antecedent = "- - - - - - - - -"; 1756 } 1757 return Bundle.getMessage("LogixAntecedent") + " " + antecedent; // NOI18N 1758 1759 case "LogicType": // NOI18N 1760 cdl = (Conditional) component; 1761 Conditional.AntecedentOperator logicType = cdl.getLogicType(); 1762 String logicName; // used for display only 1763 switch (logicType) { 1764 case ALL_AND: 1765 logicName = Bundle.getMessage("LogicAND"); // NOI18N 1766 break; 1767 case ALL_OR: 1768 logicName = Bundle.getMessage("LogicOR"); // NOI18N 1769 break; 1770 case MIXED: 1771 logicName = Bundle.getMessage("LogicMixed"); // NOI18N 1772 break; 1773 default: 1774 logicName = "None"; // only used for invalid LogicType 1775 } 1776 return Bundle.getMessage("LabelLogicTypeActions") + " " + logicName; // NOI18N 1777 1778 case "TriggerMode": // NOI18N 1779 cdl = (Conditional) component; 1780 boolean triggerMode = cdl.getTriggerOnChange(); 1781 String triggerText; 1782 if (triggerMode) { 1783 triggerText = Bundle.getMessage("triggerOnChange"); // NOI18N 1784 } else { 1785 triggerText = Bundle.getMessage("triggerOnAny"); // NOI18N 1786 } 1787 return Bundle.getMessage("LabelTriggerModeActions") + " " + triggerText; // NOI18N 1788 1789 case "Variables": // NOI18N 1790 if (idx == 0) { 1791 // The node is not expanded, return plain content 1792 return Bundle.getMessage("NodeVariablesCollapsed"); // NOI18N 1793 } else { 1794 // The node is expanded, include the field names 1795 return String.format("%s [[ %s || %s || %s ]]", // NOI18N 1796 Bundle.getMessage("NodeVariablesExpanded"), // NOI18N 1797 Bundle.getMessage("ColumnLabelDescription"), // NOI18N 1798 Bundle.getMessage("ColumnLabelTriggersCalculation"), // NOI18N 1799 Bundle.getMessage("ColumnState")); // NOI18N 1800 } 1801 1802 case "Variable": // NOI18N 1803 var = (ConditionalVariable) component; 1804 1805 String rowNum = "R" + (idx + 1) + (idx > 9 ? " " : " "); // NOI18N 1806 String rowOper = var.getOpernString() + " "; 1807 1808 String rowNot = ""; 1809 if (var.isNegated()) { 1810 rowNot = Bundle.getMessage("LogicNOT") + " "; // NOI18N 1811 } 1812 1813 String boldFormat = " || <strong>%s</strong>"; // NOI18N 1814 String rowTrigger = String.format(boldFormat, 1815 (var.doTriggerActions()) ? Bundle.getMessage("ButtonYes") : Bundle.getMessage("ButtonNo")); // NOI18N 1816 String rowStatus = String.format(boldFormat, 1817 (var.evaluate()) ? Bundle.getMessage("True") : Bundle.getMessage("False")); // NOI18N 1818 1819 String varLine = "<html>" + rowNum + rowOper + rowNot + var.toString() + rowTrigger + rowStatus + "</html>"; // NOI18N 1820 return varLine; 1821 1822 case "Actions": // NOI18N 1823 return Bundle.getMessage("NodeActions"); // NOI18N 1824 1825 case "Action": // NOI18N 1826 act = (ConditionalAction) component; 1827 return act.description(_triggerMode); 1828 1829 default: 1830 return "None"; 1831 } 1832 } 1833 1834 /** 1835 * Display reminder to save. 1836 */ 1837 void showNodeEditMessage() { 1838 if (InstanceManager.getNullableDefault(jmri.UserPreferencesManager.class) != null) { 1839 InstanceManager.getDefault(jmri.UserPreferencesManager.class). 1840 showInfoMessage(Bundle.getMessage("NodeEditTitle"), // NOI18N 1841 Bundle.getMessage("NodeEditText"), // NOI18N 1842 getClassName(), 1843 "SkipNodeEditMessage"); // NOI18N 1844 } 1845 } 1846 1847 /** 1848 * Focus gained implies intent to make changes, set up for edit. 1849 */ 1850 transient FocusListener detailFocusEvent = new FocusListener() { 1851 @Override 1852 public void focusGained(FocusEvent e) { 1853 if (!_editActive) { 1854 setEditMode(true); 1855 } 1856 } 1857 1858 @Override 1859 public void focusLost(FocusEvent e) { 1860 } 1861 }; 1862 1863 /** 1864 * Add the focus listener to each detail edit field. 1865 */ 1866 void setFocusListeners() { 1867 _editConditionalUserName.addFocusListener(detailFocusEvent); 1868 _editAntecedent.addFocusListener(detailFocusEvent); 1869 _editOperatorMode.addFocusListener(detailFocusEvent); 1870 _variableItemBox.addFocusListener(detailFocusEvent); 1871 _variableOperBox.addFocusListener(detailFocusEvent); 1872 _variableNegated.addFocusListener(detailFocusEvent); 1873 _variableTriggerActions.addFocusListener(detailFocusEvent); 1874 _variableNameField.addFocusListener(detailFocusEvent); 1875 _variableStateBox.addFocusListener(detailFocusEvent); 1876 _variableSignalBox.addFocusListener(detailFocusEvent); 1877 _selectLogixBox.addFocusListener(detailFocusEvent); 1878 _selectConditionalBox.addFocusListener(detailFocusEvent); 1879 _variableCompareOpBox.addFocusListener(detailFocusEvent); 1880 _variableCompareTypeBox.addFocusListener(detailFocusEvent); 1881 _variableData1Field.addFocusListener(detailFocusEvent); 1882 _variableData2Field.addFocusListener(detailFocusEvent); 1883 _actionItemBox.addFocusListener(detailFocusEvent); 1884 _actionNameField.addFocusListener(detailFocusEvent); 1885 _actionTypeBox.addFocusListener(detailFocusEvent); 1886 _actionBox.addFocusListener(detailFocusEvent); 1887 _shortActionString.addFocusListener(detailFocusEvent); 1888 _longActionString.addFocusListener(detailFocusEvent); 1889 _actionSetButton.addFocusListener(detailFocusEvent); 1890 _actionOptionBox.addFocusListener(detailFocusEvent); 1891 } 1892 1893 /** 1894 * Enable/disable buttons based on edit state. 1895 * Open pick lists based on the current SelectionMode. 1896 * The edit state controls the ability to select tree nodes. 1897 * 1898 * @param active True to make edit active, false to make edit inactive 1899 */ 1900 void setEditMode(boolean active) { 1901 _editActive = active; 1902 _cancelAction.setEnabled(active); 1903 _updateAction.setEnabled(active); 1904 Component delButton = _deleteButtonPanel.getComponent(0); 1905 if (delButton instanceof JButton) { 1906 delButton.setEnabled(!active); 1907 } 1908 Component addButton = _addButtonPanel.getComponent(0); 1909 if (addButton instanceof JButton) { 1910 addButton.setEnabled(!active); 1911 } 1912 if (_curNodeType != null) { 1913 if (_curNodeType.equals("Conditional") || _curNodeType.equals("Variable") || _curNodeType.equals("Action")) { // NOI18N 1914 setMoveButtons(); 1915 } 1916 } 1917 if (active) { 1918 setPickWindow("Activate", Conditional.ItemType.NONE); // NOI18N 1919 } else { 1920 setPickWindow("Deactivate", Conditional.ItemType.NONE); // NOI18N 1921 } 1922 } 1923 1924 /** 1925 * Ceate tabbed Pick Taba;e or Pick Single based on Selection Mode. 1926 * Called by {@link #setEditMode} when edit mode becomes active. 1927 * Called by {@link #variableTypeChanged} and {@link #actionItemChanged} when item type changes. 1928 * 1929 * @param cmd The source or action to be performed. 1930 * @param item The item type for Variable or Action or zero 1931 */ 1932 void setPickWindow(String cmd, Conditional.ItemType item) { 1933 if (_selectionMode == SelectionMode.USECOMBO) { 1934 return; 1935 } 1936 // Save the item information 1937 if (cmd.equals("Variable") || cmd.equals("Action")) { // NOI18N 1938 _pickCommand = cmd; 1939 _pickItem = item; 1940 if (_editActive) { 1941 if (_selectionMode == SelectionMode.USEMULTI) { 1942 doPickList(); 1943 } else { 1944 doPickSingle(); 1945 } 1946 } 1947 } 1948 if (cmd.equals("Activate")) { // NOI18N 1949 if (_curNodeType.equals("Variable") || _curNodeType.equals("Action")) { // NOI18N 1950 // Open the appropriate window based on the save values 1951 if (_selectionMode == SelectionMode.USEMULTI) { 1952 doPickList(); 1953 } else { 1954 doPickSingle(); 1955 } 1956 } 1957 } 1958 if (cmd.equals("Deactivate")) { // NOI18N 1959 // Close/dispose the pick window 1960 hidePickListTable(); 1961 closeSinglePanelPickList(); 1962 } 1963 } 1964 1965 /** 1966 * Create a Variable or Action based tabbed PickList with appropriate tab selected. 1967 */ 1968 void doPickList() { 1969 if (_pickItem == Conditional.ItemType.NONE) { 1970 return; 1971 } 1972 if (_pickTables == null) { 1973 openPickListTable(); 1974 } 1975 if (_pickCommand.equals("Variable")) { 1976 setPickListTab(_pickItem, false); 1977 } else if (_pickCommand.equals("Action")) { 1978 setPickListTab(_pickItem, true); 1979 } 1980 } 1981 1982 /** 1983 * Create a Variable or Action based single pane PickList. 1984 */ 1985 void doPickSingle() { 1986 if (_pickCommand.equals("Variable")) { 1987 createSinglePanelPickList(_pickItem, new PickSingleListener(_variableNameField, _pickItem), false); 1988 } else if (_pickCommand.equals("Action")) { 1989 createSinglePanelPickList(_pickItem, new PickSingleListener(_actionNameField, _pickItem), true); 1990 } 1991 } 1992 1993 // ============ Edit Variable Section ============ 1994 1995 /** 1996 * Called once during class initialization to define the GUI objects. Where 1997 * possible, the combo box content is loaded. 1998 */ 1999 void buildVariableComponents() { 2000 // Item Type 2001 _variableItemBox = new JComboBox<>(); 2002 for (Conditional.ItemType itemType : Conditional.ItemType.getStateVarList()) { 2003 _variableItemBox.addItem(itemType); 2004 } 2005 JComboBoxUtil.setupComboBoxMaxRows(_variableItemBox); 2006 _variableItemBox.addActionListener(new ActionListener() { 2007 @Override 2008 public void actionPerformed(ActionEvent e) { 2009 Conditional.ItemType newVariableItem = _variableItemBox.getItemAt(_variableItemBox.getSelectedIndex()); 2010 if (log.isDebugEnabled()) { 2011 log.debug("_variableItemBox Listener: new = {}, curr = {}, row = {}", // NOI18N 2012 newVariableItem, _curVariableItem, _curNodeRow); 2013 } 2014 if (newVariableItem != _curVariableItem) { 2015 if (_curNodeRow >= 0) { 2016 _curVariable = new ConditionalVariable(); 2017 _variableList.set(_curNodeRow, _curVariable); 2018 } 2019 _curVariableItem = newVariableItem; 2020 } 2021 variableTypeChanged(newVariableItem); 2022 } 2023 }); 2024 2025 // Oper type 2026 _variableOperBox = new JComboBox<String>(); 2027 _variableOperBox.addItem(Bundle.getMessage("LogicAND")); // NOI18N 2028 _variableOperBox.addItem(Bundle.getMessage("LogicOR")); // NOI18N 2029 2030 // Negation 2031 _variableNegated = new JCheckBox(); 2032 2033 // trigger 2034 _variableTriggerActions = new JCheckBox(); 2035 2036 // Item Name 2037 _variableNameField = new JTextField(20); 2038 2039 // Combo box section for selecting conditional reference 2040 // First box selects the Logix, the second selects the conditional within the logix 2041 _selectLogixBox.addItem("XXXXXXXXXXXXXXXXXXXXX"); // NOI18N 2042 _selectConditionalBox.addItem("XXXXXXXXXXXXXXXXXXXXX"); // NOI18N 2043 _selectLogixBox.addActionListener(selectLogixBoxListener); 2044 _selectConditionalBox.addActionListener(selectConditionalBoxListener); 2045 2046 // State Box 2047 _variableStateBox = new JComboBox<>(); 2048 _variableStateBox.addItem(Conditional.Type.XXXXXXX); // NOI18N 2049 2050 // Aspects 2051 _variableSignalBox = new JComboBox<>(); 2052 _variableSignalBox.addItem("XXXXXXXXX"); // NOI18N 2053 2054 // Compare operator 2055 _variableCompareOpBox = new JComboBox<>(); 2056 for (int i = 1; i <= ConditionalVariable.NUM_COMPARE_OPERATIONS; i++) { 2057 _variableCompareOpBox.addItem(ConditionalVariable.getCompareOperationString(i)); 2058 } 2059 2060 // Compare type 2061 _variableCompareTypeBox = new JComboBox<>(); 2062 for (Conditional.Type type : Conditional.Type.getMemoryItems()) { 2063 _variableCompareTypeBox.addItem(type); 2064 } 2065 _variableCompareTypeBox.addActionListener(compareTypeBoxListener); 2066 2067 // Data 1 2068 _variableData1Field = new JTextField(10); 2069 2070 // Data 2 2071 _variableData2Field = new JTextField(10); 2072 } 2073 2074 // ------------ Make Variable Edit Grid Panels ------------ 2075 2076 /** 2077 * Create a one row grid with just the Variable Type box. This is the base 2078 * for larger grids as well as the initial grid for new State Variables. 2079 * 2080 * @param c the constraints object used for the grid construction 2081 */ 2082 void makeEmptyVariableGrid(GridBagConstraints c) { 2083 // Variable type box 2084 c.gridy = 0; 2085 c.gridx = 0; 2086 c.anchor = java.awt.GridBagConstraints.EAST; 2087 JLabel row0Label = new JLabel(Bundle.getMessage("LabelVariableType")); // NOI18N 2088 row0Label.setToolTipText(Bundle.getMessage("VariableTypeHint")); // NOI18N 2089 _gridPanel.add(row0Label, c); 2090 c.gridx = 1; 2091 c.anchor = java.awt.GridBagConstraints.WEST; 2092 _gridPanel.add(_variableItemBox, c); 2093 } 2094 2095 /* 2096 * Create the Oper, Not and Trigger rows. 2097 * 2098 * @param c The constraints object used for the grid construction 2099 */ 2100 void makeOptionsVariableGrid(GridBagConstraints c) { 2101 makeEmptyVariableGrid(c); 2102 2103 // Oper Select 2104 c.gridy = 1; 2105 c.gridx = 0; 2106 c.anchor = java.awt.GridBagConstraints.EAST; 2107 JLabel row1Label = new JLabel(Bundle.getMessage("ColumnLabelOperator")); // NOI18N 2108 row1Label.setToolTipText(Bundle.getMessage("VariableOperHint")); // NOI18N 2109 _gridPanel.add(row1Label, c); 2110 c.gridx = 1; 2111 c.anchor = java.awt.GridBagConstraints.WEST; 2112 _gridPanel.add(_variableOperBox, c); 2113 2114 // Not Select 2115 c.gridy = 2; 2116 c.gridx = 0; 2117 c.anchor = java.awt.GridBagConstraints.EAST; 2118 JLabel row2Label = new JLabel(Bundle.getMessage("ColumnLabelNot")); // NOI18N 2119 row2Label.setToolTipText(Bundle.getMessage("VariableNotHint")); // NOI18N 2120 _gridPanel.add(row2Label, c); 2121 c.gridx = 1; 2122 c.anchor = java.awt.GridBagConstraints.WEST; 2123 _gridPanel.add(_variableNegated, c); 2124 2125 // Trigger Select 2126 c.gridy = 3; 2127 c.gridx = 0; 2128 c.anchor = java.awt.GridBagConstraints.EAST; 2129 JLabel row3Label = new JLabel(Bundle.getMessage("ColumnLabelTriggersCalculation")); // NOI18N 2130 row3Label.setToolTipText(Bundle.getMessage("VariableTriggerHint")); // NOI18N 2131 _gridPanel.add(row3Label, c); 2132 c.gridx = 1; 2133 c.anchor = java.awt.GridBagConstraints.WEST; 2134 _gridPanel.add(_variableTriggerActions, c); 2135 } 2136 2137 /** 2138 * Create the standard Name and State rows. 2139 * The name field will be either a text field or a combo box. 2140 * The name field label is a variable to support run time changes. 2141 * 2142 * @param c The constraints object used for the grid construction 2143 */ 2144 void makeStandardVariableGrid(GridBagConstraints c) { 2145 makeOptionsVariableGrid(c); 2146 2147 // Name Field 2148 c.gridy = 4; 2149 c.gridx = 0; 2150 c.anchor = java.awt.GridBagConstraints.EAST; 2151 _gridPanel.add(_variableNameLabel, c); 2152 c.gridx = 1; 2153 c.anchor = java.awt.GridBagConstraints.WEST; 2154 if (_selectionMode == SelectionMode.USECOMBO) { 2155 _gridPanel.add(_comboNameBox, c); 2156 } else { 2157 _gridPanel.add(_variableNameField, c); 2158 } 2159 2160 // State Box 2161 c.gridy = 5; 2162 c.gridx = 0; 2163 c.anchor = java.awt.GridBagConstraints.EAST; 2164 JLabel row5Label = new JLabel(Bundle.getMessage("LabelVariableState")); // NOI18N 2165 row5Label.setToolTipText(Bundle.getMessage("VariableStateHint")); // NOI18N 2166 _gridPanel.add(row5Label, c); 2167 c.gridx = 1; 2168 c.anchor = java.awt.GridBagConstraints.WEST; 2169 _gridPanel.add(_variableStateBox, c); 2170 } 2171 2172 /** 2173 * Add the Aspect field for signal heads and signal masts. 2174 * 2175 * @param c The constraints object used for the grid construction 2176 */ 2177 void makeSignalAspectVariableGrid(GridBagConstraints c) { 2178 makeStandardVariableGrid(c); 2179 2180 // Mast Aspect Box 2181 c.gridy = 6; 2182 c.gridx = 0; 2183 c.anchor = java.awt.GridBagConstraints.EAST; 2184 JLabel row5Label = new JLabel(Bundle.getMessage("LabelVariableAspect")); // NOI18N 2185 row5Label.setToolTipText(Bundle.getMessage("VariableAspectHint")); // NOI18N 2186 _gridPanel.add(row5Label, c); 2187 c.gridx = 1; 2188 c.anchor = java.awt.GridBagConstraints.WEST; 2189 _gridPanel.add(_variableSignalBox, c); 2190 } 2191 2192 /** 2193 * Create the Logix and Conditional rows and the State row. 2194 * 2195 * @param c The constraints object used for the grid construction 2196 */ 2197 void makeConditionalVariableGrid(GridBagConstraints c) { 2198 makeOptionsVariableGrid(c); 2199 2200 // Logix Selection ComboBox 2201 c.gridy = 4; 2202 c.gridx = 0; 2203 c.anchor = java.awt.GridBagConstraints.EAST; 2204 JLabel row4Label = new JLabel(Bundle.getMessage("SelectLogix")); // NOI18N 2205 row4Label.setToolTipText(Bundle.getMessage("VariableLogixHint")); // NOI18N 2206 _gridPanel.add(row4Label, c); 2207 c.gridx = 1; 2208 c.anchor = java.awt.GridBagConstraints.WEST; 2209 _gridPanel.add(_selectLogixBox, c); 2210 2211 // Conditional Selection ComboBox 2212 c.gridy = 5; 2213 c.gridx = 0; 2214 c.anchor = java.awt.GridBagConstraints.EAST; 2215 JLabel row5Label = new JLabel(Bundle.getMessage("SelectConditional")); // NOI18N 2216 row5Label.setToolTipText(Bundle.getMessage("VariableConditionalHint")); // NOI18N 2217 _gridPanel.add(row5Label, c); 2218 c.gridx = 1; 2219 c.anchor = java.awt.GridBagConstraints.WEST; 2220 _gridPanel.add(_selectConditionalBox, c); 2221 2222 // State Box 2223 c.gridy = 6; 2224 c.gridx = 0; 2225 c.anchor = java.awt.GridBagConstraints.EAST; 2226 JLabel row6Label = new JLabel(Bundle.getMessage("LabelVariableState")); // NOI18N 2227 row6Label.setToolTipText(Bundle.getMessage("VariableStateHint")); // NOI18N 2228 _gridPanel.add(row6Label, c); 2229 c.gridx = 1; 2230 c.anchor = java.awt.GridBagConstraints.WEST; 2231 _gridPanel.add(_variableStateBox, c); 2232 } 2233 2234 /** 2235 * Create the Memory specific rows. 2236 * 2237 * @param c The constraints object used for the grid construction 2238 */ 2239 void makeMemoryVariableGrid(GridBagConstraints c) { 2240 makeOptionsVariableGrid(c); 2241 2242 // Name Field 2243 c.gridy = 4; 2244 c.gridx = 0; 2245 c.anchor = java.awt.GridBagConstraints.EAST; 2246 JLabel row4Label = new JLabel(Bundle.getMessage("LabelItemName")); // NOI18N 2247 row4Label.setToolTipText(Bundle.getMessage("NameHintMemory")); // NOI18N 2248 _gridPanel.add(row4Label, c); 2249 c.gridx = 1; 2250 c.anchor = java.awt.GridBagConstraints.WEST; 2251 if (_selectionMode == SelectionMode.USECOMBO) { 2252 _gridPanel.add(_comboNameBox, c); 2253 } else { 2254 _gridPanel.add(_variableNameField, c); 2255 } 2256 2257 // Comparison Operator 2258 c.gridy = 5; 2259 c.gridx = 0; 2260 c.anchor = java.awt.GridBagConstraints.EAST; 2261 JLabel row5Label = new JLabel(Bundle.getMessage("LabelCompareOp")); // NOI18N 2262 row5Label.setToolTipText(Bundle.getMessage("CompareHintMemory")); // NOI18N 2263 _gridPanel.add(row5Label, c); 2264 c.gridx = 1; 2265 c.anchor = java.awt.GridBagConstraints.WEST; 2266 _gridPanel.add(_variableCompareOpBox, c); 2267 2268 // Compare As 2269 c.gridy = 6; 2270 c.gridx = 0; 2271 c.anchor = java.awt.GridBagConstraints.EAST; 2272 JLabel row6Label = new JLabel(Bundle.getMessage("LabelCompareType")); // NOI18N 2273 row6Label.setToolTipText(Bundle.getMessage("CompareTypeHint")); // NOI18N 2274 _gridPanel.add(row6Label, c); 2275 c.gridx = 1; 2276 c.anchor = java.awt.GridBagConstraints.WEST; 2277 _gridPanel.add(_variableCompareTypeBox, c); 2278 2279 // Literal Value (default) / Memory Value (name) 2280 c.gridy = 7; 2281 c.gridx = 0; 2282 c.anchor = java.awt.GridBagConstraints.EAST; 2283 _gridPanel.add(_variableMemoryValueLabel, c); 2284 c.gridx = 1; 2285 c.anchor = java.awt.GridBagConstraints.WEST; 2286 _gridPanel.add(_variableData1Field, c); 2287 } 2288 2289 /** 2290 * Create the Fast Clock start and end time rows. 2291 * 2292 * @param c The constraints object used for the grid construction 2293 */ 2294 void makeFastClockVariableGrid(GridBagConstraints c) { 2295 makeOptionsVariableGrid(c); 2296 2297 // Start Time Field 2298 c.gridy = 4; 2299 c.gridx = 0; 2300 c.anchor = java.awt.GridBagConstraints.EAST; 2301 JLabel row4Label = new JLabel(Bundle.getMessage("LabelStartTime")); // NOI18N 2302 row4Label.setToolTipText(Bundle.getMessage("DataHintTime")); // NOI18N 2303 _gridPanel.add(row4Label, c); 2304 c.gridx = 1; 2305 c.anchor = java.awt.GridBagConstraints.WEST; 2306 _gridPanel.add(_variableData1Field, c); 2307 2308 // End Time Field 2309 c.gridy = 5; 2310 c.gridx = 0; 2311 c.anchor = java.awt.GridBagConstraints.EAST; 2312 JLabel row5Label = new JLabel(Bundle.getMessage("LabelEndTime")); // NOI18N 2313 row5Label.setToolTipText(Bundle.getMessage("DataHintTime")); // NOI18N 2314 _gridPanel.add(row5Label, c); 2315 c.gridx = 1; 2316 c.anchor = java.awt.GridBagConstraints.WEST; 2317 _gridPanel.add(_variableData2Field, c); 2318 } 2319 2320 // ------------ Main Variable methods ------------ 2321 2322 /** 2323 * Set display to show current state variable (curVariable) parameters. 2324 */ 2325 void initializeStateVariables() { 2326 Conditional.Type testType = _curVariable.getType(); 2327 if (log.isDebugEnabled()) { 2328 log.debug("initializeStateVariables: testType= {}", testType); // NOI18N 2329 } 2330 Conditional.ItemType itemType = testType.getItemType(); 2331 log.debug("initializeStateVariables: itemType= {}, testType= {}", itemType, testType); // NOI18N 2332 if (itemType == _variableItemBox.getSelectedItem()) { 2333 // Force a refresh of variableTypeChanged 2334 variableTypeChanged(itemType); 2335 } 2336 _variableItemBox.setSelectedItem(itemType); 2337 _variableOperBox.setSelectedItem(_curVariable.getOpernString()); 2338 _variableNegated.setSelected(_curVariable.isNegated()); 2339 _variableTriggerActions.setSelected(_curVariable.doTriggerActions()); 2340 2341 switch (itemType) { 2342 case NONE: 2343 _variableNameField.setText(""); 2344 break; 2345 2346 case SENSOR: 2347 case TURNOUT: 2348 case LIGHT: 2349 case CONDITIONAL: 2350 case WARRANT: 2351 _variableStateBox.setSelectedItem(testType); 2352 _variableNameField.setText(_curVariable.getName()); 2353 break; 2354 2355 case SIGNALHEAD: 2356 _variableStateBox.setSelectedItem(testType); 2357 _variableNameField.setText(_curVariable.getName()); 2358 if (Conditional.Type.isSignalHeadApperance(testType)) { 2359 _variableStateBox.setSelectedItem(Conditional.Type.SIGNAL_HEAD_APPEARANCE_EQUALS); 2360 _variableSignalBox.setSelectedItem(_curVariable.getType()); 2361 } 2362 break; 2363 2364 case SIGNALMAST: 2365 // set display to show current state variable (curVariable) parameters 2366 _variableStateBox.setSelectedItem(testType); 2367 _variableNameField.setText(_curVariable.getName()); 2368 if (testType == Conditional.Type.SIGNAL_MAST_ASPECT_EQUALS) { 2369 _variableSignalBox.setSelectedItem(_curVariable.getDataString()); 2370 } 2371 break; 2372 2373 case MEMORY: 2374 _variableCompareTypeBox.setSelectedIndex( 2375 Conditional.Type.getIndexInList(Conditional.Type.getMemoryItems(), testType)); 2376 _variableNameField.setText(_curVariable.getName()); 2377 int num1 = _curVariable.getNum1() - 1; 2378 if (num1 == -1) { // former code was only equals 2379 num1 = ConditionalVariable.EQUAL - 1; 2380 } 2381 _variableCompareOpBox.setSelectedIndex(num1); 2382 _variableData1Field.setText(_curVariable.getDataString()); 2383 break; 2384 2385 case CLOCK: 2386 int time = _curVariable.getNum1(); 2387 _variableData1Field.setText(formatTime(time / 60, time - ((time / 60) * 60))); 2388 time = _curVariable.getNum2(); 2389 _variableData2Field.setText(formatTime(time / 60, time - ((time / 60) * 60))); 2390 _variableNameField.setText(""); 2391 break; 2392 2393 case OBLOCK: 2394 _variableNameField.setText(_curVariable.getName()); 2395 //_variableStateBox.removeAllItems(); 2396 for (Conditional.Type type : Conditional.Type.getOBlockItems()) { 2397 _variableStateBox.addItem(type); 2398 if (type.toString().equals(OBlock.getLocalStatusName(_curVariable.getDataString()))) { 2399 _variableStateBox.setSelectedItem(type); 2400 } 2401 } 2402// Iterator<String> names = OBlock.getLocalStatusNames(); 2403// while (names.hasNext()) { 2404// _variableStateBox.addItem(names.next()); 2405// } 2406// _variableStateBox.setSelectedItem(OBlock.getLocalStatusName(_curVariable.getDataString())); 2407 break; 2408 2409 case ENTRYEXIT: 2410 _variableNameField.setText(_curVariable.getBean().getUserName()); 2411 _variableStateBox.setSelectedItem(testType); 2412 break; 2413 2414 default: 2415 break; 2416 } 2417 _detailGrid.setVisible(true); 2418 } 2419 2420 /** 2421 * Respond to change in variable type chosen in the State Variable combo box. 2422 * 2423 * @param itemType value representing the newly selected Conditional type, 2424 * i.e. ITEM_TYPE_SENSOR 2425 */ 2426 private void variableTypeChanged(Conditional.ItemType itemType) { 2427 Conditional.Type testType = _curVariable.getType(); 2428 log.debug("variableTypeChanged: itemType= {}, testType= {}", itemType, testType); // NOI18N 2429 _variableStateBox.removeAllItems(); 2430 _variableNameField.removeActionListener(variableSignalHeadNameListener); 2431 _variableNameField.removeActionListener(variableSignalMastNameListener); 2432 _variableStateBox.removeActionListener(variableSignalTestStateListener); 2433 _detailGrid.setVisible(false); 2434 2435 if (_comboNameBox != null) { 2436 for (ActionListener item : _comboNameBox.getActionListeners()) { 2437 _comboNameBox.removeActionListener(item); 2438 } 2439 _comboNameBox.removeFocusListener(detailFocusEvent); 2440 } 2441 setPickWindow("Variable", itemType); // NOI18N 2442 2443 _variableOperBox.setSelectedItem(_curVariable.getOpernString()); 2444 _variableNegated.setSelected(_curVariable.isNegated()); 2445 _variableTriggerActions.setSelected(_curVariable.doTriggerActions()); 2446 2447 switch (itemType) { 2448 case NONE: 2449 makeDetailGrid("EmptyVariable"); // NOI18N 2450 break; 2451 2452 case SENSOR: 2453 _variableNameLabel.setToolTipText(Bundle.getMessage("NameHintSensor")); // NOI18N 2454 for (Conditional.Type type : Conditional.Type.getSensorItems()) { 2455 _variableStateBox.addItem(type); 2456 } 2457 setVariableNameBox(itemType); 2458 makeDetailGrid("StandardVariable"); // NOI18N 2459 break; 2460 2461 case TURNOUT: 2462 _variableNameLabel.setToolTipText(Bundle.getMessage("NameHintTurnout")); // NOI18N 2463 for (Conditional.Type type : Conditional.Type.getTurnoutItems()) { 2464 _variableStateBox.addItem(type); 2465 } 2466 setVariableNameBox(itemType); 2467 makeDetailGrid("StandardVariable"); // NOI18N 2468 break; 2469 2470 case LIGHT: 2471 _variableNameLabel.setToolTipText(Bundle.getMessage("NameHintLight")); // NOI18N 2472 for (Conditional.Type type : Conditional.Type.getLightItems()) { 2473 _variableStateBox.addItem(type); 2474 } 2475 setVariableNameBox(itemType); 2476 makeDetailGrid("StandardVariable"); // NOI18N 2477 break; 2478 2479 case SIGNALHEAD: 2480 _variableNameLabel.setToolTipText(Bundle.getMessage("NameHintSignal")); // NOI18N 2481 loadJComboBoxWithHeadAppearances(_variableSignalBox, _variableNameField.getText().trim()); 2482 2483 for (Conditional.Type type : Conditional.Type.getSignalHeadStateMachineItems()) { 2484 _variableStateBox.addItem(type); 2485 } 2486 2487 setVariableNameBox(itemType); 2488 if (testType == Conditional.Type.SIGNAL_HEAD_APPEARANCE_EQUALS) { 2489 makeDetailGrid("SignalAspectVariable"); // NOI18N 2490 } else { 2491 makeDetailGrid("StandardVariable"); // NOI18N 2492 } 2493 2494 _variableNameField.addActionListener(variableSignalHeadNameListener); 2495 _variableStateBox.addActionListener(variableSignalTestStateListener); 2496 break; 2497 2498 case SIGNALMAST: 2499 _variableNameLabel.setToolTipText(Bundle.getMessage("NameHintSignalMast")); // NOI18N 2500 _variableNameField.addActionListener(variableSignalMastNameListener); 2501 _variableStateBox.addActionListener(variableSignalTestStateListener); 2502 loadJComboBoxWithMastAspects(_variableSignalBox, _variableNameField.getText().trim()); 2503 2504 for (Conditional.Type type : Conditional.Type.getSignalMastItems()) { 2505 _variableStateBox.addItem(type); 2506 } 2507 setVariableNameBox(itemType); 2508 if (testType == Conditional.Type.SIGNAL_MAST_ASPECT_EQUALS) { 2509 makeDetailGrid("SignalAspectVariable"); // NOI18N 2510 } else { 2511 makeDetailGrid("StandardVariable"); // NOI18N 2512 } 2513 break; 2514 2515 case MEMORY: 2516 _variableNameLabel.setToolTipText(Bundle.getMessage("NameHintMemory")); // NOI18N 2517 setVariableNameBox(itemType); 2518 makeDetailGrid("MemoryVariable"); // NOI18N 2519 compareTypeChanged(testType); // Force the label update 2520 break; 2521 2522 case CONDITIONAL: 2523 for (Conditional.Type type : Conditional.Type.getConditionalItems()) { 2524 _variableStateBox.addItem(type); 2525 } 2526 loadSelectLogixBox(); 2527 makeDetailGrid("ConditionalVariable"); // NOI18N 2528 _selectLogixBox.addActionListener(selectLogixBoxListener); 2529 _selectConditionalBox.addActionListener(selectConditionalBoxListener); 2530 break; 2531 2532 case WARRANT: 2533 _variableNameLabel.setToolTipText(Bundle.getMessage("NameHintWarrant")); // NOI18N 2534 for (Conditional.Type type : Conditional.Type.getWarrantItems()) { 2535 _variableStateBox.addItem(type); 2536 } 2537 setVariableNameBox(itemType); 2538 makeDetailGrid("StandardVariable"); // NOI18N 2539 break; 2540 2541 case CLOCK: 2542 makeDetailGrid("FastClockVariable"); // NOI18N 2543 break; 2544 2545 case OBLOCK: 2546 _variableNameLabel.setToolTipText(Bundle.getMessage("NameHintOBlock")); // NOI18N 2547 _variableStateBox.removeAllItems(); 2548 for (Conditional.Type type : Conditional.Type.getOBlockItems()) { 2549 _variableStateBox.addItem(type); 2550 } 2551// Iterator<String> names = OBlock.getLocalStatusNames(); 2552// while (names.hasNext()) { 2553// _variableStateBox.addItem(names.next()); 2554// } 2555 setVariableNameBox(itemType); 2556 makeDetailGrid("StandardVariable"); // NOI18N 2557 break; 2558 2559 case ENTRYEXIT: 2560 _variableNameLabel.setToolTipText(Bundle.getMessage("NameHintEntryExit")); // NOI18N 2561 _variableNameField.setText(_curVariable.getName()); 2562 for (Conditional.Type type : Conditional.Type.getEntryExitItems()) { 2563 _variableStateBox.addItem(type); 2564 } 2565 setVariableNameBox(itemType); 2566 makeDetailGrid("StandardVariable"); // NOI18N 2567 break; 2568 2569 default: 2570 break; 2571 } 2572 } 2573 2574 /** 2575 * Update the name combo box selection based on the current contents of the 2576 * name field. Called by variableItemChanged. 2577 * 2578 * @since 4.7.3 2579 * @param itemType The item type, such as sensor or turnout. 2580 */ 2581 void setVariableNameBox(Conditional.ItemType itemType) { 2582 if (_selectionMode != SelectionMode.USECOMBO) { 2583 return; 2584 } 2585 _comboNameBox = createNameBox(itemType); 2586 if (_comboNameBox == null) { 2587 return; 2588 } 2589 // Select the current entry, add the listener 2590 _comboNameBox.setSelectedItemByName(_curVariable.getName()); 2591 _comboNameBox.addActionListener(new NameBoxListener(_variableNameField)); 2592 _comboNameBox.addFocusListener(detailFocusEvent); 2593 } 2594 2595 // ------------ Variable detail methods ------------ 2596 2597 /** 2598 * Respond to Cancel variable button 2599 */ 2600 void cancelEditVariable() { 2601 if (_newVariableItem) { 2602 _newVariableItem = false; 2603 deletePressed(); 2604 } 2605 cleanUpVariable(); 2606 } 2607 2608 /** 2609 * Respond to Update Variable button in the Edit Variable pane. 2610 */ 2611 void updateVariable() { 2612 if (!validateVariable()) { 2613 return; 2614 } 2615 _newVariableItem = false; 2616 _curConditional.setStateVariables(_variableList); 2617 2618 // Update conditional references 2619 TreeSet<String> newTargetNames = new TreeSet<>(); 2620 loadReferenceNames(_variableList, newTargetNames); 2621 updateWhereUsed(_oldTargetNames, newTargetNames, _curNodeName); 2622 2623 // Update the tree nodeChanged 2624 _curNode.setText(buildNodeText("Variable", _curVariable, _curNodeRow)); // NOI18N 2625 _cdlModel.nodeChanged(_curNode); 2626 cleanUpVariable(); 2627 } 2628 2629 /** 2630 * Clean up: Cancel, Update and Delete Variable buttons. 2631 */ 2632 void cleanUpVariable() { 2633 if (_logicType != Conditional.AntecedentOperator.MIXED) { 2634 setMoveButtons(); 2635 } 2636 } 2637 2638 /** 2639 * Load the Logix selection box. Set the selection to the current Logix. 2640 * 2641 * @since 4.7.4 2642 */ 2643 void loadSelectLogixBox() { 2644 // Get the current Logix name for selecting the current combo box row 2645 String cdlName = _curVariable.getName(); 2646 String lgxName; 2647 if (cdlName.length() == 0 || (_curVariable.getType() != Conditional.Type.CONDITIONAL_TRUE 2648 && _curVariable.getType() != Conditional.Type.CONDITIONAL_FALSE)) { 2649 // Use the current logix name for "add" state variable 2650 lgxName = _curLogix.getSystemName(); 2651 } else { 2652 Logix x = _conditionalManager.getParentLogix(cdlName); 2653 if (x == null) { 2654 log.error("Unable to find the Logix for {}, using the current Logix", cdlName); // NOI18N 2655 lgxName = _curLogix.getSystemName(); 2656 } else { 2657 lgxName = x.getSystemName(); 2658 } 2659 } 2660 2661 _selectLogixBox.removeAllItems(); 2662 _selectLogixMap.clear(); 2663 2664 String itemKey = ""; 2665 for (Logix lgx : _logixManager.getNamedBeanSet()) { 2666 String sName = lgx.getSystemName(); 2667 if (sName.equals("SYS")) { // NOI18N 2668 // Cannot refer to sensor name groups 2669 continue; 2670 } 2671 String uName = lgx.getUserName(); 2672 String itemName = ""; 2673 if (uName == null || uName.length() < 1) { 2674 itemName = sName; 2675 } else { 2676 itemName = uName + " ( " + sName + " )"; 2677 } 2678 _selectLogixMap.put(itemName, sName); 2679 if (lgxName.equals(sName)) { 2680 itemKey = itemName; 2681 } 2682 } 2683 2684 // Load the combo box 2685 for (String item : _selectLogixMap.keySet()) { 2686 _selectLogixBox.addItem(item); 2687 } 2688 2689 JComboBoxUtil.setupComboBoxMaxRows(_selectLogixBox); 2690 _selectLogixBox.setSelectedItem(itemKey); 2691 loadSelectConditionalBox(lgxName); 2692 } 2693 2694 /** 2695 * Load the Conditional selection box. The first row is a prompt. 2696 * 2697 * @since 4.7.4 2698 * @param logixName The Logix system name for selecting the owned 2699 * Conditionals 2700 */ 2701 void loadSelectConditionalBox(String logixName) { 2702 // Get the current Conditional name for selecting the current combo box row 2703 String cdlName = _curVariable.getName(); 2704 2705 _selectConditionalBox.removeAllItems(); 2706 _selectConditionalList.clear(); 2707 2708 // Create the first row 2709 String itemKey = Bundle.getMessage("SelectFirstRow"); // NOI18N 2710 _selectConditionalBox.addItem(itemKey); 2711 _selectConditionalList.add("-None-"); // NOI18N 2712 2713 Logix x = _logixManager.getBySystemName(logixName); 2714 if (x == null) { 2715 log.error("Logix '{}' not found while building the conditional list", logixName); // NOI18N 2716 return; 2717 } 2718 if (x.getNumConditionals() == 0) { 2719 return; 2720 } 2721 for (String cName : _conditionalManager.getSystemNameListForLogix(x)) { 2722 Conditional c = _conditionalManager.getConditional(cName); 2723 if (_curConditional.getSystemName().equals(c.getSystemName())) { 2724 // Don't add myself to the list 2725 continue; 2726 } 2727 String uName = c.getUserName(); 2728 String itemName = ""; 2729 if (uName == null || uName.length() < 1) { 2730 itemName = cName; 2731 } else { 2732 itemName = uName + " ( " + cName + " )"; 2733 } 2734 _selectConditionalBox.addItem(itemName); 2735 _selectConditionalList.add(cName); 2736 if (cdlName.equals(cName)) { 2737 itemKey = itemName; 2738 } 2739 } 2740 JComboBoxUtil.setupComboBoxMaxRows(_selectConditionalBox); 2741 _selectConditionalBox.setSelectedItem(itemKey); 2742 } 2743 2744 /** 2745 * Check if Memory type in a Conditional was changed by the user. 2746 * <p> 2747 * Update GUI if it has. 2748 * 2749 * @param testType One of the four types 2750 */ 2751 private void compareTypeChanged(Conditional.Type testType) { 2752 if ((testType == Conditional.Type.MEMORY_COMPARE) 2753 || (testType == Conditional.Type.MEMORY_COMPARE_INSENSITIVE)) { 2754 _variableMemoryValueLabel.setText(Bundle.getMessage("LabelMemoryValue")); // NOI18N 2755 _variableMemoryValueLabel.setToolTipText(Bundle.getMessage("DataHintMemory")); // NOI18N 2756 } else { 2757 _variableMemoryValueLabel.setText(Bundle.getMessage("LabelLiteralValue")); // NOI18N 2758 _variableMemoryValueLabel.setToolTipText(Bundle.getMessage("DataHintValue")); // NOI18N 2759 } 2760 } 2761 2762 /** 2763 * Fetch valid localized appearances for a given Signal Head. 2764 * <p> 2765 * Warn if head is not found. 2766 * 2767 * @param box the comboBox on the setup pane to fill 2768 * @param signalHeadName user or system name of the Signal Head 2769 */ 2770 void loadJComboBoxWithHeadAppearances(JComboBox<String> box, String signalHeadName) { 2771 box.removeAllItems(); 2772 log.debug("loadJComboBoxWithSignalHeadAppearances called with name: {}", signalHeadName); // NOI18N 2773 SignalHead h = InstanceManager.getDefault(jmri.SignalHeadManager.class).getSignalHead(signalHeadName); 2774 if (h == null) { 2775 box.addItem(Bundle.getMessage("PromptLoadHeadName")); // NOI18N 2776 } else { 2777 String[] v = h.getValidStateNames(); 2778 for (int i = 0; i < v.length; i++) { 2779 box.addItem(v[i]); 2780 } 2781 box.setSelectedItem(h.getAppearanceName()); 2782 } 2783 } 2784 2785 /** 2786 * Fetch valid aspects for a given Signal Mast. 2787 * <p> 2788 * Warn if mast is not found. 2789 * 2790 * @param box the comboBox on the setup pane to fill 2791 * @param mastName user or system name of the Signal Mast 2792 */ 2793 void loadJComboBoxWithMastAspects(JComboBox<String> box, String mastName) { 2794 box.removeAllItems(); 2795 SignalMast m = InstanceManager.getDefault(jmri.SignalMastManager.class).getSignalMast(mastName); 2796 if (m == null) { 2797 box.addItem(Bundle.getMessage("PromptLoadMastName")); // NOI18N 2798 } else { 2799 java.util.Vector<String> v = m.getValidAspects(); 2800 for (int i = 0; i < v.size(); i++) { 2801 box.addItem(v.get(i)); 2802 } 2803 box.setSelectedItem(m.getAspect()); 2804 } 2805 } 2806 2807 // ------------ Variable update processes ------------ 2808 2809 /** 2810 * Validate Variable data from Edit Variable panel, and transfer it to 2811 * current variable object as appropriate. 2812 * <p> 2813 * Messages are sent to the user for any errors found. This routine returns 2814 * false immediately after finding the first error, even if there might be 2815 * more errors. 2816 * 2817 * @return true if all data checks out OK, otherwise false 2818 */ 2819 boolean validateVariable() { 2820 String name = _variableNameField.getText().trim(); 2821 _variableNameField.setText(name); 2822 _curVariable.setDataString(""); 2823 _curVariable.setNum1(0); 2824 _curVariable.setNum2(0); 2825 2826 updateVariableOperator(); 2827 updateVariableNegation(); 2828 _curVariable.setTriggerActions(_variableTriggerActions.isSelected()); 2829 2830 Conditional.ItemType itemType = _variableItemBox.getItemAt(_variableItemBox.getSelectedIndex()); 2831 if (!checkIsAction(name, itemType) ) { 2832 return false; 2833 } 2834 Conditional.Type testType = Conditional.Type.NONE; 2835 switch (itemType) { 2836 case SENSOR: 2837 case TURNOUT: 2838 case LIGHT: 2839 case SIGNALHEAD: 2840 case SIGNALMAST: 2841 case CONDITIONAL: 2842 case WARRANT: 2843 case ENTRYEXIT: 2844 testType = _variableStateBox.getItemAt(_variableStateBox.getSelectedIndex()); 2845 break; 2846 case MEMORY: 2847 testType = _variableCompareTypeBox.getItemAt(_variableCompareTypeBox.getSelectedIndex()); 2848 break; 2849 case CLOCK: 2850 testType = Conditional.Type.FAST_CLOCK_RANGE; 2851 break; 2852 case OBLOCK: 2853 testType = Conditional.Type.BLOCK_STATUS_EQUALS; 2854 break; 2855 default: 2856 JmriJOptionPane.showMessageDialog(_editLogixFrame, 2857 Bundle.getMessage("ErrorVariableType"), Bundle.getMessage("ErrorTitle"), // NOI18N 2858 JmriJOptionPane.ERROR_MESSAGE); 2859 return false; 2860 } 2861 _curVariable.setType(testType); 2862 log.debug("validateVariable: itemType= {}, testType= {}", itemType, testType); // NOI18N 2863 switch (itemType) { 2864 case SENSOR: 2865 name = validateSensorReference(name); 2866 if (name == null) { 2867 return false; 2868 } 2869 break; 2870 case TURNOUT: 2871 name = validateTurnoutReference(name); 2872 if (name == null) { 2873 return false; 2874 } 2875 break; 2876 case CONDITIONAL: 2877 name = validateConditionalReference(name); 2878 if (name == null) { 2879 return false; 2880 } 2881 _curVariable.setName(name); 2882 Conditional c = _conditionalManager.getBySystemName(name); 2883 if (c == null) { 2884 return false; 2885 } 2886 String uName = c.getUserName(); 2887 if (uName == null || uName.isEmpty()) { 2888 _curVariable.setGuiName(c.getSystemName()); 2889 } else { 2890 _curVariable.setGuiName(uName); 2891 } 2892 break; 2893 case LIGHT: 2894 name = validateLightReference(name); 2895 if (name == null) { 2896 return false; 2897 } 2898 break; 2899 case MEMORY: 2900 name = validateMemoryReference(name); 2901 if (name == null) { 2902 return false; 2903 } 2904 String name2 = _variableData1Field.getText(); 2905 if ((testType == Conditional.Type.MEMORY_COMPARE) 2906 || (testType == Conditional.Type.MEMORY_COMPARE_INSENSITIVE)) { 2907 name2 = validateMemoryReference(name2); 2908 if (name2 == null) { 2909 return false; 2910 } 2911 } 2912 _curVariable.setDataString(name2); 2913 _curVariable.setNum1(_variableCompareOpBox.getSelectedIndex() + 1); 2914 break; 2915 case CLOCK: 2916 int beginTime = parseTime(_variableData1Field.getText()); 2917 if (beginTime < 0) { 2918 // parse error occurred - message has been sent 2919 return (false); 2920 } 2921 int endTime = parseTime(_variableData2Field.getText()); 2922 if (endTime < 0) { 2923 return (false); 2924 } 2925 // set beginning and end time (minutes since midnight) 2926 _curVariable.setNum1(beginTime); 2927 _curVariable.setNum2(endTime); 2928 name = "Clock"; // NOI18N 2929 break; 2930 case SIGNALHEAD: 2931 name = validateSignalHeadReference(name); 2932 if (name == null) { 2933 return false; 2934 } 2935 if (testType == Conditional.Type.SIGNAL_HEAD_APPEARANCE_EQUALS) { 2936 String appStr = (String) _variableSignalBox.getSelectedItem(); 2937 if (appStr != null) { 2938 Conditional.Type type = ConditionalVariable.stringToVariableTest(appStr); 2939 if (type == Conditional.Type.ERROR) { 2940 JmriJOptionPane.showMessageDialog(_editLogixFrame, Bundle.getMessage("ErrorAppearance"), Bundle.getMessage("ErrorTitle"), // NOI18N 2941 JmriJOptionPane.ERROR_MESSAGE); 2942 return false; 2943 } 2944 _curVariable.setType(type); 2945 _curVariable.setDataString(appStr); 2946 log.debug("SignalHead \"{}\"of type '{}' _variableSignalBox.getSelectedItem()= {}", name, testType, _variableSignalBox.getSelectedItem()); // NOI18N 2947 } else { 2948 log.warn("null selection in _variableSignalBox"); 2949 } 2950 } 2951 break; 2952 case SIGNALMAST: 2953 name = validateSignalMastReference(name); 2954 if (name == null) { 2955 return false; 2956 } 2957 if (testType == Conditional.Type.SIGNAL_MAST_ASPECT_EQUALS) { 2958 if (_variableSignalBox.getSelectedIndex() < 0) { 2959 JmriJOptionPane.showMessageDialog(_editLogixFrame, 2960 Bundle.getMessage("ErrorAspect"), Bundle.getMessage("ErrorTitle"), // NOI18N 2961 JmriJOptionPane.ERROR_MESSAGE); 2962 return false; 2963 } 2964 // save the selected aspect for comparison 2965 _curVariable.setDataString((String) _variableSignalBox.getSelectedItem()); 2966 // _curVariable.setType(ConditionalVariable.stringToVariableTest(appStr)); 2967 } 2968 break; 2969 case WARRANT: 2970 name = validateWarrantReference(name); 2971 if (name == null) { 2972 return false; 2973 } 2974 break; 2975 case OBLOCK: 2976 name = validateOBlockReference(name); 2977 if (name == null) { 2978 return false; 2979 } 2980 String stri18n = (String) _variableStateBox.getSelectedItem(); 2981 if (stri18n != null) { 2982 _curVariable.setDataString(OBlock.getSystemStatusName(stri18n)); 2983 log.debug("OBlock \"{}\"of type '{}' _variableSignalBox.getSelectedItem()= {}", name, testType, _variableSignalBox.getSelectedItem()); // NOI18N 2984 } 2985 break; 2986 case ENTRYEXIT: 2987 name = validateEntryExitReference(name); 2988 if (name == null) { 2989 return false; 2990 } 2991 break; 2992 default: 2993 JmriJOptionPane.showMessageDialog(_editLogixFrame, 2994 Bundle.getMessage("ErrorVariableType"), Bundle.getMessage("ErrorTitle"), // NOI18N 2995 JmriJOptionPane.ERROR_MESSAGE); 2996 return false; 2997 } 2998 _curVariable.setName(name); 2999 boolean result = _curVariable.evaluate(); 3000 log.debug("State Variable \"{}\" of type '{}' state= {} type= {}", 3001 name, testType.getTestTypeString(), 3002 result, _curVariable.getType()); // NOI18N 3003 if (_curVariable.getType() == Conditional.Type.NONE) { 3004 JmriJOptionPane.showMessageDialog(_editLogixFrame, 3005 Bundle.getMessage("ErrorVariableState"), Bundle.getMessage("ErrorTitle"), // NOI18N 3006 JmriJOptionPane.ERROR_MESSAGE); 3007 return false; 3008 } 3009 return (true); 3010 } 3011 3012 /** 3013 * Update the variable operation. If a change has occurred, also update the 3014 * antecedent and antecedent tree node. 3015 */ 3016 @SuppressFBWarnings(value = "BC_UNCONFIRMED_CAST_OF_RETURN_VALUE", justification = "Except for the root node, all nodes are ConditionalTreeNode") // NOI18N 3017 void updateVariableOperator() { 3018 Operator oldOper = _curVariable.getOpern(); 3019 if (_curNodeRow > 0) { 3020 if (_variableOperBox.getSelectedIndex() == 0) { 3021 _curVariable.setOpern(Conditional.Operator.AND); 3022 } else { 3023 _curVariable.setOpern(Conditional.Operator.OR); 3024 } 3025 } else { 3026 _curVariable.setOpern(Conditional.Operator.NONE); 3027 } 3028 if (_curVariable.getOpern() != oldOper) { 3029 makeAntecedent(); 3030 _curConditional.setLogicType(_logicType, _antecedent); // non-localized 3031 ConditionalTreeNode antLeaf = (ConditionalTreeNode) ((ConditionalTreeNode) _curNode.getParent()).getPreviousSibling(); 3032 antLeaf.setText(buildNodeText("Antecedent", _curConditional, 0)); // NOI18N 3033 _cdlModel.nodeChanged(antLeaf); 3034 } 3035 } 3036 3037 /** 3038 * Update the variable negation. If a change has occurred, also update the 3039 * antecedent and antecedent tree node. 3040 */ 3041 @SuppressFBWarnings(value = "BC_UNCONFIRMED_CAST_OF_RETURN_VALUE", justification = "Except for the root node, all nodes are ConditionalTreeNode") // NOI18N 3042 void updateVariableNegation() { 3043 boolean state = _curVariable.isNegated(); 3044 if (_variableNegated.isSelected()) { 3045 _curVariable.setNegation(true); 3046 } else { 3047 _curVariable.setNegation(false); 3048 } 3049 if (_curVariable.isNegated() != state) { 3050 makeAntecedent(); 3051 _curConditional.setLogicType(_logicType, _antecedent); // non-localized 3052 ConditionalTreeNode antLeaf = (ConditionalTreeNode) ((ConditionalTreeNode) _curNode.getParent()).getPreviousSibling(); 3053 antLeaf.setText(buildNodeText("Antecedent", _curConditional, 0)); 3054 _cdlModel.nodeChanged(antLeaf); 3055 } 3056 } 3057 3058 /** 3059 * Update the conditional variable list and refresh the local copy. 3060 * The parent Logix is de-activated and re-activated. This ensures 3061 * that listeners are properly handled. 3062 * @since 4.11.2 3063 */ 3064 void updateVariableList() { 3065 _curLogix.deActivateLogix(); 3066 _curConditional.setStateVariables(_variableList); 3067 _variableList = _curConditional.getCopyOfStateVariables(); 3068 _curLogix.activateLogix(); 3069 } 3070 3071 // ------------ Variable detail listeners ------------ 3072 3073 transient ActionListener variableSignalHeadNameListener = new ActionListener() { 3074 @Override 3075 public void actionPerformed(ActionEvent e) { 3076 // fired when signal head name changes, but only 3077 // while in signal head mode 3078 log.debug("variableSignalHeadNameListener fires; _variableNameField : {}", _variableNameField.getText().trim()); // NOI18N 3079 loadJComboBoxWithHeadAppearances(_variableSignalBox, _variableNameField.getText().trim()); 3080 } 3081 }; 3082 3083 transient ActionListener variableSignalMastNameListener = new ActionListener() { 3084 @Override 3085 public void actionPerformed(ActionEvent e) { 3086 // fired when signal mast name changes, but only 3087 // while in signal mast mode 3088 log.debug("variableSignalMastNameListener fires; _variableNameField : {}", _variableNameField.getText().trim()); // NOI18N 3089 loadJComboBoxWithMastAspects(_variableSignalBox, _variableNameField.getText().trim()); 3090 } 3091 }; 3092 3093 transient ActionListener variableSignalTestStateListener = new ActionListener() { 3094 @Override 3095 public void actionPerformed(ActionEvent e) { 3096 log.debug("variableSignalTestStateListener fires; _variableItemBox.getSelectedIndex()= \"{}\" _variableStateBox.getSelectedIndex()= \"{}\"", // NOI18N 3097 _variableItemBox.getSelectedIndex(), 3098 _variableStateBox.getSelectedIndex()); 3099 3100 Conditional.ItemType itemType = _variableItemBox.getItemAt(_variableItemBox.getSelectedIndex()); 3101 3102 if (_variableStateBox.getSelectedIndex() == 1) { 3103 if (itemType == Conditional.ItemType.SIGNALHEAD) { 3104 loadJComboBoxWithHeadAppearances(_variableSignalBox, _variableNameField.getText().trim()); 3105 _detailGrid.setVisible(false); 3106 makeDetailGrid("SignalAspectVariable"); // NOI18N 3107 } else if (itemType == Conditional.ItemType.SIGNALMAST) { 3108 loadJComboBoxWithMastAspects(_variableSignalBox, _variableNameField.getText().trim()); 3109 _detailGrid.setVisible(false); 3110 makeDetailGrid("SignalAspectVariable"); // NOI18N 3111 } else { 3112 _detailGrid.setVisible(false); 3113 makeDetailGrid("StandardVariable"); // NOI18N 3114 } 3115 } else { 3116 _detailGrid.setVisible(false); 3117 makeDetailGrid("StandardVariable"); // NOI18N 3118 } 3119 } 3120 }; 3121 3122 transient ActionListener selectLogixBoxListener = new ActionListener() { 3123 @Override 3124 public void actionPerformed(ActionEvent e) { 3125 String lgxItem = (String) _selectLogixBox.getSelectedItem(); 3126 if (lgxItem != null) { 3127 String lgxName = _selectLogixMap.get(lgxItem); 3128 if (lgxName != null) { 3129 loadSelectConditionalBox(lgxName); 3130 } 3131 } 3132 } 3133 }; 3134 3135 transient ActionListener selectConditionalBoxListener = new ActionListener() { 3136 @Override 3137 public void actionPerformed(ActionEvent e) { 3138 int cdlIndex = _selectConditionalBox.getSelectedIndex(); 3139 if (cdlIndex > 0 && cdlIndex < _selectConditionalList.size()) { 3140 String cdlName = _selectConditionalList.get(cdlIndex); 3141 _variableNameField.setText(cdlName); 3142 } 3143 } 3144 }; 3145 3146 transient ActionListener compareTypeBoxListener = new ActionListener() { 3147 @Override 3148 public void actionPerformed(ActionEvent e) { 3149 int selection = _variableCompareTypeBox.getSelectedIndex(); 3150 compareTypeChanged(Conditional.Type.getMemoryItems().get(selection)); 3151 } 3152 }; 3153 3154 // ============ Edit Action Section ============ 3155 3156 /** 3157 * Called once during class initialization to define the GUI objects. Where 3158 * possible, the combo box content is loaded. 3159 */ 3160 void buildActionComponents() { 3161 // Item Type 3162 _actionItemBox = new JComboBox<>(); 3163 for (Conditional.ItemType itemType : Conditional.ItemType.values()) { 3164 _actionItemBox.addItem(itemType); 3165 } 3166 JComboBoxUtil.setupComboBoxMaxRows(_actionItemBox); 3167 _actionItemBox.addActionListener(new ActionListener() { 3168 @Override 3169 public void actionPerformed(ActionEvent e) { 3170 Conditional.ItemType newActionItem = 3171 _actionItemBox.getItemAt(_actionItemBox.getSelectedIndex()); 3172 if (log.isDebugEnabled()) { 3173 log.debug("_actionItemBox Listener: new = {}, curr = {}, row = {}", // NOI18N 3174 newActionItem, _curActionItem, _curNodeRow); 3175 } 3176 if (newActionItem != _curActionItem) { 3177 if (_curNodeRow >= 0) { 3178 _curAction = new DefaultConditionalAction(); 3179 _actionList.set(_curNodeRow, _curAction); 3180 } 3181 _curActionItem = newActionItem; 3182 } 3183 actionItemChanged(newActionItem); 3184 } 3185 }); 3186 3187 // Item Name 3188 _actionNameField = new JTextField(20); 3189 3190 // Action Type Box 3191 _actionTypeBox = new JComboBox<>(); 3192 JComboBoxUtil.setupComboBoxMaxRows(_actionTypeBox); 3193 _actionTypeBox.addItem(Conditional.Action.NONE); 3194 3195 // Action State Box 3196 _actionBox = new JComboBox<String>(); 3197 _actionBox.addItem(""); 3198 3199 // Short strings: Delay time, memory value/copy target 3200 _shortActionString = new JTextField(15); 3201 3202 // On Change / Trigger options 3203 _actionOptionBox = new JComboBox<String>(); 3204 3205 // File Selector 3206 _actionSetButton = new JButton("..."); // "File" replaced by ... 3207 _actionSetButton.addActionListener(new ActionListener() { 3208 @Override 3209 public void actionPerformed(ActionEvent e) { 3210 validateAction(); 3211 setFileLocation(e); 3212 } 3213 }); 3214 3215 // File names, etc. 3216 _longActionString = new JTextField(30); 3217 } 3218 3219 // ------------ Make Action Edit Grid Panels ------------ 3220 3221 /** 3222 * Create a one row grid with just the Action Item box. This is the base for 3223 * larger grids as well as the initial grid for new Actions. 3224 * 3225 * @param c the constraints object used for the grid construction 3226 */ 3227 void makeEmptyActionGrid(GridBagConstraints c) { 3228 // Action item box 3229 c.gridy = 0; 3230 c.gridx = 0; 3231 c.anchor = java.awt.GridBagConstraints.EAST; 3232 JLabel row0Label = new JLabel(Bundle.getMessage("LabelActionItem")); // NOI18N 3233 row0Label.setToolTipText(Bundle.getMessage("ActionItemHint")); // NOI18N 3234 _gridPanel.add(row0Label, c); 3235 c.gridx = 1; 3236 c.anchor = java.awt.GridBagConstraints.WEST; 3237 _gridPanel.add(_actionItemBox, c); 3238 } 3239 3240 /** 3241 * Create the standard Name and Type rows. 3242 * The name field will be either a text field or a combo box. 3243 * The name field label is a variable to support run time changes. 3244 * 3245 * @param c The constraints object used for the grid construction 3246 * @param finalRow Controls whether the tigger combo box is included 3247 */ 3248 void makeNameTypeActionGrid(GridBagConstraints c, boolean finalRow) { 3249 makeEmptyActionGrid(c); 3250 3251 Conditional.Action actionType = _curAction.getType(); 3252 Conditional.ItemType itemType = actionType.getItemType(); 3253 3254 // Name Field 3255 c.gridy = 1; 3256 c.gridx = 0; 3257 c.anchor = java.awt.GridBagConstraints.EAST; 3258 _gridPanel.add(_actionNameLabel, c); 3259 c.gridx = 1; 3260 c.anchor = java.awt.GridBagConstraints.WEST; 3261 if ((_selectionMode == SelectionMode.USECOMBO) 3262 && (itemType != Conditional.ItemType.AUDIO)) { 3263 _gridPanel.add(_comboNameBox, c); 3264 } else { 3265 _gridPanel.add(_actionNameField, c); 3266 } 3267 3268 // Action Type Box 3269 c.gridy = 2; 3270 c.gridx = 0; 3271 c.anchor = java.awt.GridBagConstraints.EAST; 3272 JLabel row5Label = new JLabel(Bundle.getMessage("LabelActionType")); // NOI18N 3273 row5Label.setToolTipText(Bundle.getMessage("ActionTypeHint")); // NOI18N 3274 _gridPanel.add(row5Label, c); 3275 c.gridx = 1; 3276 c.anchor = java.awt.GridBagConstraints.WEST; 3277 _gridPanel.add(_actionTypeBox, c); 3278 3279 if (itemType == Conditional.ItemType.NONE) { 3280 // Skip the change/trigger section for new Actions 3281 return; 3282 } 3283 3284 if (finalRow) { 3285 makeChangeTriggerActionGrid(c); 3286 } 3287 } 3288 3289 /** 3290 * Create the standard Type row. 3291 * 3292 * @param c The constraints object used for the grid construction 3293 * @param finalRow Controls whether the tigger combo box is included 3294 */ 3295 void makeTypeActionGrid(GridBagConstraints c, boolean finalRow) { 3296 makeEmptyActionGrid(c); 3297 3298 Conditional.Action actionType = _curAction.getType(); 3299 Conditional.ItemType itemType = actionType.getItemType(); 3300 3301 // Action Type Box 3302 c.gridy = 1; 3303 c.gridx = 0; 3304 c.anchor = java.awt.GridBagConstraints.EAST; 3305 JLabel row5Label = new JLabel(Bundle.getMessage("LabelActionType")); // NOI18N 3306 row5Label.setToolTipText(Bundle.getMessage("ActionTypeHint")); // NOI18N 3307 _gridPanel.add(row5Label, c); 3308 c.gridx = 1; 3309 c.anchor = java.awt.GridBagConstraints.WEST; 3310 _gridPanel.add(_actionTypeBox, c); 3311 3312 if (itemType == Conditional.ItemType.NONE) { 3313 // Skip the change/trigger section for new Actions 3314 return; 3315 } 3316 3317 if (finalRow) { 3318 makeChangeTriggerActionGrid(c); 3319 } 3320 } 3321 3322 /** 3323 * Add the action box to the grid. 3324 * 3325 * @param c The constraints object used for the grid construction 3326 * @param finalRow Controls whether the tigger combo box is included 3327 */ 3328 void makeStandardActionGrid(GridBagConstraints c, boolean finalRow) { 3329 makeNameTypeActionGrid(c, false); 3330 3331 // Action Box 3332 c.gridy = 3; 3333 c.gridx = 0; 3334 c.anchor = java.awt.GridBagConstraints.EAST; 3335 _gridPanel.add(_actionBoxLabel, c); 3336 c.gridx = 1; 3337 c.anchor = java.awt.GridBagConstraints.WEST; 3338 _gridPanel.add(_actionBox, c); 3339 3340 if (finalRow) { 3341 makeChangeTriggerActionGrid(c); 3342 } 3343 } 3344 3345 /** 3346 * Add the short name field to the grid. 3347 * 3348 * @param c The constraints object used for the grid construction 3349 * @param includeBox Controls whether the normal action type combo box is 3350 * included 3351 */ 3352 void makeShortFieldActionGrid(GridBagConstraints c, boolean includeBox) { 3353 if (includeBox) { 3354 makeStandardActionGrid(c, false); 3355 } else { 3356 makeNameTypeActionGrid(c, false); 3357 } 3358 3359 // Add the short text field 3360 c.gridy = 4; 3361 c.gridx = 0; 3362 c.anchor = java.awt.GridBagConstraints.EAST; 3363 _gridPanel.add(_shortActionLabel, c); 3364 c.gridx = 1; 3365 c.anchor = java.awt.GridBagConstraints.WEST; 3366 _gridPanel.add(_shortActionString, c); 3367 3368 makeChangeTriggerActionGrid(c); 3369 } 3370 3371 /** 3372 * Just a short text field, no name field. Used by set clock and jython 3373 * command. 3374 * 3375 * @param c The constraints object used for the grid construction 3376 */ 3377 void makeTypeShortActionGrid(GridBagConstraints c) { 3378 makeTypeActionGrid(c, false); 3379 3380 // Add the short text field 3381 c.gridy = 2; 3382 c.gridx = 0; 3383 c.anchor = java.awt.GridBagConstraints.EAST; 3384 _gridPanel.add(_shortActionLabel, c); 3385 c.gridx = 1; 3386 c.anchor = java.awt.GridBagConstraints.WEST; 3387 _gridPanel.add(_shortActionString, c); 3388 3389 makeChangeTriggerActionGrid(c); 3390 } 3391 3392 /** 3393 * Add the file selection components. 3394 * 3395 * @param c The constraints object used for the grid construction 3396 */ 3397 void makeFileActionGrid(GridBagConstraints c) { 3398 makeTypeActionGrid(c, false); 3399 3400 // Add the file selecttor 3401 c.gridy = 2; 3402 c.gridx = 0; 3403 c.anchor = java.awt.GridBagConstraints.EAST; 3404 _gridPanel.add(_shortActionLabel, c); 3405 c.gridx = 1; 3406 c.anchor = java.awt.GridBagConstraints.WEST; 3407 _gridPanel.add(_actionSetButton, c); 3408 3409 c.gridwidth = 2; // span both columns 3410 // Add the long text field 3411 c.gridy = 3; 3412 c.gridx = 0; 3413 c.anchor = java.awt.GridBagConstraints.CENTER; 3414 _gridPanel.add(_longActionString, c); 3415 c.gridwidth = 1; 3416 3417 makeChangeTriggerActionGrid(c); 3418 } 3419 3420 /** 3421 * Add the change/trigger box the grid. This is the last item in an Action 3422 * and is usually called from one of the other entry points. 3423 * 3424 * @param c The constraints object used for the grid construction 3425 */ 3426 void makeChangeTriggerActionGrid(GridBagConstraints c) { 3427 // Action item box 3428 c.gridy = 9; 3429 c.gridx = 0; 3430 c.anchor = java.awt.GridBagConstraints.EAST; 3431 JLabel row0Label = new JLabel(Bundle.getMessage("LabelActionOption")); // NOI18N 3432 row0Label.setToolTipText(Bundle.getMessage("ActionOptionHint")); // NOI18N 3433 _gridPanel.add(row0Label, c); 3434 c.gridx = 1; 3435 c.anchor = java.awt.GridBagConstraints.WEST; 3436 _gridPanel.add(_actionOptionBox, c); 3437 } 3438 3439 // ------------ Main Action methods ------------ 3440 3441 /** 3442 * Set display to show current action (curAction) parameters. 3443 */ 3444 void initializeActionVariables() { 3445 Conditional.Action actionType = _curAction.getType(); 3446 Conditional.ItemType itemType = actionType.getItemType(); 3447 log.debug("initializeActionVariables: itemType= {}, actionType= {}", itemType, actionType); // NOI18N 3448 _actionItemBox.setSelectedItem(itemType); 3449 _actionNameField.setText(_curAction.getDeviceName()); 3450 switch (itemType) { 3451 case NONE: 3452 _actionNameField.setText(""); 3453 break; 3454 3455 case SENSOR: 3456 _actionTypeBox.setSelectedItem(actionType); 3457 if ((actionType == Conditional.Action.RESET_DELAYED_SENSOR) 3458 || (actionType == Conditional.Action.DELAYED_SENSOR)) { 3459 _shortActionString.setText(_curAction.getActionString()); 3460 } 3461 if (actionType == Conditional.Action.SET_SENSOR 3462 || actionType == Conditional.Action.DELAYED_SENSOR 3463 || actionType == Conditional.Action.RESET_DELAYED_SENSOR) { 3464 if (_curAction.getActionData() == Sensor.ACTIVE) { 3465 _actionBox.setSelectedIndex(0); 3466 } else if (_curAction.getActionData() == Sensor.INACTIVE) { 3467 _actionBox.setSelectedIndex(1); 3468 } else if (_curAction.getActionData() == Route.TOGGLE) { 3469 _actionBox.setSelectedIndex(2); 3470 } 3471 } 3472 break; 3473 3474 case TURNOUT: 3475 _actionTypeBox.setSelectedItem(actionType); 3476 if ((actionType == Conditional.Action.RESET_DELAYED_TURNOUT) 3477 || (actionType == Conditional.Action.DELAYED_TURNOUT)) { 3478 _shortActionString.setText(_curAction.getActionString()); 3479 } 3480 if ((actionType == Conditional.Action.SET_TURNOUT) 3481 || (actionType == Conditional.Action.RESET_DELAYED_TURNOUT) 3482 || (actionType == Conditional.Action.DELAYED_TURNOUT)) { 3483 if (_curAction.getActionData() == Turnout.CLOSED) { 3484 _actionBox.setSelectedIndex(0); 3485 } else if (_curAction.getActionData() == Turnout.THROWN) { 3486 _actionBox.setSelectedIndex(1); 3487 } else if (_curAction.getActionData() == Route.TOGGLE) { 3488 _actionBox.setSelectedIndex(2); 3489 } 3490 } else if (actionType == Conditional.Action.LOCK_TURNOUT) { 3491 if (_curAction.getActionData() == Turnout.UNLOCKED) { 3492 _actionBox.setSelectedIndex(0); 3493 } else if (_curAction.getActionData() == Turnout.LOCKED) { 3494 _actionBox.setSelectedIndex(1); 3495 } else if (_curAction.getActionData() == Route.TOGGLE) { 3496 _actionBox.setSelectedIndex(2); 3497 } 3498 } 3499 break; 3500 3501 case LIGHT: 3502 _actionTypeBox.setSelectedItem(actionType); 3503 if (actionType == Conditional.Action.SET_LIGHT) { 3504 if (_curAction.getActionData() == Light.ON) { 3505 _actionBox.setSelectedIndex(0); 3506 } else if (_curAction.getActionData() == Light.OFF) { 3507 _actionBox.setSelectedIndex(1); 3508 } else if (_curAction.getActionData() == Route.TOGGLE) { 3509 _actionBox.setSelectedIndex(2); 3510 } 3511 } else if ((actionType == Conditional.Action.SET_LIGHT_INTENSITY) 3512 || (actionType == Conditional.Action.SET_LIGHT_TRANSITION_TIME)) { 3513 _shortActionString.setText(_curAction.getActionString()); 3514 } 3515 break; 3516 3517 case SIGNALHEAD: 3518 _actionTypeBox.setSelectedItem(actionType); 3519 if (actionType == Conditional.Action.SET_SIGNAL_APPEARANCE) { 3520 loadJComboBoxWithHeadAppearances(_actionBox, _actionNameField.getText().trim()); 3521 } 3522 break; 3523 3524 case CLOCK: 3525 _actionTypeBox.setSelectedItem(actionType); 3526 if (actionType == Conditional.Action.SET_FAST_CLOCK_TIME) { 3527 int time = _curAction.getActionData(); 3528 _longActionString.setText(formatTime(time / 60, time - ((time / 60) * 60))); 3529 _actionNameField.setText(""); 3530 } 3531 break; 3532 3533 case MEMORY: 3534 _actionTypeBox.setSelectedItem(actionType); 3535 _shortActionString.setText(_curAction.getActionString()); 3536 break; 3537 3538 case WARRANT: 3539 _actionTypeBox.setSelectedItem(actionType); 3540 if (actionType == Conditional.Action.CONTROL_TRAIN) { 3541 switch (_curAction.getActionData()) { 3542 case Warrant.HALT: 3543 _actionBox.setSelectedIndex(0); 3544 break; 3545 case Warrant.RESUME: 3546 _actionBox.setSelectedIndex(1); 3547 break; 3548 case Warrant.RETRY_FWD: 3549 _actionBox.setSelectedIndex(2); 3550 break; 3551 case Warrant.SPEED_UP: 3552 _actionBox.setSelectedIndex(3); 3553 break; 3554 case Warrant.STOP: 3555 _actionBox.setSelectedIndex(4); 3556 break; 3557 case Warrant.ESTOP: 3558 _actionBox.setSelectedIndex(5); 3559 break; 3560 case Warrant.ABORT: 3561 _actionBox.setSelectedIndex(6); 3562 break; 3563 default: 3564 log.warn("Unexpected _curAction.getActionData() of {}", _curAction.getActionData()); // NOI18N 3565 } 3566 } else if (actionType == Conditional.Action.SET_TRAIN_ID 3567 || actionType == Conditional.Action.SET_TRAIN_NAME) { 3568 _shortActionString.setText(_curAction.getActionString()); 3569 } 3570 break; 3571 3572 case OBLOCK: 3573 _actionTypeBox.setSelectedItem(actionType); 3574 if (actionType == Conditional.Action.SET_BLOCK_VALUE 3575 || actionType == Conditional.Action.SET_TRAIN_NAME 3576 || actionType == Conditional.Action.GET_TRAIN_LOCATION) { 3577 _shortActionString.setText(_curAction.getActionString()); 3578 } 3579 break; 3580 3581 case ENTRYEXIT: 3582 _actionNameField.setText(_curAction.getBean().getUserName()); 3583 _actionTypeBox.setSelectedItem(actionType); 3584 break; 3585 3586 case AUDIO: 3587 _actionTypeBox.setSelectedItem(actionType); 3588 if (actionType == Conditional.Action.PLAY_SOUND) { 3589 _longActionString.setText(_curAction.getActionString()); 3590 } else if (actionType == Conditional.Action.CONTROL_AUDIO) { 3591 switch (_curAction.getActionData()) { 3592 case Audio.CMD_PLAY: 3593 _actionBox.setSelectedIndex(0); 3594 break; 3595 case Audio.CMD_STOP: 3596 _actionBox.setSelectedIndex(1); 3597 break; 3598 case Audio.CMD_PLAY_TOGGLE: 3599 _actionBox.setSelectedIndex(2); 3600 break; 3601 case Audio.CMD_PAUSE: 3602 _actionBox.setSelectedIndex(3); 3603 break; 3604 case Audio.CMD_RESUME: 3605 _actionBox.setSelectedIndex(4); 3606 break; 3607 case Audio.CMD_PAUSE_TOGGLE: 3608 _actionBox.setSelectedIndex(5); 3609 break; 3610 case Audio.CMD_REWIND: 3611 _actionBox.setSelectedIndex(6); 3612 break; 3613 case Audio.CMD_FADE_IN: 3614 _actionBox.setSelectedIndex(7); 3615 break; 3616 case Audio.CMD_FADE_OUT: 3617 _actionBox.setSelectedIndex(8); 3618 break; 3619 case Audio.CMD_RESET_POSITION: 3620 _actionBox.setSelectedIndex(9); 3621 break; 3622 default: 3623 log.warn("Unexpected _curAction.getActionData() of {}", _curAction.getActionData()); // NOI18N 3624 break; 3625 } 3626 } 3627 break; 3628 3629 case SCRIPT: 3630 _actionTypeBox.setSelectedItem(actionType); 3631 if (actionType == Conditional.Action.RUN_SCRIPT) { 3632 _longActionString.setText(_curAction.getActionString()); 3633 } else if (actionType == Conditional.Action.JYTHON_COMMAND) { 3634 _shortActionString.setText(_curAction.getActionString()); 3635 } 3636 break; 3637 3638 case SIGNALMAST: 3639 case LOGIX: 3640 case OTHER: // ACTION_TRIGGER_ROUTE 3641 _actionTypeBox.setSelectedItem(actionType); 3642 break; 3643 3644 default: 3645 log.error("Unhandled type: {}", itemType); // NOI18N 3646 break; 3647 } 3648 _actionOptionBox.setSelectedIndex(_curAction.getOption() - 1); 3649 } 3650 3651 /** 3652 * Respond to a change in an Action Type comboBox. 3653 * <p> 3654 * Set components visible for the selected type. 3655 * 3656 * @param type index of the newly selected Action type 3657 */ 3658 void actionItemChanged(Conditional.ItemType type) { 3659 Conditional.Action actionType = _curAction.getType(); 3660 log.debug("actionItemChanged: itemType= {}, actionType= {}", type, actionType); // NOI18N 3661 _detailGrid.setVisible(false); 3662 _actionTypeBox.removeActionListener(_actionTypeListener); 3663 _shortActionString.setText(""); 3664 _longActionString.setText(""); 3665 _actionTypeBox.removeAllItems(); 3666 _actionTypeBox.addItem(Conditional.Action.NONE); 3667 _actionBox.removeAllItems(); 3668 Conditional.ItemType itemType = actionType.getItemType(); 3669 if (type != Conditional.ItemType.NONE) { // actionItem listener choice overrides current item 3670 itemType = type; 3671 } 3672 if (itemType != actionType.getItemType()) { 3673 actionType = Conditional.Action.NONE; // chosen item type does not support action type 3674 } 3675 3676 _actionNameField.removeActionListener(actionSignalHeadNameListener); 3677 _actionNameField.removeActionListener(actionSignalMastNameListener); 3678 3679 if (_comboNameBox != null) { 3680 for (ActionListener item : _comboNameBox.getActionListeners()) { 3681 _comboNameBox.removeActionListener(item); 3682 } 3683 _comboNameBox.removeFocusListener(detailFocusEvent); 3684 } 3685 setPickWindow("Action", itemType); // NOI18N 3686 3687 switch (itemType) { 3688 case NONE: 3689 makeDetailGrid("EmptyAction"); // NOI18N 3690 break; 3691 3692 case TURNOUT: 3693 _actionNameLabel.setToolTipText(Bundle.getMessage("NameHintTurnout")); // NOI18N 3694 String turnoutGrid = "NameTypeAction"; // NOI18N 3695 boolean delayTurnout = false; 3696 3697 for (Conditional.Action action : Conditional.Action.getTurnoutItems()) { 3698 _actionTypeBox.addItem(action); 3699 } 3700 3701 if ((actionType == Conditional.Action.RESET_DELAYED_TURNOUT) 3702 || (actionType == Conditional.Action.DELAYED_TURNOUT)) { 3703 delayTurnout = true; 3704 _shortActionLabel.setText(Bundle.getMessage("LabelDelayTime")); // NOI18N 3705 _shortActionLabel.setToolTipText(Bundle.getMessage("DataHintDelayedTurnout")); // NOI18N 3706 } 3707 if ((actionType == Conditional.Action.SET_TURNOUT) 3708 || (actionType == Conditional.Action.RESET_DELAYED_TURNOUT) 3709 || (actionType == Conditional.Action.DELAYED_TURNOUT)) { 3710 turnoutGrid = (delayTurnout) ? "ShortFieldAction" : "StandardAction"; // NOI18N 3711 _actionBoxLabel.setText(Bundle.getMessage("LabelActionTurnout")); // NOI18N 3712 _actionBoxLabel.setToolTipText(Bundle.getMessage("TurnoutSetHint")); // NOI18N 3713 _actionBox.addItem(Bundle.getMessage("TurnoutStateClosed")); // NOI18N 3714 _actionBox.addItem(Bundle.getMessage("TurnoutStateThrown")); // NOI18N 3715 _actionBox.addItem(Bundle.getMessage("Toggle")); // NOI18N 3716 } else if (actionType == Conditional.Action.LOCK_TURNOUT) { 3717 turnoutGrid = (delayTurnout) ? "ShortFieldAction" : "StandardAction"; // NOI18N 3718 _actionBoxLabel.setText(Bundle.getMessage("LabelActionLock")); // NOI18N 3719 _actionBoxLabel.setToolTipText(Bundle.getMessage("LockSetHint")); // NOI18N 3720 _actionBox.addItem(Bundle.getMessage("TurnoutUnlock")); // NOI18N 3721 _actionBox.addItem(Bundle.getMessage("TurnoutLock")); // NOI18N 3722 _actionBox.addItem(Bundle.getMessage("Toggle")); // NOI18N 3723 } else if ((actionType == Conditional.Action.CANCEL_TURNOUT_TIMERS) 3724 || (actionType == Conditional.Action.NONE)) { 3725 turnoutGrid = "NameTypeActionFinal"; // NOI18N 3726 } 3727 3728 setActionNameBox(itemType); 3729 makeDetailGrid(turnoutGrid); 3730 break; 3731 3732 case SENSOR: 3733 _actionNameLabel.setToolTipText(Bundle.getMessage("NameHintSensor")); // NOI18N 3734 String sensorGrid = "NameTypeAction"; // NOI18N 3735 boolean delaySensor = false; 3736 3737 for (Conditional.Action action : Conditional.Action.getSensorItems()) { 3738 _actionTypeBox.addItem(action); 3739 } 3740 if ((actionType == Conditional.Action.RESET_DELAYED_SENSOR) 3741 || (actionType == Conditional.Action.DELAYED_SENSOR)) { 3742 delaySensor = true; 3743 _shortActionLabel.setText(Bundle.getMessage("LabelDelayTime")); // NOI18N 3744 _shortActionLabel.setToolTipText(Bundle.getMessage("DataHintDelayedSensor")); // NOI18N 3745 } 3746 if ((actionType == Conditional.Action.SET_SENSOR) 3747 || (actionType == Conditional.Action.RESET_DELAYED_SENSOR) 3748 || (actionType == Conditional.Action.DELAYED_SENSOR)) { 3749 sensorGrid = (delaySensor) ? "ShortFieldAction" : "StandardAction"; // NOI18N 3750 _actionBoxLabel.setText(Bundle.getMessage("LabelActionSensor")); // NOI18N 3751 _actionBoxLabel.setToolTipText(Bundle.getMessage("SensorSetHint")); // NOI18N 3752 _actionBox.addItem(Bundle.getMessage("SensorStateActive")); // NOI18N 3753 _actionBox.addItem(Bundle.getMessage("SensorStateInactive")); // NOI18N 3754 _actionBox.addItem(Bundle.getMessage("Toggle")); // NOI18N 3755 } else if ((actionType == Conditional.Action.CANCEL_SENSOR_TIMERS) 3756 || (actionType == Conditional.Action.NONE)) { 3757 sensorGrid = "NameTypeActionFinal"; // NOI18N 3758 } 3759 3760 setActionNameBox(itemType); 3761 makeDetailGrid(sensorGrid); 3762 break; 3763 3764 case SIGNALHEAD: 3765 _actionNameLabel.setToolTipText(Bundle.getMessage("NameHintSignal")); // NOI18N 3766 String signalHeadGrid = "NameTypeAction"; // NOI18N 3767 _actionNameField.addActionListener(actionSignalHeadNameListener); 3768 3769 for (Conditional.Action action : Conditional.Action.getSignalHeadItems()) { 3770 _actionTypeBox.addItem(action); 3771 } 3772 3773 if (actionType == Conditional.Action.SET_SIGNAL_APPEARANCE) { 3774 signalHeadGrid = "StandardAction"; // NOI18N 3775 _actionBoxLabel.setText(Bundle.getMessage("LabelActionSignal")); // NOI18N 3776 _actionBoxLabel.setToolTipText(Bundle.getMessage("SignalSetHint")); // NOI18N 3777 loadJComboBoxWithHeadAppearances(_actionBox, _actionNameField.getText().trim()); 3778 _actionBox.setSelectedItem(_curAction.getActionDataString()); 3779 } else if (actionType != Conditional.Action.NONE) { 3780 signalHeadGrid = "NameTypeActionFinal"; // NOI18N 3781 } 3782 3783 setActionNameBox(itemType); 3784 makeDetailGrid(signalHeadGrid); 3785 break; 3786 3787 case SIGNALMAST: 3788 _actionNameLabel.setToolTipText(Bundle.getMessage("NameHintSignalMast")); // NOI18N 3789 String signalMastGrid = "NameTypeAction"; // NOI18N 3790 _actionNameField.addActionListener(actionSignalMastNameListener); 3791 3792 for (Conditional.Action action : Conditional.Action.getSignalMastItems()) { 3793 _actionTypeBox.addItem(action); 3794 } 3795 3796 if (actionType == Conditional.Action.SET_SIGNALMAST_ASPECT) { 3797 signalMastGrid = "StandardAction"; // NOI18N 3798 _actionBoxLabel.setText(Bundle.getMessage("LabelSignalAspect")); // NOI18N 3799 _actionBoxLabel.setToolTipText(Bundle.getMessage("SignalMastSetHint")); // NOI18N 3800 loadJComboBoxWithMastAspects(_actionBox, _actionNameField.getText().trim()); 3801 _actionBox.setSelectedItem(_curAction.getActionDataString()); 3802 } else if (actionType != Conditional.Action.NONE) { 3803 signalMastGrid = "NameTypeActionFinal"; // NOI18N 3804 } 3805 3806 setActionNameBox(itemType); 3807 makeDetailGrid(signalMastGrid); 3808 break; 3809 3810 case LIGHT: 3811 _actionNameLabel.setToolTipText(Bundle.getMessage("NameHintLight")); // NOI18N 3812 String lightGrid = "NameTypeAction"; // NOI18N 3813 3814 for (Conditional.Action action : Conditional.Action.getLightItems()) { 3815 _actionTypeBox.addItem(action); 3816 } 3817 3818 if (actionType == Conditional.Action.SET_LIGHT_INTENSITY) { 3819 lightGrid = "ShortFieldNoBoxAction"; // NOI18N 3820 _shortActionLabel.setText(Bundle.getMessage("LabelLightIntensity")); // NOI18N 3821 _shortActionLabel.setToolTipText(Bundle.getMessage("DataHintLightIntensity")); // NOI18N 3822 } else if (actionType == Conditional.Action.SET_LIGHT_TRANSITION_TIME) { 3823 lightGrid = "ShortFieldNoBoxAction"; // NOI18N 3824 _shortActionLabel.setText(Bundle.getMessage("LabelTransitionTime")); // NOI18N 3825 _shortActionLabel.setToolTipText(Bundle.getMessage("DataHintLightTransitionTime")); // NOI18N 3826 } else if (actionType == Conditional.Action.SET_LIGHT) { 3827 lightGrid = "StandardAction"; // NOI18N 3828 _actionBoxLabel.setText(Bundle.getMessage("LabelActionLight")); // NOI18N 3829 _actionBoxLabel.setToolTipText(Bundle.getMessage("LightSetHint")); // NOI18N 3830 _actionBox.addItem(Bundle.getMessage("LightOn")); // NOI18N 3831 _actionBox.addItem(Bundle.getMessage("LightOff")); // NOI18N 3832 _actionBox.addItem(Bundle.getMessage("Toggle")); // NOI18N 3833 } 3834 3835 setActionNameBox(itemType); 3836 makeDetailGrid(lightGrid); 3837 break; 3838 3839 case MEMORY: 3840 _actionNameLabel.setToolTipText(Bundle.getMessage("NameHintMemory")); // NOI18N 3841 String memoryGrid = "NameTypeAction"; // NOI18N 3842 3843 for (Conditional.Action action : Conditional.Action.getMemoryItems()) { 3844 _actionTypeBox.addItem(action); 3845 } 3846 3847 if (actionType == Conditional.Action.COPY_MEMORY) { 3848 memoryGrid = "ShortFieldNoBoxAction"; // NOI18N 3849 _shortActionLabel.setText(Bundle.getMessage("LabelMemoryLocation")); // NOI18N 3850 _shortActionLabel.setToolTipText(Bundle.getMessage("DataHintToMemory")); // NOI18N 3851 } else if (actionType == Conditional.Action.SET_MEMORY) { 3852 memoryGrid = "ShortFieldNoBoxAction"; // NOI18N 3853 _shortActionLabel.setText(Bundle.getMessage("LabelValue")); // NOI18N 3854 _shortActionLabel.setToolTipText(Bundle.getMessage("DataHintMemory")); // NOI18N 3855 } 3856 3857 setActionNameBox(itemType); 3858 makeDetailGrid(memoryGrid); 3859 break; 3860 3861 case CLOCK: 3862 String clockGrid = "TypeAction"; // NOI18N 3863 3864 for (Conditional.Action action : Conditional.Action.getClockItems()) { 3865 _actionTypeBox.addItem(action); 3866 } 3867 3868 if (actionType == Conditional.Action.SET_FAST_CLOCK_TIME) { 3869 clockGrid = "TypeShortAction"; // NOI18N 3870 _shortActionLabel.setText(Bundle.getMessage("LabelSetTime")); // NOI18N 3871 _shortActionLabel.setToolTipText(Bundle.getMessage("DataHintTime")); // NOI18N 3872 } else if ((actionType == Conditional.Action.START_FAST_CLOCK) 3873 || (actionType == Conditional.Action.STOP_FAST_CLOCK)) { 3874 clockGrid = "TypeActionFinal"; // NOI18N 3875 } 3876 3877 makeDetailGrid(clockGrid); 3878 break; 3879 3880 case LOGIX: 3881 _actionNameLabel.setToolTipText(Bundle.getMessage("NameHintLogix")); // NOI18N 3882 String logixGrid = "NameTypeAction"; // NOI18N 3883 3884 for (Conditional.Action action : Conditional.Action.getLogixItems()) { 3885 _actionTypeBox.addItem(action); 3886 } 3887 3888 if ((actionType == Conditional.Action.ENABLE_LOGIX) 3889 || (actionType == Conditional.Action.DISABLE_LOGIX)) { 3890 logixGrid = "NameTypeActionFinal"; // NOI18N 3891 } 3892 3893 setActionNameBox(itemType); 3894 makeDetailGrid(logixGrid); 3895 break; 3896 3897 case WARRANT: 3898 _actionNameLabel.setToolTipText(Bundle.getMessage("NameHintWarrant")); // NOI18N 3899 String warrantGrid = "NameTypeAction"; // NOI18N 3900 3901 for (Conditional.Action action : Conditional.Action.getWarrantItems()) { 3902 _actionTypeBox.addItem(action); 3903 } 3904 3905 if (actionType == Conditional.Action.CONTROL_TRAIN) { 3906 warrantGrid = "StandardAction"; // NOI18N 3907 _actionBoxLabel.setText(Bundle.getMessage("LabelControlTrain")); // NOI18N 3908 _actionBoxLabel.setToolTipText(Bundle.getMessage("DataHintTrainControl")); // NOI18N 3909 _actionBox.addItem(Bundle.getMessage("WarrantHalt")); 3910 _actionBox.addItem(Bundle.getMessage("WarrantResume")); 3911 _actionBox.addItem(Bundle.getMessage("WarrantMoveToNext")); 3912 _actionBox.addItem(Bundle.getMessage("WarrantSpeedUp")); 3913 _actionBox.addItem(Bundle.getMessage("WarrantStop")); 3914 _actionBox.addItem(Bundle.getMessage("WarantEStop")); 3915 _actionBox.addItem(Bundle.getMessage("WarrantAbort")); 3916 } else if (actionType == Conditional.Action.SET_TRAIN_ID 3917 || actionType == Conditional.Action.SET_TRAIN_NAME 3918 || actionType == Conditional.Action.GET_TRAIN_LOCATION) { 3919 warrantGrid = "ShortFieldNoBoxAction"; // NOI18N 3920 if (actionType == Conditional.Action.SET_TRAIN_ID) { 3921 _shortActionLabel.setText(Bundle.getMessage("LabelTrainId")); // NOI18N 3922 _shortActionLabel.setToolTipText(Bundle.getMessage("DataHintTrainId")); // NOI18N 3923 } else if (actionType == Conditional.Action.SET_TRAIN_NAME) { 3924 _shortActionLabel.setText(Bundle.getMessage("LabelTrainName")); // NOI18N 3925 _shortActionLabel.setToolTipText(Bundle.getMessage("DataHintTrainName")); // NOI18N 3926 } else if (actionType == Conditional.Action.GET_TRAIN_LOCATION) { 3927 _shortActionLabel.setText(Bundle.getMessage("LabelMemoryLocation")); // NOI18N 3928 _shortActionLabel.setToolTipText(Bundle.getMessage("DataHintToMemory")); // NOI18N 3929 } 3930 } 3931 setActionNameBox(itemType); 3932 makeDetailGrid(warrantGrid); 3933 break; 3934 3935 case OBLOCK: 3936 _actionNameLabel.setToolTipText(Bundle.getMessage("NameHintOBlock")); // NOI18N 3937 String oblockGrid = "NameTypeAction"; // NOI18N 3938 3939 for (Conditional.Action action : Conditional.Action.getOBlockItems()) { 3940 _actionTypeBox.addItem(action); 3941 } 3942 if (actionType == Conditional.Action.SET_BLOCK_VALUE) { 3943 _shortActionLabel.setText(Bundle.getMessage("LabelBlockValue")); // NOI18N 3944 _shortActionLabel.setToolTipText(Bundle.getMessage("DataHintBlockValue")); // NOI18N 3945 oblockGrid = "ShortFieldNoBoxAction"; // NOI18N 3946 } else if(actionType == Conditional.Action.GET_BLOCK_TRAIN_NAME 3947 || actionType == Conditional.Action.GET_BLOCK_WARRANT) { 3948 _shortActionLabel.setText(Bundle.getMessage("LabelMemoryLocation")); // NOI18N 3949 _shortActionLabel.setToolTipText(Bundle.getMessage("DataHintToMemory")); // NOI18N 3950 oblockGrid = "ShortFieldNoBoxAction"; // NOI18N 3951 } else { 3952 oblockGrid = "NameTypeActionFinal"; // NOI18N 3953 } 3954 3955 setActionNameBox(itemType); 3956 makeDetailGrid(oblockGrid); 3957 break; 3958 3959 case ENTRYEXIT: 3960 for (Conditional.Action action : Conditional.Action.getEntryExitItems()) { 3961 _actionTypeBox.addItem(action); 3962 } 3963 setActionNameBox(itemType); 3964 makeDetailGrid("NameTypeActionFinal"); 3965 break; 3966 3967 case AUDIO: 3968 _actionNameLabel.setToolTipText(Bundle.getMessage("NameHintOBlock")); // NOI18N 3969 String audioGrid = "TypeAction"; // NOI18N 3970 3971 for (Conditional.Action action : Conditional.Action.getAudioItems()) { 3972 _actionTypeBox.addItem(action); 3973 } 3974 3975 if (actionType == Conditional.Action.PLAY_SOUND) { 3976 audioGrid = "FileAction"; // NOI18N 3977 _shortActionLabel.setText(Bundle.getMessage("LabelSelectFile")); // NOI18N 3978 _actionSetButton.setToolTipText(Bundle.getMessage("SetHintSound")); // NOI18N 3979 } else if (actionType == Conditional.Action.CONTROL_AUDIO) { 3980 audioGrid = "StandardAction"; // NOI18N 3981 _actionNameLabel.setToolTipText(Bundle.getMessage("NameHintAudio")); // NOI18N 3982 _actionBoxLabel.setText(Bundle.getMessage("LabelActionAudio")); // NOI18N 3983 _actionBoxLabel.setToolTipText(Bundle.getMessage("SetHintAudio")); // NOI18N 3984 _actionBox.addItem(Bundle.getMessage("AudioSourcePlay")); // NOI18N 3985 _actionBox.addItem(Bundle.getMessage("AudioSourceStop")); // NOI18N 3986 _actionBox.addItem(Bundle.getMessage("AudioSourcePlayToggle")); // NOI18N 3987 _actionBox.addItem(Bundle.getMessage("AudioSourcePause")); // NOI18N 3988 _actionBox.addItem(Bundle.getMessage("AudioSourceResume")); // NOI18N 3989 _actionBox.addItem(Bundle.getMessage("AudioSourcePauseToggle")); // NOI18N 3990 _actionBox.addItem(Bundle.getMessage("AudioSourceRewind")); // NOI18N 3991 _actionBox.addItem(Bundle.getMessage("AudioSourceFadeIn")); // NOI18N 3992 _actionBox.addItem(Bundle.getMessage("AudioSourceFadeOut")); // NOI18N 3993 _actionBox.addItem(Bundle.getMessage("AudioResetPosition")); // NOI18N 3994 } 3995 3996 makeDetailGrid(audioGrid); 3997 break; 3998 3999 case SCRIPT: 4000 String scriptGrid = "TypeAction"; // NOI18N 4001 4002 for (Conditional.Action action : Conditional.Action.getScriptItems()) { 4003 _actionTypeBox.addItem(action); 4004 } 4005 4006 if (actionType == Conditional.Action.RUN_SCRIPT) { 4007 scriptGrid = "FileAction"; // NOI18N 4008 _shortActionLabel.setText(Bundle.getMessage("LabelSelectFile")); // NOI18N 4009 _actionSetButton.setToolTipText(Bundle.getMessage("SetHintScript")); // NOI18N 4010 } else if (actionType == Conditional.Action.JYTHON_COMMAND) { 4011 scriptGrid = "TypeShortAction"; // NOI18N 4012 _shortActionLabel.setText(Bundle.getMessage("LabelScriptCommand")); // NOI18N 4013 _shortActionLabel.setToolTipText(Bundle.getMessage("SetHintJythonCmd")); // NOI18N 4014 } 4015 4016 makeDetailGrid(scriptGrid); 4017 break; 4018 4019 case OTHER: 4020 String otherGrid = "TypeAction"; // NOI18N 4021 4022 for (Conditional.Action action : Conditional.Action.getOtherItems()) { 4023 _actionTypeBox.addItem(action); 4024 } 4025 4026 if (actionType == Conditional.Action.TRIGGER_ROUTE) { 4027 otherGrid = "NameTypeActionFinal"; // NOI18N 4028 _actionNameLabel.setToolTipText(Bundle.getMessage("NameHintRoute")); // NOI18N 4029 } 4030 4031 setActionNameBox(itemType); 4032 makeDetailGrid(otherGrid); 4033 break; 4034 4035 default: 4036 break; 4037 } 4038 _actionTypeListener.setItemType(itemType); 4039 _actionTypeBox.addActionListener(_actionTypeListener); 4040 } 4041 4042 /** 4043 * Update the name combo box selection based on the current contents of the 4044 * name field. 4045 * 4046 * @since 4.7.3 4047 * @param itemType The item type, such as sensor or turnout. 4048 */ 4049 void setActionNameBox(Conditional.ItemType itemType) { 4050 if (_selectionMode != SelectionMode.USECOMBO) { 4051 return; 4052 } 4053 _comboNameBox = createNameBox(itemType); 4054 if (_comboNameBox == null) { 4055 return; 4056 } 4057 // Select the current entry 4058 _comboNameBox.setSelectedItemByName(_curAction.getDeviceName()); 4059 _comboNameBox.addActionListener(new NameBoxListener(_actionNameField)); 4060 _comboNameBox.addFocusListener(detailFocusEvent); 4061 } 4062 4063 // ------------ Action detail methods ------------ 4064 4065 /** 4066 * Respond to Cancel action button and window closer of the Edit Action 4067 * window. 4068 * <p> 4069 * Also does cleanup of Update and Delete buttons. 4070 */ 4071 void cancelEditAction() { 4072 if (_newActionItem) { 4073 _newActionItem = false; 4074 deletePressed(); 4075 } 4076 cleanUpAction(); 4077 } 4078 4079 /** 4080 * Respond to Update button. 4081 */ 4082 void updateAction() { 4083 if (!validateAction()) { 4084 return; 4085 } 4086 _newActionItem = false; 4087 updateActionList(); 4088 4089 // Update the Action node 4090 _curNode.setText(_curAction.description(_triggerMode)); 4091 _cdlModel.nodeChanged(_curNode); 4092 cleanUpAction(); 4093 } 4094 4095 /** 4096 * Clean up Update and Delete Action buttons. 4097 */ 4098 void cleanUpAction() { 4099 setMoveButtons(); 4100 } 4101 4102 /*.* 4103 * Convert user setting in Conditional Action configuration pane to integer 4104 * for processing. 4105 * 4106 * @param itemType value for current item type 4107 * @param actionTypeSelection index of selected item in configuration 4108 * comboBox 4109 * @return integer representing the selected action 4110 */ 4111/* static Conditional.Action getActionTypeFromBox(Conditional.ItemType itemType, int actionTypeSelection) { 4112// if (itemType < 0 || actionTypeSelection < 0) { 4113// return Conditional.Action.NONE; 4114// } 4115 if (actionTypeSelection < 0) { 4116 return Conditional.Action.NONE; 4117 } 4118 switch (itemType) { 4119 case SENSOR: 4120 return Conditional.Action.getSensorItems().get(actionTypeSelection); 4121 case TURNOUT: 4122 return Conditional.Action.getTurnoutItems().get(actionTypeSelection); 4123 case LIGHT: 4124 return Conditional.Action.getLightItems().get(actionTypeSelection); 4125 case SIGNALHEAD: 4126 return Conditional.Action.getSignalHeadItems().get(actionTypeSelection); 4127 case SIGNALMAST: 4128 return Conditional.Action.getSignalMastItems().get(actionTypeSelection); 4129 case MEMORY: 4130 return Conditional.Action.getMemoryItems().get(actionTypeSelection); 4131 case LOGIX: 4132 return Conditional.Action.getLogixItems().get(actionTypeSelection); 4133 case WARRANT: 4134 return Conditional.Action.getWarrantItems().get(actionTypeSelection); 4135 case OBLOCK: 4136 return Conditional.Action.getOBlockItems().get(actionTypeSelection); 4137 case CLOCK: 4138 return Conditional.Action.getClockItems().get(actionTypeSelection); 4139 case AUDIO: 4140 return Conditional.Action.getAudioItems().get(actionTypeSelection); 4141 case SCRIPT: 4142 return Conditional.Action.getScriptItems().get(actionTypeSelection); 4143 case OTHER: 4144 return Conditional.Action.getOtherItems().get(actionTypeSelection); 4145 case ENTRYEXIT: 4146 return Conditional.Action.getEntryExitItems().get(actionTypeSelection); 4147 default: 4148 // fall through 4149 break; 4150 } 4151 return Conditional.Action.NONE; 4152 } 4153*/ 4154 JFileChooser sndFileChooser = null; 4155 ScriptFileChooser scriptFileChooser = null; 4156 JFileChooser defaultFileChooser = null; 4157 4158 /** 4159 * Respond to the [...] button in the Edit Action window action section. 4160 * <p> 4161 * Ask user to select an audio or python script file on disk. 4162 * 4163 * @param e the event heard 4164 */ 4165 void setFileLocation(ActionEvent e) { 4166 ConditionalAction action = _actionList.get(_curNodeRow); 4167 JFileChooser currentChooser; 4168 Conditional.Action actionType = action.getType(); 4169 if (actionType == Conditional.Action.PLAY_SOUND) { 4170 if (sndFileChooser == null) { 4171 sndFileChooser = new jmri.util.swing.JmriJFileChooser(System.getProperty("user.dir") // NOI18N 4172 + java.io.File.separator + "resources" // NOI18N 4173 + java.io.File.separator + "sounds"); // NOI18N 4174 sndFileChooser.setFileFilter(new FileNameExtensionFilter("wav sound files", "wav")); // NOI18N 4175 } 4176 currentChooser = sndFileChooser; 4177 } else if (actionType == Conditional.Action.RUN_SCRIPT) { 4178 if (scriptFileChooser == null) { 4179 scriptFileChooser = new ScriptFileChooser(FileUtil.getScriptsPath()); 4180 } 4181 currentChooser = scriptFileChooser; 4182 } else { 4183 log.warn("Unexpected actionType[{}] = {}", actionType.name(), actionType); // NOI18N 4184 if (defaultFileChooser == null) { 4185 defaultFileChooser = new jmri.util.swing.JmriJFileChooser(FileUtil.getUserFilesPath()); 4186 defaultFileChooser.setFileFilter(new jmri.util.NoArchiveFileFilter()); 4187 } 4188 currentChooser = defaultFileChooser; 4189 } 4190 4191 currentChooser.rescanCurrentDirectory(); 4192 int retVal = currentChooser.showOpenDialog(null); 4193 // handle selection or cancel 4194 if (retVal == JFileChooser.APPROVE_OPTION) { 4195 // set selected file location in data string 4196 try { 4197 _longActionString.setText(FileUtil.getPortableFilename(currentChooser.getSelectedFile().getCanonicalPath())); 4198 } catch (java.io.IOException ex) { 4199 if (log.isDebugEnabled()) { 4200 log.error("exception setting file location: ", ex); // NOI18N 4201 } 4202 _longActionString.setText(""); 4203 } 4204 } 4205 } 4206 4207 // ------------ Action update processes ------------ 4208 4209 /** 4210 * Validate Action data from Edit Action Window, and transfer it to current 4211 * action object as appropriate. 4212 * <p> 4213 * Messages are sent to the user for any errors found. This routine returns 4214 * false immediately after finding an error, even if there might be more 4215 * errors. 4216 * 4217 * @return true if all data checks out OK, otherwise false. 4218 */ 4219 boolean validateAction() { 4220 Conditional.ItemType itemType = _actionItemBox.getItemAt(_actionItemBox.getSelectedIndex()); 4221 Conditional.Action actionType = Conditional.Action.NONE; 4222 Conditional.Action selection = _actionTypeBox.getItemAt(_actionTypeBox.getSelectedIndex()); 4223 if (selection == Conditional.Action.NONE) { 4224 JmriJOptionPane.showMessageDialog( 4225 _editLogixFrame, Bundle.getMessage("makeSelection"), 4226 Bundle.getMessage("WarningTitle"), JmriJOptionPane.WARNING_MESSAGE); 4227 return false; 4228 } 4229 String name = _actionNameField.getText().trim(); 4230 String actionString = _shortActionString.getText().trim(); 4231 _curAction.setActionString(""); 4232 _curAction.setActionData(-1); 4233 boolean referenceByMemory = false; 4234 if (name.length() > 0 && name.charAt(0) == '@') { 4235 String memName = name.substring(1); 4236 if (!confirmIndirectMemory(memName)) { 4237 return false; 4238 } 4239 memName = validateMemoryReference(memName); 4240 if (memName == null) { 4241 return false; 4242 } 4243 referenceByMemory = true; 4244 } 4245 if (!checkIsVariable(name, itemType) ) { 4246 return false; 4247 } 4248 switch (itemType) { 4249 case SENSOR: 4250 if (!referenceByMemory) { 4251 name = validateSensorReference(name); 4252 if (name == null) { 4253 return false; 4254 } 4255 } 4256 actionType = selection; 4257 if ((actionType == Conditional.Action.RESET_DELAYED_SENSOR) 4258 || (actionType == Conditional.Action.DELAYED_SENSOR)) { 4259 if (!validateTimeReference(actionType, actionString)) { 4260 return (false); 4261 } 4262 _curAction.setActionString(actionString); 4263 } 4264 if ((actionType == Conditional.Action.SET_SENSOR) 4265 || (actionType == Conditional.Action.RESET_DELAYED_SENSOR) 4266 || (actionType == Conditional.Action.DELAYED_SENSOR)) { 4267 if (_actionBox.getSelectedIndex() == 0) { 4268 _curAction.setActionData(Sensor.ACTIVE); 4269 } else if (_actionBox.getSelectedIndex() == 1) { 4270 _curAction.setActionData(Sensor.INACTIVE); 4271 } else { 4272 _curAction.setActionData(Route.TOGGLE); 4273 } 4274 } 4275 _actionNameField.setText(name); 4276 _curAction.setDeviceName(name); 4277 break; 4278 case TURNOUT: 4279 if (!referenceByMemory) { 4280 name = validateTurnoutReference(name); 4281 if (name == null) { 4282 return false; 4283 } 4284 } 4285 actionType = selection; 4286 if ((actionType == Conditional.Action.RESET_DELAYED_TURNOUT) 4287 || (actionType == Conditional.Action.DELAYED_TURNOUT)) { 4288 if (!validateTimeReference(actionType, actionString)) { 4289 return (false); 4290 } 4291 _curAction.setActionString(actionString); 4292 } 4293 if ((actionType == Conditional.Action.SET_TURNOUT) 4294 || (actionType == Conditional.Action.RESET_DELAYED_TURNOUT) 4295 || (actionType == Conditional.Action.DELAYED_TURNOUT)) { 4296 if (_actionBox.getSelectedIndex() == 0) { 4297 _curAction.setActionData(Turnout.CLOSED); 4298 } else if (_actionBox.getSelectedIndex() == 1) { 4299 _curAction.setActionData(Turnout.THROWN); 4300 } else { 4301 _curAction.setActionData(Route.TOGGLE); 4302 } 4303 } else if (actionType == Conditional.Action.LOCK_TURNOUT) { 4304 if (_actionBox.getSelectedIndex() == 0) { 4305 _curAction.setActionData(Turnout.UNLOCKED); 4306 } else if (_actionBox.getSelectedIndex() == 1) { 4307 _curAction.setActionData(Turnout.LOCKED); 4308 } else { 4309 _curAction.setActionData(Route.TOGGLE); 4310 } 4311 } 4312 _actionNameField.setText(name); 4313 _curAction.setDeviceName(name); 4314 break; 4315 case LIGHT: 4316 if (!referenceByMemory) { 4317 name = validateLightReference(name); 4318 if (name == null) { 4319 return false; 4320 } 4321 } 4322 actionType = selection; 4323 if (actionType == Conditional.Action.SET_LIGHT_INTENSITY) { 4324 Light lgtx = getLight(name); 4325 // check if light user name was entered 4326 if (lgtx == null) { 4327 return false; 4328 } 4329 if (!(lgtx instanceof VariableLight)) { 4330 JmriJOptionPane.showMessageDialog(_editLogixFrame, 4331 Bundle.getMessage("Error45", name), // NOI18N 4332 Bundle.getMessage("ErrorTitle"), 4333 JmriJOptionPane.ERROR_MESSAGE); // NOI18N 4334 return (false); 4335 } 4336 if (!validateIntensityReference(actionType, actionString)) { 4337 return (false); 4338 } 4339 _curAction.setActionString(actionString); 4340 } else if (actionType == Conditional.Action.SET_LIGHT_TRANSITION_TIME) { 4341 Light lgtx = getLight(name); 4342 // check if light user name was entered 4343 if (lgtx == null) { 4344 return false; 4345 } 4346 if ( !(lgtx instanceof VariableLight) 4347 || !((VariableLight)lgtx).isTransitionAvailable()) { 4348 JmriJOptionPane.showMessageDialog(_editLogixFrame, 4349 Bundle.getMessage("Error40", name), // NOI18N 4350 Bundle.getMessage("ErrorTitle"), 4351 JmriJOptionPane.ERROR_MESSAGE); // NOI18N 4352 return (false); 4353 } 4354 if (!validateTimeReference(actionType, actionString)) { 4355 return (false); 4356 } 4357 _curAction.setActionString(actionString); 4358 } else if (actionType == Conditional.Action.SET_LIGHT) { 4359 if (_actionBox.getSelectedIndex() == 0) { 4360 _curAction.setActionData(Light.ON); 4361 } else if (_actionBox.getSelectedIndex() == 1) { 4362 _curAction.setActionData(Light.OFF); 4363 } else { 4364 _curAction.setActionData(Route.TOGGLE); 4365 } 4366 } 4367 _actionNameField.setText(name); 4368 _curAction.setDeviceName(name); 4369 break; 4370 case SIGNALHEAD: 4371 if (!referenceByMemory) { 4372 name = validateSignalHeadReference(name); 4373 if (name == null) { 4374 return false; 4375 } 4376 } 4377 actionType = selection; 4378 if (actionType == Conditional.Action.SET_SIGNAL_APPEARANCE) { 4379 String appStr = (String) _actionBox.getSelectedItem(); 4380 _curAction.setActionData(DefaultConditionalAction.stringToActionData(appStr)); 4381 _curAction.setActionString(appStr); 4382 } 4383 _actionNameField.setText(name); 4384 _curAction.setDeviceName(name); 4385 break; 4386 case SIGNALMAST: 4387 if (!referenceByMemory) { 4388 name = validateSignalMastReference(name); 4389 if (name == null) { 4390 return false; 4391 } 4392 } 4393 actionType = selection; 4394 if (actionType == Conditional.Action.SET_SIGNALMAST_ASPECT) { 4395 _curAction.setActionString((String) _actionBox.getSelectedItem()); 4396 } 4397 _actionNameField.setText(name); 4398 _curAction.setDeviceName(name); 4399 break; 4400 case MEMORY: 4401 if (referenceByMemory) { 4402 JmriJOptionPane.showMessageDialog(_editLogixFrame, Bundle.getMessage("Warn6"), Bundle.getMessage("WarningTitle"), // NOI18N 4403 JmriJOptionPane.WARNING_MESSAGE); 4404 return false; 4405 } 4406 name = validateMemoryReference(name); 4407 if (name == null) { 4408 return false; 4409 } 4410 actionType = selection; 4411 if (actionType == Conditional.Action.COPY_MEMORY) { 4412 actionString = validateMemoryReference(actionString); 4413 if (actionString == null) { 4414 return false; 4415 } 4416 } 4417 _actionNameField.setText(name); 4418 _curAction.setDeviceName(name); 4419 _curAction.setActionString(actionString); 4420 break; 4421 case LOGIX: 4422 if (!referenceByMemory) { 4423 name = validateLogixReference(name); 4424 if (name == null) { 4425 return false; 4426 } 4427 } 4428 actionType = selection; 4429 _actionNameField.setText(name); 4430 _curAction.setDeviceName(name); 4431 break; 4432 case WARRANT: 4433 if (!referenceByMemory) { 4434 name = validateWarrantReference(name); 4435 if (name == null) { 4436 return false; 4437 } 4438 } 4439 actionType = selection; 4440 _actionNameField.setText(name); 4441 _curAction.setDeviceName(name); 4442 if (actionType == Conditional.Action.CONTROL_TRAIN) { 4443 switch (_actionBox.getSelectedIndex()) { 4444 case 0: 4445 _curAction.setActionData(Warrant.HALT); 4446 break; 4447 case 1: 4448 _curAction.setActionData(Warrant.RESUME); 4449 break; 4450 case 2: 4451 _curAction.setActionData(Warrant.RETRY_FWD); 4452 break; 4453 case 3: 4454 _curAction.setActionData(Warrant.SPEED_UP); 4455 break; 4456 case 4: 4457 _curAction.setActionData(Warrant.STOP); 4458 break; 4459 case 5: 4460 _curAction.setActionData(Warrant.ESTOP); 4461 break; 4462 case 6: 4463 _curAction.setActionData(Warrant.ABORT); 4464 break; 4465 default: 4466 log.warn("Unexpected _actionBox.getSelectedIndex() of {}", _actionBox.getSelectedIndex()); // NOI18N 4467 break; 4468 } 4469 } else if (actionType == Conditional.Action.SET_TRAIN_ID 4470 || actionType == Conditional.Action.SET_TRAIN_NAME 4471 || actionType == Conditional.Action.GET_TRAIN_LOCATION) { 4472 _curAction.setActionString(actionString); 4473 } 4474 break; 4475 case OBLOCK: 4476 if (!referenceByMemory) { 4477 name = validateOBlockReference(name); 4478 if (name == null) { 4479 return false; 4480 } 4481 } 4482 actionType = selection; 4483 _actionNameField.setText(name); 4484 _curAction.setDeviceName(name); 4485 if (actionType == Conditional.Action.SET_BLOCK_VALUE 4486 || actionType == Conditional.Action.SET_TRAIN_NAME 4487 || actionType == Conditional.Action.GET_TRAIN_LOCATION) { 4488 _curAction.setActionString(actionString); 4489 } 4490 break; 4491 case ENTRYEXIT: 4492 if (!referenceByMemory) { 4493 name = validateEntryExitReference(name); 4494 if (name == null) { 4495 return false; 4496 } 4497 } 4498 actionType = selection; 4499 _actionNameField.setText(name); 4500 _curAction.setDeviceName(name); 4501 break; 4502 case CLOCK: 4503 actionType = selection; 4504 if (actionType == Conditional.Action.SET_FAST_CLOCK_TIME) { 4505 int time = parseTime(_shortActionString.getText().trim()); 4506 if (time < 0) { 4507 return (false); 4508 } 4509 _curAction.setActionData(time); 4510 } 4511 break; 4512 case AUDIO: 4513 actionType = selection; 4514 if (actionType == Conditional.Action.PLAY_SOUND) { 4515 _curAction.setActionString(_longActionString.getText().trim()); 4516 } else if (actionType == Conditional.Action.CONTROL_AUDIO) { 4517 if (!referenceByMemory) { 4518 name = validateAudioReference(name); 4519 if (name == null) { 4520 return false; 4521 } 4522 } 4523 _actionNameField.setText(name); 4524 _curAction.setDeviceName(name); 4525 switch (_actionBox.getSelectedIndex()) { 4526 case 0: 4527 _curAction.setActionData(Audio.CMD_PLAY); 4528 break; 4529 case 1: 4530 _curAction.setActionData(Audio.CMD_STOP); 4531 break; 4532 case 2: 4533 _curAction.setActionData(Audio.CMD_PLAY_TOGGLE); 4534 break; 4535 case 3: 4536 _curAction.setActionData(Audio.CMD_PAUSE); 4537 break; 4538 case 4: 4539 _curAction.setActionData(Audio.CMD_RESUME); 4540 break; 4541 case 5: 4542 _curAction.setActionData(Audio.CMD_PAUSE_TOGGLE); 4543 break; 4544 case 6: 4545 _curAction.setActionData(Audio.CMD_REWIND); 4546 break; 4547 case 7: 4548 _curAction.setActionData(Audio.CMD_FADE_IN); 4549 break; 4550 case 8: 4551 _curAction.setActionData(Audio.CMD_FADE_OUT); 4552 break; 4553 case 9: 4554 _curAction.setActionData(Audio.CMD_RESET_POSITION); 4555 break; 4556 default: 4557 log.warn("Unexpected _actionBox.getSelectedIndex() of {}", _actionBox.getSelectedIndex()); // NOI18N 4558 break; 4559 } 4560 } 4561 break; 4562 case SCRIPT: 4563 actionType = selection; 4564 if (actionType == Conditional.Action.RUN_SCRIPT) { 4565 _curAction.setActionString(_longActionString.getText().trim()); 4566 } else if (actionType == Conditional.Action.JYTHON_COMMAND) { 4567 _curAction.setActionString(_shortActionString.getText().trim()); 4568 } 4569 break; 4570 case OTHER: 4571 actionType = selection; 4572 if (actionType == Conditional.Action.TRIGGER_ROUTE) { 4573 if (!referenceByMemory) { 4574 name = validateRouteReference(name); 4575 if (name == null) { 4576 return false; 4577 } 4578 } 4579 _actionNameField.setText(name); 4580 _curAction.setDeviceName(name); 4581 } 4582 break; 4583 default: 4584 break; 4585 } 4586 _curAction.setType(actionType); 4587 if (actionType != Conditional.Action.NONE) { 4588 _curAction.setOption(_actionOptionBox.getSelectedIndex() + 1); 4589 } else { 4590 _curAction.setOption(0); 4591 } 4592 return (true); 4593 } 4594 4595 /** 4596 * Update the conditional action list and refresh the local copy. 4597 * The parent Logix is de-activated and re-activated. This ensures 4598 * that listeners are properly handled, specifically the delayed sensor 4599 * and turnout options. 4600 * @since 4.11.2 4601 */ 4602 void updateActionList() { 4603 _curLogix.deActivateLogix(); 4604 _curConditional.setAction(_actionList); 4605 _actionList = _curConditional.getCopyOfActions(); 4606 _curLogix.activateLogix(); 4607 } 4608 4609 /** 4610 * Check that a state variable is not also used as an action 4611 * 4612 * @param name of the state variable 4613 * @param itemType item type of the state variable 4614 * @return true if variable is not an action of if the user OK's 4615 * its use as an action also. 4616 */ 4617 boolean checkIsAction(String name, Conditional.ItemType itemType) { 4618 String actionName = null; 4619 for (ConditionalAction action : _actionList) { 4620 Conditional.ItemType actionType = action.getType().getItemType(); 4621 if (itemType == actionType) { 4622 if (name.equals(action.getDeviceName())) { 4623 actionName = action.getDeviceName(); 4624 } else { 4625 NamedBean bean = action.getBean(); 4626 if (bean != null && 4627 (name.equals(bean.getSystemName()) || 4628 name.equals(bean.getUserName()))) { 4629 actionName = action.getDeviceName(); 4630 } 4631 } 4632 } 4633 if (actionName != null) { 4634 return confirmActionAsVariable(actionName, name); 4635 } 4636 } 4637 return true; 4638 } 4639 4640 /** 4641 * Check that an action is not also used as a state variable 4642 * 4643 * @param name of the action 4644 * @param itemType item type of the action 4645 * @return true if action is not a state variable of if the user OK's 4646 * its use as such. 4647 */ 4648 boolean checkIsVariable(String name, Conditional.ItemType itemType) { 4649 String varName = null; 4650 for (ConditionalVariable var : _variableList) { 4651 Conditional.ItemType varType = var.getType().getItemType(); 4652 if (itemType == varType) { 4653 if (name.equals(var.getName())) { 4654 varName = var.getName(); 4655 } else { 4656 NamedBean bean = var.getBean(); 4657 if (bean != null && 4658 (name.equals(bean.getSystemName()) || 4659 name.equals(bean.getUserName()))) { 4660 varName = var.getName(); 4661 } 4662 } 4663 } 4664 if (varName != null) { 4665 return confirmActionAsVariable(name, varName); 4666 } 4667 } 4668 return true; 4669 } 4670 4671 // ------------ Action detail listeners ------------ 4672 4673 /** 4674 * Listener for _actionTypeBox. 4675 */ 4676 class ActionTypeListener implements ActionListener { 4677 4678 Conditional.ItemType _itemType; 4679 4680 @Override 4681 public void actionPerformed(ActionEvent e) { 4682 Conditional.ItemType select1 = _actionItemBox.getItemAt(_actionItemBox.getSelectedIndex()); 4683 Conditional.Action select2 = _actionTypeBox.getItemAt(_actionTypeBox.getSelectedIndex()); 4684 if (log.isDebugEnabled()) { 4685 log.debug("ActionTypeListener: itemType = {}, local itemType = {}, actionType = {}", // NOI18N 4686 select1, _itemType, select2); 4687 } 4688 if (select1 != _itemType) { 4689 log.error("ActionTypeListener actionItem selection ({}) != expected actionItem ({})", // NOI18N 4690 select1, _itemType); 4691 } 4692 if (_curAction != null) { 4693 if (select1 != Conditional.ItemType.NONE && _itemType == select1) { 4694 _curAction.setType(select2); 4695 if (select1 == _itemType) { 4696 String text = _actionNameField.getText(); 4697 if (text != null && text.length() > 0) { 4698 _curAction.setDeviceName(text); 4699 } 4700 } 4701 actionItemChanged(_itemType); 4702 initializeActionVariables(); 4703 } 4704 } 4705 } 4706 4707 public void setItemType(Conditional.ItemType type) { 4708 _itemType = type; 4709 } 4710 } 4711 4712 ActionTypeListener _actionTypeListener = new ActionTypeListener(); 4713 4714 transient ActionListener actionSignalHeadNameListener = new ActionListener() { 4715 @Override 4716 public void actionPerformed(ActionEvent e) { 4717 // fired when signal head name changes, but only 4718 // while in signal head mode 4719 log.debug("actionSignalHeadNameListener fires; _actionNameField : {}", _actionNameField.getText().trim()); // NOI18N 4720 loadJComboBoxWithHeadAppearances(_actionBox, _actionNameField.getText().trim()); 4721 } 4722 }; 4723 4724 transient ActionListener actionSignalMastNameListener = new ActionListener() { 4725 @Override 4726 public void actionPerformed(ActionEvent e) { 4727 // fired when signal mast name changes, but only 4728 // while in signal mast mode 4729 log.debug("actionSignalMastNameListener fires; _actionNameField : {}", _actionNameField.getText().trim()); // NOI18N 4730 loadJComboBoxWithMastAspects(_actionBox, _actionNameField.getText().trim()); 4731 } 4732 }; 4733 4734 /** 4735 * Conditional Tree Node Definition. 4736 */ 4737 static class ConditionalTreeNode extends DefaultMutableTreeNode { 4738 4739 private String cdlText; 4740 private String cdlType; 4741 private String cdlName; 4742 private int cdlRow; 4743 4744 public ConditionalTreeNode(String nameText, String type, String sysName, int row) { 4745 this.cdlText = nameText; 4746 this.cdlType = type; 4747 this.cdlName = sysName; 4748 this.cdlRow = row; 4749 } 4750 4751 public String getType() { 4752 return cdlType; 4753 } 4754 4755 public String getName() { 4756 return cdlName; 4757 } 4758 4759 public void setName(String newName) { 4760 cdlName = newName; 4761 } 4762 4763 public int getRow() { 4764 return cdlRow; 4765 } 4766 4767 public void setRow(int newRow) { 4768 cdlRow = newRow; 4769 } 4770 4771 public String getText() { 4772 return cdlText; 4773 } 4774 4775 public void setText(String newText) { 4776 cdlText = newText; 4777 } 4778 4779 @Override 4780 public String toString() { 4781 return cdlText; 4782 } 4783 } 4784 4785 @Override 4786 protected String getClassName() { 4787 return ConditionalTreeEdit.class.getName(); 4788 } 4789 4790 private static final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(ConditionalTreeEdit.class); 4791 4792}