001package jmri.jmrit.conditional;
002
003import java.awt.Container;
004import java.awt.Dimension;
005import java.awt.FlowLayout;
006import java.awt.Font;
007import java.awt.event.ActionEvent;
008import java.awt.event.ActionListener;
009import java.util.ArrayList;
010import java.util.TreeMap;
011
012import javax.swing.*;
013import javax.swing.border.Border;
014import javax.swing.filechooser.FileNameExtensionFilter;
015import javax.swing.table.*;
016
017import jmri.*;
018import jmri.Conditional.Operator;
019import jmri.Conditional.State;
020import jmri.implementation.DefaultConditionalAction;
021import jmri.jmrit.beantable.LRouteTableAction;
022import jmri.jmrit.conditional.ConditionalEditBase.NameBoxListener;
023import jmri.jmrit.conditional.ConditionalEditBase.SelectionMode;
024import jmri.jmrit.logix.OBlock;
025import jmri.jmrit.logix.Warrant;
026import jmri.script.swing.ScriptFileChooser;
027import jmri.swing.NamedBeanComboBox;
028import jmri.util.FileUtil;
029import jmri.util.JmriJFrame;
030import jmri.util.swing.JComboBoxUtil;
031import jmri.util.swing.JmriJOptionPane;
032import jmri.util.table.ButtonEditor;
033import jmri.util.table.ButtonRenderer;
034
035/**
036 * Extracted from ConditionalEditList.
037 * Allows ConditionalEditList to open alternate frame
038 * for copying Conditionals.
039 *
040 * @author Pete Cressman Copyright (C) 2020
041 */
042public class ConditionalEditFrame extends ConditionalFrame {
043
044    // ------------ Edit Conditional Variables ------------
045    JRadioButton _triggerOnChangeButton;
046    boolean _inActReorder = false;
047    boolean _inVarReorder = false;
048    int _nextInOrder = 0;
049
050    // ------------ Select Logix/Conditional Variables ------------
051    JPanel _selectLogixPanel = null;
052    JPanel _selectConditionalPanel = null;
053
054    ActionTableModel _actionTableModel = null;
055    VariableTableModel _variableTableModel = null;
056    JComboBox<Conditional.AntecedentOperator> _operatorBox;
057    JComboBox<String> _andOperatorBox;
058    JComboBox<String> _notOperatorBox;
059    JTextField _antecedentField;
060    JPanel _antecedentPanel;
061    boolean _newItem = false; // marks a new Action or Variable object was added
062
063    // ------------ Components of Edit Variable panes ------------
064    JmriJFrame _editVariableFrame = null;
065    JComboBox<Conditional.ItemType> _variableItemBox;
066    JComboBox<Conditional.Type> _variableStateBox;
067    JTextField _variableNameField;
068    JComboBox<String> _variableCompareOpBox;
069    JComboBox<String> _variableSignalBox;
070    JComboBox<Conditional.Type> _variableCompareTypeBox;
071    JTextField _variableData1Field;
072    JTextField _variableData2Field;
073    JButton _reorderVarButton;
074    JPanel _variableNamePanel;
075    JPanel _variableStatePanel;
076    JPanel _variableComparePanel;
077    JPanel _variableSignalPanel;
078    JPanel _variableData1Panel;
079    JPanel _variableData2Panel;
080    JPanel _variableComboNamePanel;
081
082    // ------------ Components of Edit Action panes ------------
083    JmriJFrame _editActionFrame = null;
084    JComboBox<Conditional.ItemType> _actionItemBox;
085    JComboBox<Conditional.Action> _actionTypeBox;
086    JComboBox<String> _actionBox;
087    JTextField _actionNameField;
088    JTextField _longActionString;
089    JTextField _shortActionString;
090    JComboBox<String> _actionOptionBox;
091    JPanel _actionPanel;
092    JPanel _actionTypePanel;
093    JPanel _actionNamePanel;
094    JPanel _shortTextPanel;
095    JPanel _optionPanel;
096    JPanel _actionComboNamePanel;
097
098    JPanel _setPanel;
099    JPanel _textPanel;
100    NamedBeanComboBox<?> _comboNameBox = null;
101
102    // ------------ Current Variable Information ------------
103    ConditionalVariable _curVariable;
104    int _curVariableRowNumber;
105    Conditional.ItemType _curVariableItem = Conditional.ItemType.NONE;
106
107    // ------------ Current Action Information ------------
108    ConditionalAction _curAction;
109    int _curActionRowNumber;
110    Conditional.ItemType _curActionItem = Conditional.ItemType.NONE;
111
112    // ------------ Components of Logix and SConditional selection ------------
113    JComboBox<String> _selectLogixBox = new JComboBox<>();
114    JComboBox<String> _selectConditionalBox = new JComboBox<>();
115    TreeMap<String, String> _selectLogixMap = new TreeMap<>();
116    ArrayList<String> _selectConditionalList = new ArrayList<>();
117
118    // ------------------------------------------------------------------
119
120    ConditionalEditFrame(String title, Conditional conditional, ConditionalList parent) {
121        super(title, conditional, parent);
122        makeConditionalFrame(conditional);
123    }
124
125    void makeConditionalFrame(Conditional conditional) {
126        addHelpMenu(
127                "package.jmri.jmrit.conditional.ConditionalListEditor", true);  // NOI18N
128        Container contentPane = getContentPane();
129        contentPane.setLayout(new BoxLayout(contentPane, BoxLayout.Y_AXIS));
130        contentPane.add(makeTopPanel(conditional));
131
132        // add Logical Expression Section
133        JPanel logicPanel = new JPanel();
134        logicPanel.setLayout(new BoxLayout(logicPanel, BoxLayout.Y_AXIS));
135
136        // add Antecedent Expression Panel - ONLY appears for MIXED operator statements
137        _antecedentField = new JTextField(65);
138        _antecedentField.setText(ConditionalEditBase.translateAntecedent(_antecedent, false));
139        _antecedentField.setFont(new Font("SansSerif", Font.BOLD, 14));  // NOI18N
140        _antecedentPanel = makeEditPanel(_antecedentField, "LabelAntecedent", "LabelAntecedentHint");  // NOI18N
141
142        JButton helpButton = new JButton(Bundle.getMessage("MenuHelp"));  // NOI18N
143        _antecedentPanel.add(helpButton);
144        helpButton.addActionListener(new ActionListener() {
145            @Override
146            public void actionPerformed(ActionEvent e) {
147                helpPressed(e);
148            }
149        });
150        _antecedentPanel.add(helpButton);
151        _antecedentPanel.setVisible(_logicType == Conditional.AntecedentOperator.MIXED);
152        logicPanel.add(_antecedentPanel);
153
154        // add state variable table title
155        JPanel varTitle = new JPanel();
156        varTitle.setLayout(new FlowLayout());
157        varTitle.add(new JLabel(Bundle.getMessage("StateVariableTableTitle")));  // NOI18N
158        logicPanel.add(varTitle);
159        // set up state variables table
160        // initialize and populate Combo boxes for table of state variables
161        _notOperatorBox = new JComboBox<String>();
162        _notOperatorBox.addItem(" ");
163        _notOperatorBox.addItem(Bundle.getMessage("LogicNOT"));  // NOI18N
164
165        _andOperatorBox = new JComboBox<String>();
166        _andOperatorBox.addItem(Bundle.getMessage("LogicAND"));  // NOI18N
167        _andOperatorBox.addItem(Bundle.getMessage("LogicOR"));   // NOI18N
168        // initialize table of state variables
169        _variableTableModel = new VariableTableModel();
170        JTable variableTable = new JTable(_variableTableModel);
171        variableTable.setRowHeight(_notOperatorBox.getPreferredSize().height);
172        variableTable.setRowSelectionAllowed(false);
173        int rowHeight = variableTable.getRowHeight();
174
175        TableColumnModel variableColumnModel = variableTable.getColumnModel();
176
177        TableColumn rowColumn = variableColumnModel.getColumn(VariableTableModel.ROWNUM_COLUMN);
178        rowColumn.setResizable(false);
179        rowColumn.setMaxWidth(new JTextField(3).getPreferredSize().width);
180
181        TableColumn andColumn = variableColumnModel.getColumn(VariableTableModel.AND_COLUMN);
182        andColumn.setResizable(false);
183        andColumn.setCellEditor(new DefaultCellEditor(_andOperatorBox));
184        andColumn.setMaxWidth(_andOperatorBox.getPreferredSize().width - 5);
185
186        TableColumn notColumn = variableColumnModel.getColumn(VariableTableModel.NOT_COLUMN);
187        notColumn.setCellEditor(new DefaultCellEditor(_notOperatorBox));
188        notColumn.setMaxWidth(_notOperatorBox.getPreferredSize().width - 5);
189        notColumn.setResizable(false);
190
191        TableColumn descColumn = variableColumnModel.getColumn(VariableTableModel.DESCRIPTION_COLUMN);
192        descColumn.setMinWidth(200);
193        descColumn.setResizable(true);
194
195        TableColumn stateColumn = variableColumnModel.getColumn(VariableTableModel.STATE_COLUMN);
196        stateColumn.setResizable(true);
197        stateColumn.setMinWidth(50);
198        stateColumn.setMaxWidth(80);
199
200        TableColumn triggerColumn = variableColumnModel.getColumn(VariableTableModel.TRIGGERS_COLUMN);
201        triggerColumn.setResizable(true);
202        triggerColumn.setMinWidth(30);
203        triggerColumn.setMaxWidth(80);
204
205        TableColumn editColumn = variableColumnModel.getColumn(VariableTableModel.EDIT_COLUMN);
206        ButtonRenderer buttonRenderer = new ButtonRenderer();
207        variableTable.setDefaultRenderer(JButton.class, buttonRenderer);
208        TableCellEditor buttonEditor = new ButtonEditor(new JButton());
209        variableTable.setDefaultEditor(JButton.class, buttonEditor);
210        JButton testButton = new JButton("XXXXXX");  // NOI18N
211        variableTable.setRowHeight(testButton.getPreferredSize().height);
212        editColumn.setMinWidth(testButton.getPreferredSize().width);
213        editColumn.setMaxWidth(testButton.getPreferredSize().width);
214        editColumn.setResizable(false);
215
216        TableColumn deleteColumn = variableColumnModel.getColumn(VariableTableModel.DELETE_COLUMN);
217        // ButtonRenderer and TableCellEditor already set
218        deleteColumn.setMinWidth(testButton.getPreferredSize().width);
219        deleteColumn.setMaxWidth(testButton.getPreferredSize().width);
220        deleteColumn.setResizable(false);
221        // add a scroll pane
222        JScrollPane variableTableScrollPane = new JScrollPane(variableTable);
223        Dimension dim = variableTable.getPreferredSize();
224        dim.height = 7 * rowHeight;
225        variableTableScrollPane.getViewport().setPreferredSize(dim);
226
227        logicPanel.add(variableTableScrollPane);
228
229        // set up state variable buttons and logic
230        JPanel panel42 = new JPanel();
231        panel42.setLayout(new FlowLayout());
232
233        //  Add State Variable
234        JButton addVariableButton = new JButton(Bundle.getMessage("AddVariableButton"));  // NOI18N
235        panel42.add(addVariableButton);
236        addVariableButton.addActionListener(new ActionListener() {
237            @Override
238            public void actionPerformed(ActionEvent e) {
239                addVariablePressed(e);
240            }
241        });
242        addVariableButton.setToolTipText(Bundle.getMessage("AddVariableButtonHint"));  // NOI18N
243
244        JButton checkVariableButton = new JButton(Bundle.getMessage("CheckVariableButton"));  // NOI18N
245        panel42.add(checkVariableButton);
246        checkVariableButton.addActionListener(new ActionListener() {
247            @Override
248            public void actionPerformed(ActionEvent e) {
249                checkVariablePressed(e);
250            }
251        });
252        checkVariableButton.setToolTipText(Bundle.getMessage("CheckVariableButtonHint"));  // NOI18N
253
254        //  - Reorder variable button
255        _reorderVarButton = new JButton(Bundle.getMessage("ReorderButton"));  // NOI18N
256        panel42.add(_reorderVarButton);
257        _reorderVarButton.addActionListener(new ActionListener() {
258            @Override
259            public void actionPerformed(ActionEvent e) {
260                reorderVariablePressed(e);
261            }
262        });
263        _reorderVarButton.setToolTipText(Bundle.getMessage("ReorderButtonHint"));  // NOI18N
264        _reorderVarButton.setEnabled(!(_logicType == Conditional.AntecedentOperator.MIXED));
265        logicPanel.add(panel42);
266
267        // logic type area
268        _operatorBox = new JComboBox<>();
269        for (Conditional.AntecedentOperator operator : Conditional.AntecedentOperator.values()) {
270            _operatorBox.addItem(operator);
271        }
272        JPanel typePanel = makeEditPanel(_operatorBox, "LabelLogicType", "TypeLogicHint");  // NOI18N
273        _operatorBox.setSelectedItem(_logicType);
274        _operatorBox.addActionListener(new ActionListener() {
275            @Override
276            public void actionPerformed(ActionEvent e) {
277                logicTypeChanged(e);
278                _dataChanged = true;
279            }
280        });
281        logicPanel.add(typePanel);
282        logicPanel.add(Box.createHorizontalStrut(STRUT));
283
284        Border logicPanelBorder = BorderFactory.createEtchedBorder();
285        Border logicPanelTitled = BorderFactory.createTitledBorder(
286                logicPanelBorder, Bundle.getMessage("TitleLogicalExpression") + " ");  // NOI18N
287        logicPanel.setBorder(logicPanelTitled);
288        contentPane.add(logicPanel);
289        // End of Logic Expression Section
290
291        JPanel triggerPanel = new JPanel();
292        triggerPanel.setLayout(new BoxLayout(triggerPanel, BoxLayout.Y_AXIS));
293        ButtonGroup tGroup = new ButtonGroup();
294        _triggerOnChangeButton = new JRadioButton(Bundle.getMessage("triggerOnChange"));  // NOI18N
295        _triggerOnChangeButton.addActionListener(new ActionListener() {
296            @Override
297            public void actionPerformed(ActionEvent e) {
298                _actionTableModel.fireTableDataChanged();
299                _dataChanged = true;
300            }
301        });
302        tGroup.add(_triggerOnChangeButton);
303        triggerPanel.add(_triggerOnChangeButton);
304        JRadioButton triggerOnAny = new JRadioButton(Bundle.getMessage("triggerOnAny"));  // NOI18N
305        triggerOnAny.addActionListener(new ActionListener() {
306            @Override
307            public void actionPerformed(ActionEvent e) {
308                _actionTableModel.fireTableDataChanged();
309                _dataChanged = true;
310            }
311        });
312        tGroup.add(triggerOnAny);
313        triggerPanel.add(triggerOnAny);
314        triggerOnAny.setSelected(true);
315        JPanel trigPanel = new JPanel();
316        trigPanel.add(triggerPanel);
317        contentPane.add(trigPanel);
318        _triggerOnChangeButton.setSelected(conditional.getTriggerOnChange());
319
320        // add Action Consequents Section
321        JPanel conseqentPanel = new JPanel();
322        conseqentPanel.setLayout(new BoxLayout(conseqentPanel, BoxLayout.Y_AXIS));
323
324        JPanel actTitle = new JPanel();
325        actTitle.setLayout(new FlowLayout());
326        actTitle.add(new JLabel(Bundle.getMessage("ActionTableTitle")));  // NOI18N
327        conseqentPanel.add(actTitle);
328
329        // set up action consequents table
330        _actionTableModel = new ActionTableModel();
331        JTable actionTable = new JTable(_actionTableModel);
332        actionTable.setRowSelectionAllowed(false);
333        actionTable.setRowHeight(testButton.getPreferredSize().height);
334        JPanel actionPanel = new JPanel();
335        actionPanel.setLayout(new BoxLayout(actionPanel, BoxLayout.Y_AXIS));
336        JPanel actionTitle = new JPanel();
337        actionTitle.setLayout(new FlowLayout());
338        conseqentPanel.add(actionPanel);
339
340        TableColumnModel actionColumnModel = actionTable.getColumnModel();
341
342        TableColumn descriptionColumn = actionColumnModel.getColumn(
343                ActionTableModel.DESCRIPTION_COLUMN);
344        descriptionColumn.setResizable(true);
345        descriptionColumn.setMinWidth(300);
346
347        TableColumn actionEditColumn = actionColumnModel.getColumn(ActionTableModel.EDIT_COLUMN);
348        // ButtonRenderer already exists
349        actionTable.setDefaultRenderer(JButton.class, buttonRenderer);
350        TableCellEditor editButEditor = new ButtonEditor(new JButton());
351        actionTable.setDefaultEditor(JButton.class, editButEditor);
352        actionEditColumn.setMinWidth(testButton.getPreferredSize().width);
353        actionEditColumn.setMaxWidth(testButton.getPreferredSize().width);
354        actionEditColumn.setResizable(false);
355
356        TableColumn actionDeleteColumn = actionColumnModel.getColumn(ActionTableModel.DELETE_COLUMN);
357        // ButtonRenderer and TableCellEditor already set
358        actionDeleteColumn.setMinWidth(testButton.getPreferredSize().width);
359        actionDeleteColumn.setMaxWidth(testButton.getPreferredSize().width);
360        actionDeleteColumn.setResizable(false);
361        // add a scroll pane
362        JScrollPane actionTableScrollPane = new JScrollPane(actionTable);
363        dim = actionTableScrollPane.getPreferredSize();
364        dim.height = 7 * rowHeight;
365        actionTableScrollPane.getViewport().setPreferredSize(dim);
366        conseqentPanel.add(actionTableScrollPane);
367
368        // add action buttons to Action Section
369        JPanel panel43 = new JPanel();
370        panel43.setLayout(new FlowLayout());
371        JButton addActionButton = new JButton(Bundle.getMessage("addActionButton"));  // NOI18N
372        panel43.add(addActionButton);
373        addActionButton.addActionListener(new ActionListener() {
374            @Override
375            public void actionPerformed(ActionEvent e) {
376                addActionPressed(e);
377            }
378        });
379
380        addActionButton.setToolTipText(Bundle.getMessage("addActionButtonHint"));  // NOI18N
381        conseqentPanel.add(panel43);
382
383        //  - Reorder action button
384        JButton reorderButton = new JButton(Bundle.getMessage("ReorderButton"));  // NOI18N
385        panel43.add(reorderButton);
386        reorderButton.addActionListener(new ActionListener() {
387            @Override
388            public void actionPerformed(ActionEvent e) {
389                reorderActionPressed(e);
390            }
391        });
392        reorderButton.setToolTipText(Bundle.getMessage("ReorderButtonHint"));  // NOI18N
393        conseqentPanel.add(panel43);
394
395        Border conseqentPanelBorder = BorderFactory.createEtchedBorder();
396        Border conseqentPanelTitled = BorderFactory.createTitledBorder(
397                conseqentPanelBorder, Bundle.getMessage("TitleAction"));  // NOI18N
398        conseqentPanel.setBorder(conseqentPanelTitled);
399        contentPane.add(conseqentPanel);
400        // End of Action Consequents Section
401
402        contentPane.add(_parent.makeBottomPanel());
403
404        // setup window closing listener
405        this.addWindowListener(
406                new java.awt.event.WindowAdapter() {
407            @Override
408            public void windowClosing(java.awt.event.WindowEvent e) {
409                cancelConditionalPressed();
410            }
411        });
412        // initialize state variable table
413        _variableTableModel.fireTableDataChanged();
414        // initialize action variables
415        _actionTableModel.fireTableDataChanged();
416        checkVariablePressed(null); // update variables to their current states
417    }   // end makeConditionalFrame
418
419
420    // ============ Edit Conditional Window and Methods ============
421
422    /**
423     * Respond to the Add State Variable Button in the Edit Conditional window.
424     *
425     * @param e The event heard
426     */
427    void addVariablePressed(ActionEvent e) {
428        if (alreadyEditingActionOrVariable()) {
429            return;
430        }
431        _curVariableItem = Conditional.ItemType.NONE;
432        ConditionalVariable variable = new ConditionalVariable();
433        _variableList.add(variable);
434        _newItem = true;
435        int size = _variableList.size();
436        // default of operator for postion 0 (row 1) is Conditional.OPERATOR_NONE
437        if (size > 1) {
438            if (_logicType == Conditional.AntecedentOperator.ALL_OR) {
439                variable.setOpern(Conditional.Operator.OR);
440            } else {
441                variable.setOpern(Conditional.Operator.AND);
442            }
443        }
444        size--;
445        _variableTableModel.fireTableRowsInserted(size, size);
446        makeEditVariableWindow(size);
447        appendToAntecedent();
448    }
449
450    /**
451     * Respond to the Check State Variable Button in the Edit Conditional
452     * window.
453     *
454     * @param e the event heard
455     */
456    void checkVariablePressed(ActionEvent e) {
457        for (int i = 0; i < _variableList.size(); i++) {
458            _variableList.get(i).evaluate();
459        }
460        _variableTableModel.fireTableDataChanged();
461    }
462
463    /**
464     * Respond to the Reorder Variable Button in the Edit Conditional window.
465     *
466     * @param e The event heard
467     */
468    void reorderVariablePressed(ActionEvent e) {
469        if (alreadyEditingActionOrVariable()) {
470            return;
471        }
472        // Check if reorder is reasonable
473        if (_variableList.size() <= 1) {
474            JmriJOptionPane.showMessageDialog(this,
475                    Bundle.getMessage("Error51"),
476                    Bundle.getMessage("ErrorTitle"), // NOI18N
477                    JmriJOptionPane.ERROR_MESSAGE);
478            return;
479        }
480        _nextInOrder = 0;
481        _inVarReorder = true;
482        _variableTableModel.fireTableDataChanged();
483        _dataChanged = true;
484    }
485
486    /**
487     * Respond to the First/Next (Delete) Button in the Edit Conditional window.
488     *
489     * @param row index of the row to put as next in line (instead of the one
490     *            that was supposed to be next)
491     */
492    void swapVariables(int row) {
493        ConditionalVariable temp = _variableList.get(row);
494        for (int i = row; i > _nextInOrder; i--) {
495            _variableList.set(i, _variableList.get(i - 1));
496        }
497
498        // Adjust operator type
499        Operator oper;
500        if (_nextInOrder == 0) {
501            oper = Conditional.Operator.NONE;
502        } else {
503            oper = (_logicType == Conditional.AntecedentOperator.ALL_AND)
504                    ? Conditional.Operator.AND
505                    : Conditional.Operator.OR;
506        }
507
508        temp.setOpern(oper);
509        _variableList.set(_nextInOrder, temp);
510        _nextInOrder++;
511        if (_nextInOrder >= _variableList.size()) {
512            _inVarReorder = false;
513        }
514        _variableTableModel.fireTableDataChanged();
515    }
516
517    /**
518     * Respond to the Negation column in the Edit Conditional window.
519     *
520     * @param row  index of the Conditional to change the setting on
521     * @param oper NOT (i18n) as negation of condition
522     */
523    void variableNegationChanged(int row, String oper) {
524        ConditionalVariable variable = _variableList.get(row);
525        boolean state = variable.isNegated();
526        if (oper == null) {
527            variable.setNegation(false);
528        } else {
529            variable.setNegation(oper.equals(Bundle.getMessage("LogicNOT")));  // NOI18N
530        }
531        if (variable.isNegated() != state) {
532            makeAntecedent();
533        }
534    }
535
536    /**
537     * Respond to the Operator column in the Edit Conditional window.
538     *
539     * @param row  index of the Conditional to change the setting on
540     * @param oper AND or OR (i18n) as operand on the list of conditions
541     */
542    void variableOperatorChanged(int row, String oper) {
543        ConditionalVariable variable = _variableList.get(row);
544        Operator oldOper = variable.getOpern();
545        if (row > 0) {
546            if (oper.equals(Bundle.getMessage("LogicOR"))) {  // NOI18N
547                variable.setOpern(Conditional.Operator.OR);
548            } else {
549                variable.setOpern(Conditional.Operator.AND);
550            }
551        } else {
552            variable.setOpern(Conditional.Operator.NONE);
553        }
554        if (variable.getOpern() != oldOper) {
555            makeAntecedent();
556        }
557    }
558
559    /**
560     * Respond to Add action button in the EditConditional window.
561     *
562     * @param e The event heard
563     */
564    void addActionPressed(ActionEvent e) {
565        if (alreadyEditingActionOrVariable()) {
566            return;
567        }
568        _curActionItem = Conditional.ItemType.NONE;
569        _actionList.add(new DefaultConditionalAction());
570        _newItem = true;
571        _actionTableModel.fireTableRowsInserted(_actionList.size(),
572                _actionList.size());
573        makeEditActionWindow(_actionList.size() - 1);
574    }
575
576    /**
577     * Respond to the Reorder Action Button in the Edit Conditional window.
578     *
579     * @param e The event heard
580     */
581    void reorderActionPressed(ActionEvent e) {
582        if (alreadyEditingActionOrVariable()) {
583            return;
584        }
585        // Check if reorder is reasonable
586        if (_actionList.size() <= 1) {
587            JmriJOptionPane.showMessageDialog(this,
588                    Bundle.getMessage("Error46"),
589                    Bundle.getMessage("ErrorTitle"), // NOI18N
590                    JmriJOptionPane.ERROR_MESSAGE);
591            return;
592        }
593        _nextInOrder = 0;
594        _inActReorder = true;
595        _actionTableModel.fireTableDataChanged();
596        _dataChanged = true;
597    }
598
599    /**
600     * Respond to the First/Next (Delete) Button in the Edit Conditional window.
601     *
602     * @param row index of the row to put as next in line (instead of the one
603     *            that was supposed to be next)
604     */
605    void swapActions(int row) {
606        ConditionalAction temp = _actionList.get(row);
607        for (int i = row; i > _nextInOrder; i--) {
608            _actionList.set(i, _actionList.get(i - 1));
609        }
610        _actionList.set(_nextInOrder, temp);
611        _nextInOrder++;
612        if (_nextInOrder >= _actionList.size()) {
613            _inActReorder = false;
614        }
615        _actionTableModel.fireTableDataChanged();
616    }
617
618    /**
619     * Respond to the Update Conditional Button in the Edit Conditional window.
620     *
621     * @param e The event heard
622     * @return true if updated
623     */
624    @Override
625    boolean updateConditionalPressed(ActionEvent e) {
626        if (alreadyEditingActionOrVariable()) {
627            return false;
628        }
629        log.debug("updateConditionalPressed");
630        if (validateAntecedent()) {
631            _antecedent = ConditionalEditBase.translateAntecedent(_antecedentField.getText(), true);
632            _trigger = _triggerOnChangeButton.isSelected();
633        } else {
634            return false;
635        }
636        return super.updateConditionalPressed(e);
637    }
638
639    /**
640     * Respond to the Cancel button in the Edit Conditional frame.
641     * <p>
642     * Does the cleanup from deleteConditionalPressed, updateConditionalPressed
643     * and _editConditionalFrame window closer.
644     */
645    @Override
646    void cancelConditionalPressed() {
647        log.debug("cancelConditionalPressed");
648        if (_editActionFrame != null) {
649            cleanUpAction();
650        }
651        if (_editVariableFrame != null) {
652            cleanUpVariable();
653        }
654        super.cancelConditionalPressed();
655    }
656
657    /**
658     * Respond to a change of Conditional Type in the Edit Conditional pane by
659     * showing/hiding the _antecedentPanel when Mixed is selected.
660     *
661     * @param e The event heard
662     * @return false if there is no change in operator
663     */
664    boolean logicTypeChanged(ActionEvent e) {
665        Conditional.AntecedentOperator type =
666                _operatorBox.getItemAt(_operatorBox.getSelectedIndex());
667        if (type == _logicType) {
668            return false;
669        }
670        makeAntecedent();
671
672        if (type == Conditional.AntecedentOperator.MIXED) {
673            _antecedentPanel.setVisible(true);
674            _reorderVarButton.setEnabled(false);
675        } else {
676            Operator oper = (type == Conditional.AntecedentOperator.ALL_AND)
677                    ? Conditional.Operator.AND
678                    : Conditional.Operator.OR;
679            for (int i = 1; i < _variableList.size(); i++) {
680                _variableList.get(i).setOpern(oper);
681            }
682            _antecedentPanel.setVisible(false);
683            _reorderVarButton.setEnabled(true);
684        }
685
686        _logicType = type;
687        _dataChanged = true;
688        _variableTableModel.fireTableDataChanged();
689        repaint();
690        return true;
691    }
692
693    /**
694     * Respond to Help button press in the Edit Conditional pane.
695     *
696     * @param e The event heard
697     */
698    void helpPressed(ActionEvent e) {
699        JmriJOptionPane.showMessageDialog(this,
700                new String[]{
701                    Bundle.getMessage("ConditionalHelpText1"), // NOI18N
702                    Bundle.getMessage("ConditionalHelpText2"), // NOI18N
703                    Bundle.getMessage("ConditionalHelpText3"), // NOI18N
704                    Bundle.getMessage("ConditionalHelpText4"), // NOI18N
705                    Bundle.getMessage("ConditionalHelpText5"), // NOI18N
706                    Bundle.getMessage("ConditionalHelpText6"), // NOI18N
707                    Bundle.getMessage("ConditionalHelpText7")  // NOI18N
708                },
709                Bundle.getMessage("MenuHelp"),
710                JmriJOptionPane.INFORMATION_MESSAGE);  // NOI18N
711    }
712
713    /**
714     * Build the antecedent statement.
715     */
716    void makeAntecedent() {
717        _antecedent = _parent.makeAntecedent(_variableList);
718        _antecedentField.setText(ConditionalEditBase.translateAntecedent(_antecedent, false));
719    }
720
721    /**
722     * Add a R# to the antecedent statement.
723     */
724    void appendToAntecedent() {
725        _antecedent = _parent.appendToAntecedent(_logicType, _variableList.size(), _antecedent);
726        _antecedentField.setText(ConditionalEditBase.translateAntecedent(_antecedent, false));
727    }
728
729    /**
730     * Check the antecedent and logic type.
731     *
732     * @return false if antecedent can't be validated
733     */
734    boolean validateAntecedent() {
735        return _parent.validateAntecedent(_logicType, _antecedentField.getText(),
736                _variableList, _parent._curConditional);
737    }
738
739    // ============ Shared Variable and Action Methods ============
740
741    /**
742     * Check if an editing session is going on.
743     * <p>
744     * If it is, display a message to user and bring current editing pane to
745     * front.
746     *
747     * @return true if an _editActionFrame or _editVariableFrame exists
748     */
749    boolean alreadyEditingActionOrVariable() {
750        if (_editActionFrame != null) {
751            if (!_dataChanged) {
752                cleanUpAction();
753                return false;
754            }
755            JmriJOptionPane.showMessageDialog(_editActionFrame,
756                    Bundle.getMessage("Error48"),
757                    Bundle.getMessage("ErrorTitle"), // NOI18N
758                    JmriJOptionPane.ERROR_MESSAGE);
759            _editActionFrame.setVisible(true);
760            _editActionFrame.toFront();
761            return true;
762        }
763        if (_editVariableFrame != null) {
764            if (!_dataChanged) {
765                cleanUpVariable();
766                return false;
767            }
768            JmriJOptionPane.showMessageDialog(_editVariableFrame,
769                    Bundle.getMessage("Error47"),
770                    Bundle.getMessage("ErrorTitle"), // NOI18N
771                    JmriJOptionPane.ERROR_MESSAGE);
772            _editVariableFrame.setVisible(true);
773            _editVariableFrame.toFront();
774            return true;
775        }
776        if (_parent._selectionMode == SelectionMode.USEMULTI) {
777            _parent.openPickListTable();
778        }
779        return false;
780    }
781
782    /**
783     * Fetch valid localized appearances for a given Signal Head.
784     * <p>
785     * Warn if head is not found.
786     *
787     * @param box            the comboBox on the setup pane to fill
788     * @param signalHeadName user or system name of the Signal Head
789     */
790    void loadJComboBoxWithHeadAppearances(JComboBox<String> box, String signalHeadName) {
791        box.removeAllItems();
792        log.debug("loadJComboBoxWithSignalHeadAppearances called with name: {}", signalHeadName);  // NOI18N
793        SignalHead h = InstanceManager.getDefault(jmri.SignalHeadManager.class).getSignalHead(signalHeadName);
794        if (h == null) {
795            box.addItem(Bundle.getMessage("PromptLoadHeadName"));  // NOI18N
796        } else {
797            String[] v = h.getValidStateNames();
798            for (int i = 0; i < v.length; i++) {
799                box.addItem(v[i]);
800            }
801            box.setSelectedItem(h.getAppearanceName());
802        }
803    }
804
805    /**
806     * Fetch valid aspects for a given Signal Mast.
807     * <p>
808     * Warn if mast is not found.
809     *
810     * @param box      the comboBox on the setup pane to fill
811     * @param mastName user or system name of the Signal Mast
812     */
813    void loadJComboBoxWithMastAspects(JComboBox<String> box, String mastName) {
814        box.removeAllItems();
815        log.debug("loadJComboBoxWithMastAspects called with name: {}", mastName);  // NOI18N
816        SignalMast m = InstanceManager.getDefault(jmri.SignalMastManager.class).getSignalMast(mastName);
817        if (m == null) {
818            box.addItem(Bundle.getMessage("PromptLoadMastName"));  // NOI18N
819        } else {
820            java.util.Vector<String> v = m.getValidAspects();
821            for (int i = 0; i < v.size(); i++) {
822                box.addItem(v.get(i));
823            }
824            box.setSelectedItem(m.getAspect());
825        }
826    }
827
828    // ------------ Build sub-panels ------------
829
830    /**
831     * Create Variable and Action editing pane top part.
832     *
833     * @param frame  JFrame to add to
834     * @param title  property key for border title
835     * @param width  fixed dimension to use
836     * @param height fixed dimension to use
837     * @return JPanel containing interface
838     */
839    JPanel makeTopPanel(JFrame frame, String title, int width, int height) {
840        Container contentPane = frame.getContentPane();
841        contentPane.setLayout(new BoxLayout(contentPane, BoxLayout.X_AXIS));
842        contentPane.add(Box.createRigidArea(new Dimension(0, height)));
843        JPanel topPanel = new JPanel();
844        topPanel.setLayout(new BoxLayout(topPanel, BoxLayout.Y_AXIS));
845        Border panelBorder = BorderFactory.createEtchedBorder();
846        Border panelTitled = BorderFactory.createTitledBorder(panelBorder, Bundle.getMessage(title));
847        topPanel.setBorder(panelTitled);
848        topPanel.add(Box.createRigidArea(new Dimension(width, 0)));
849        topPanel.add(Box.createVerticalGlue());
850        return topPanel;
851    }
852
853    /**
854     * Create Variable and Action editing pane bottom part.
855     * <p>
856     * Called from {@link #makeEditVariableWindow(int)}
857     *
858     * @param updateListener listener for Update pressed
859     * @param cancelListener listener for Cancel pressed
860     * @param deleteListener listener for Delete pressed
861     * @return JPanel containing Update etc. buttons
862     */
863    JPanel makeButtonPanel(ActionListener updateListener,
864            ActionListener cancelListener,
865            ActionListener deleteListener) {
866        JPanel panel3 = new JPanel();
867        panel3.setLayout(new BoxLayout(panel3, BoxLayout.X_AXIS));
868
869        JButton cancelAction = new JButton(Bundle.getMessage("ButtonCancel"));  // NOI18N
870        panel3.add(cancelAction);
871        panel3.add(Box.createHorizontalStrut(STRUT));
872        cancelAction.addActionListener(cancelListener);
873        cancelAction.setToolTipText(Bundle.getMessage("CancelButtonHint"));  // NOI18N
874
875        JButton updateAction = new JButton(Bundle.getMessage("ButtonUpdate"));  // NOI18N
876        panel3.add(updateAction);
877        panel3.add(Box.createHorizontalStrut(STRUT));
878        updateAction.addActionListener(updateListener);
879        updateAction.setToolTipText(Bundle.getMessage("UpdateButtonHint"));  // NOI18N
880
881        JButton deleteAction = new JButton(Bundle.getMessage("ButtonDelete"));  // NOI18N
882        panel3.add(deleteAction);
883        deleteAction.addActionListener(deleteListener);
884        deleteAction.setToolTipText(Bundle.getMessage("DeleteButtonHint"));  // NOI18N
885        return panel3;
886    }
887
888    // ============ Edit Variable Window and Methods ============
889
890    /**
891     * Create and/or initialize the Edit a Variable pane.
892     * <p>
893     * Note: you can get here via the New Variable button (addVariablePressed)
894     * or via an Edit button in the Variable table of the EditConditional
895     * window.
896     *
897     * @param row index of item to be edited in _variableList
898     */
899    void makeEditVariableWindow(int row) {
900        if (alreadyEditingActionOrVariable()) {
901            return;
902        }
903        log.debug("makeEditVariableWindow: row = {}", row);
904        _curVariableRowNumber = row;
905        _curVariable = _variableList.get(row);
906        _editVariableFrame = new JmriJFrame(Bundle.getMessage("TitleEditVariable"), true, true);  // NOI18N
907        _editVariableFrame.addHelpMenu(
908                "package.jmri.jmrit.conditional.StateVariableActionList", true);  // NOI18N
909        JPanel topPanel = makeTopPanel(_editVariableFrame, "TitleAntecedentPhrase", 500, 160);  // NOI18N
910
911        Box panel1 = Box.createHorizontalBox();
912        panel1.add(Box.createHorizontalGlue());
913        panel1.add(Box.createHorizontalStrut(STRUT));
914
915        // Item Type
916        _variableItemBox = new JComboBox<>();
917        for (Conditional.ItemType itemType : Conditional.ItemType.getStateVarList()) {
918            _variableItemBox.addItem(itemType);
919        }
920        JComboBoxUtil.setupComboBoxMaxRows(_variableItemBox);
921        panel1.add(makeEditPanel(_variableItemBox, "LabelVariableType", "VariableTypeHint"));  // NOI18N
922        panel1.add(Box.createHorizontalStrut(STRUT));
923
924        // Item Name
925        _variableNameField = new JTextField(30);
926        _variableNamePanel = makeEditPanel(_variableNameField, "LabelItemName", null);  // NOI18N
927        _variableNamePanel.setMaximumSize(
928                new Dimension(50, _variableNamePanel.getPreferredSize().height));
929        _variableNamePanel.setVisible(false);
930        panel1.add(_variableNamePanel);
931        panel1.add(Box.createHorizontalStrut(STRUT));
932
933        // Arbitrary name combo box to facilitate the panel construction
934        if (_parent._selectionMode == SelectionMode.USECOMBO) {
935            _comboNameBox = _parent.createNameBox(Conditional.ItemType.SENSOR);
936            _variableComboNamePanel = makeEditPanel(_comboNameBox, "LabelItemName", null);  // NOI18N
937            _variableComboNamePanel.setVisible(false);
938            panel1.add(_variableComboNamePanel);
939            panel1.add(Box.createHorizontalStrut(STRUT));
940        }
941
942        // Combo box section for selecting conditional reference
943        //   First box selects the Logix, the second selects the conditional within the logix
944        _selectLogixBox.addItem("XXXXXXXXXXXXXXXXXXXXX");  // NOI18N
945        _selectConditionalBox.addItem("XXXXXXXXXXXXXXXXXXXXX");  // NOI18N
946        _selectLogixPanel = makeEditPanel(_selectLogixBox, "SelectLogix", null);  // NOI18N
947        _selectConditionalPanel = makeEditPanel(_selectConditionalBox, "SelectConditional", null);  // NOI18N
948        _selectLogixPanel.setVisible(false);
949        _selectConditionalPanel.setVisible(false);
950        panel1.add(_selectLogixPanel);
951        panel1.add(_selectConditionalPanel);
952        panel1.add(Box.createHorizontalStrut(STRUT));
953
954        // State Box
955        _variableStateBox = new JComboBox<>();
956        _variableStateBox.addItem(Conditional.Type.XXXXXXX);
957        _variableStatePanel = makeEditPanel(_variableStateBox, "LabelVariableState", "VariableStateHint");  // NOI18N
958        _variableStatePanel.setVisible(false);
959        panel1.add(_variableStatePanel);
960        panel1.add(Box.createHorizontalStrut(STRUT));
961
962        // Aspects
963        _variableSignalBox = new JComboBox<String>();
964        _variableSignalBox.addItem("XXXXXXXXX");  // NOI18N
965        _variableSignalPanel = makeEditPanel(_variableSignalBox, "LabelVariableAspect", "VariableAspectHint");  // NOI18N
966        _variableSignalPanel.setVisible(false);
967        panel1.add(_variableSignalPanel);
968        panel1.add(Box.createHorizontalStrut(STRUT));
969
970        // Compare operator
971        _variableComparePanel = new JPanel();
972        _variableComparePanel.setLayout(new BoxLayout(_variableComparePanel, BoxLayout.X_AXIS));
973        _variableCompareOpBox = new JComboBox<String>();
974        for (int i = 1; i <= ConditionalVariable.NUM_COMPARE_OPERATIONS; i++) {
975            _variableCompareOpBox.addItem(ConditionalVariable.getCompareOperationString(i));
976        }
977        _variableComparePanel.add(makeEditPanel(_variableCompareOpBox, "LabelCompareOp", "CompareHintMemory"));  // NOI18N
978        _variableComparePanel.add(Box.createHorizontalStrut(STRUT));
979
980        // Compare type
981        _variableCompareTypeBox = new JComboBox<>();
982        for (Conditional.Type t : Conditional.Type.getMemoryItems()) {
983            _variableCompareTypeBox.addItem(t);
984        }
985        _variableComparePanel.add(makeEditPanel(_variableCompareTypeBox, "LabelCompareType", "CompareTypeHint"));  // NOI18N
986        _variableComparePanel.setVisible(false);
987        _variableCompareTypeBox.addActionListener(new ActionListener() {
988            @Override
989            public void actionPerformed(ActionEvent e) {
990                compareTypeChanged(_variableCompareTypeBox.getSelectedIndex());
991                _editVariableFrame.pack();
992                _dataChanged = true;
993            }
994        });
995        panel1.add(_variableComparePanel);
996        panel1.add(Box.createHorizontalStrut(STRUT));
997
998        // Data 1
999        _variableData1Field = new JTextField(30);
1000        _variableData1Panel = makeEditPanel(_variableData1Field, "LabelStartTime", "DataHintTime");  // NOI18N
1001        _variableData1Panel.setMaximumSize(
1002                new Dimension(45, _variableData1Panel.getPreferredSize().height));
1003        _variableData1Panel.setVisible(false);
1004        panel1.add(_variableData1Panel);
1005        panel1.add(Box.createHorizontalStrut(STRUT));
1006
1007        // Data 2
1008        _variableData2Field = new JTextField(30);
1009        _variableData2Panel = makeEditPanel(_variableData2Field, "LabelEndTime", "DataHintTime");  // NOI18N
1010        _variableData2Panel.setMaximumSize(
1011                new Dimension(45, _variableData2Panel.getPreferredSize().height));
1012        _variableData2Panel.setVisible(false);
1013        panel1.add(_variableData2Panel);
1014        panel1.add(Box.createHorizontalStrut(STRUT));
1015        panel1.add(Box.createHorizontalGlue());
1016        topPanel.add(panel1);
1017
1018        ActionListener updateListener = new ActionListener() {
1019            @Override
1020            public void actionPerformed(ActionEvent e) {
1021                updateVariablePressed();
1022            }
1023        };
1024        ActionListener cancelListener = new ActionListener() {
1025            @Override
1026            public void actionPerformed(ActionEvent e) {
1027                cancelEditVariablePressed();
1028            }
1029        };
1030        ActionListener deleteListener = new ActionListener() {
1031            @Override
1032            public void actionPerformed(ActionEvent e) {
1033                deleteVariablePressed();
1034            }
1035        };
1036        JPanel panel = makeButtonPanel(updateListener, cancelListener, deleteListener);
1037        topPanel.add(panel);
1038        topPanel.add(Box.createVerticalGlue());
1039
1040        Container contentPane = _editVariableFrame.getContentPane();
1041        contentPane.add(topPanel);
1042
1043        _variableItemBox.addActionListener(new ActionListener() {
1044            @Override
1045            public void actionPerformed(ActionEvent e) {
1046                Conditional.ItemType newVariableItem = _variableItemBox.getItemAt(_variableItemBox.getSelectedIndex());
1047                if (log.isDebugEnabled()) {
1048                    log.debug("_variableItemBox Listener: new = {}, curr = {}, row = {}",  // NOI18N
1049                            newVariableItem, _curVariableItem, _curVariableRowNumber);
1050                }
1051                if (newVariableItem != _curVariableItem) {
1052                    if (_curVariableRowNumber >= 0) {
1053                        _curVariable = new ConditionalVariable();
1054                        if (_curVariableRowNumber > 0) {
1055                            if (_logicType == Conditional.AntecedentOperator.ALL_OR) {
1056                                _curVariable.setOpern(Conditional.Operator.OR);
1057                            } else {
1058                                _curVariable.setOpern(Conditional.Operator.AND);
1059                            }
1060                        }
1061                        _variableList.set(_curVariableRowNumber, _curVariable);
1062                    }
1063                    _curVariableItem = newVariableItem;
1064                }
1065                _dataChanged = true;
1066                variableItemChanged(newVariableItem);
1067                _editVariableFrame.pack();
1068            }
1069        });
1070        // setup window closing listener
1071        _editVariableFrame.addWindowListener(
1072                new java.awt.event.WindowAdapter() {
1073            @Override
1074            public void windowClosing(java.awt.event.WindowEvent e) {
1075                cancelEditVariablePressed();
1076            }
1077        });
1078        _curVariableItem = _curVariable.getType().getItemType();
1079        initializeStateVariables();
1080        _dataChanged = false;
1081        _editVariableFrame.pack();
1082        _editVariableFrame.setVisible(true);
1083    }
1084
1085    // ------------ Main Variable methods ------------
1086
1087    /**
1088     * Set display to show current state variable (_curVariable) parameters.
1089     */
1090    void initializeStateVariables() {
1091        Conditional.Type testType = _curVariable.getType();
1092        Conditional.ItemType itemType = testType.getItemType();
1093        if (log.isDebugEnabled()) {
1094            log.debug("initializeStateVariables: itemType = {}, testType = {}", itemType, testType);  // NOI18N
1095        }
1096        if (testType == Conditional.Type.NONE) {
1097            return;
1098        }
1099        // set item - _variableItemBox Listener will call variableItemChanged
1100        _variableItemBox.setSelectedItem(itemType);
1101        switch (itemType) {
1102            case SENSOR:
1103            case TURNOUT:
1104            case LIGHT:
1105            case CONDITIONAL:
1106            case WARRANT:
1107                _variableStateBox.setSelectedItem(testType);
1108                _variableNameField.setText(_curVariable.getName());
1109                break;
1110
1111            case SIGNALHEAD:
1112                _variableStateBox.setSelectedItem(testType);
1113                _variableNameField.setText(_curVariable.getName());
1114                if (Conditional.Type.isSignalHeadApperance(testType)) {
1115                    _variableStateBox.setSelectedItem(Conditional.Type.SIGNAL_HEAD_APPEARANCE_EQUALS);
1116                    loadJComboBoxWithHeadAppearances(_variableSignalBox, _curVariable.getName());
1117                    _variableSignalBox.setSelectedItem(_curVariable.getType());
1118                    _variableSignalPanel.setVisible(true);
1119                }
1120                break;
1121
1122            case SIGNALMAST:
1123                // set display to show current state variable (curVariable) parameters
1124                _variableStateBox.setSelectedItem(testType);
1125                _variableNameField.setText(_curVariable.getName());
1126                if (testType == Conditional.Type.SIGNAL_MAST_ASPECT_EQUALS) {
1127                    loadJComboBoxWithMastAspects(_variableSignalBox, _curVariable.getName());
1128                    _variableSignalBox.setSelectedItem(_curVariable.getDataString());
1129                    _variableSignalPanel.setVisible(true);
1130                }
1131                break;
1132
1133            case MEMORY:
1134                _variableCompareTypeBox.setSelectedIndex(
1135                        Conditional.Type.getIndexInList(Conditional.Type.getMemoryItems(), testType));
1136                _variableNameField.setText(_curVariable.getName());
1137                int num1 = _curVariable.getNum1() - 1;
1138                if (num1 == -1) {  // former code was only equals
1139                    num1 = ConditionalVariable.EQUAL - 1;
1140                }
1141                _variableCompareOpBox.setSelectedIndex(num1);
1142                _variableData1Field.setText(_curVariable.getDataString());
1143                break;
1144
1145            case CLOCK:
1146                int time = _curVariable.getNum1();
1147                _variableData1Field.setText(ConditionalEditBase.formatTime(time / 60, time - ((time / 60) * 60)));
1148                time = _curVariable.getNum2();
1149                _variableData2Field.setText(ConditionalEditBase.formatTime(time / 60, time - ((time / 60) * 60)));
1150                _variableNameField.setText("");
1151                break;
1152
1153            case OBLOCK:
1154                _variableNameField.setText(_curVariable.getName());
1155                //_variableStateBox.removeAllItems();
1156                for (Conditional.Type type : Conditional.Type.getOBlockItems()) {
1157                    _variableStateBox.addItem(type);
1158                    if (type.toString().equals(OBlock.getLocalStatusName(_curVariable.getDataString()))) {
1159                        _variableStateBox.setSelectedItem(type);
1160                    }
1161                }
1162//                Iterator<String> names = OBlock.getLocalStatusNames();
1163//                while (names.hasNext()) {
1164//                    _variableStateBox.addItem(names.next());
1165//                }
1166//                _variableStateBox.setSelectedItem(OBlock.getLocalStatusName(_curVariable.getDataString()));
1167                _variableStateBox.setVisible(true);
1168                break;
1169
1170            case ENTRYEXIT:
1171                _variableNameField.setText(_curVariable.getBean().getUserName());
1172                _variableStateBox.setSelectedItem(testType);
1173                _variableStateBox.setVisible(true);
1174                break;
1175
1176            default:
1177                break;
1178        }
1179        _editVariableFrame.pack();
1180        _editVariableFrame.transferFocusBackward();
1181    }
1182
1183    /**
1184     * Respond to change in variable item chosen in the State Variable Table in
1185     * the Edit Conditional pane.
1186     * <p>
1187     * Also used to set up for Edit of a Conditional with state variables.
1188     *
1189     * @param itemType value representing the newly selected Conditional type,
1190     *                 i.e. ITEM_TYPE_SENSOR
1191     */
1192    private void variableItemChanged(Conditional.ItemType itemType) {
1193        Conditional.Type testType = _curVariable.getType();
1194        if (log.isDebugEnabled()) {
1195            log.debug("variableItemChanged: itemType = {}, testType = {}", itemType, testType);  // NOI18N
1196        }
1197        _variableNamePanel.setVisible(false);
1198        _variableStatePanel.setVisible(false);
1199        _variableComparePanel.setVisible(false);
1200        _variableSignalPanel.setVisible(false);
1201        _variableData1Panel.setVisible(false);
1202        _variableData2Panel.setVisible(false);
1203        _selectLogixPanel.setVisible(false);
1204        _selectConditionalPanel.setVisible(false);
1205        _variableStateBox.removeAllItems();
1206        _variableNameField.removeActionListener(variableSignalHeadNameListener);
1207        _variableNameField.removeActionListener(variableSignalMastNameListener);
1208        _variableStateBox.removeActionListener(variableSignalTestStateListener);
1209        _selectLogixBox.removeActionListener(selectLogixBoxListener);
1210        _selectConditionalBox.removeActionListener(selectConditionalBoxListener);
1211
1212        if (_parent._selectionMode == SelectionMode.USECOMBO) {
1213            _variableComboNamePanel.setVisible(false);
1214        } else if (_parent._selectionMode == SelectionMode.USESINGLE) {
1215            _parent.createSinglePanelPickList(itemType, _parent.getPickSingleListener(_variableNameField, itemType), false);
1216        } else {
1217            // Default and USEMULTI
1218            _parent.setPickListTab(itemType, false);
1219        }
1220
1221        switch (itemType) {
1222            case NONE:
1223                return;
1224            case SENSOR:
1225                _variableNamePanel.setToolTipText(Bundle.getMessage("NameHintSensor"));  // NOI18N
1226                for (Conditional.Type type : Conditional.Type.getSensorItems()) {
1227                    _variableStateBox.addItem(type);
1228                }
1229                _variableStatePanel.setVisible(true);
1230                _variableNamePanel.setVisible(true);
1231                setVariableNameBox(itemType);
1232                break;
1233
1234            case TURNOUT:
1235                _variableNamePanel.setToolTipText(Bundle.getMessage("NameHintTurnout"));  // NOI18N
1236                for (Conditional.Type type : Conditional.Type.getTurnoutItems()) {
1237                    _variableStateBox.addItem(type);
1238                }
1239                _variableNamePanel.setVisible(true);
1240                _variableStatePanel.setVisible(true);
1241                setVariableNameBox(itemType);
1242                break;
1243
1244            case LIGHT:
1245                _variableNamePanel.setToolTipText(Bundle.getMessage("NameHintLight"));  // NOI18N
1246                for (Conditional.Type type : Conditional.Type.getLightItems()) {
1247                    _variableStateBox.addItem(type);
1248                }
1249                _variableStatePanel.setVisible(true);
1250                _variableNamePanel.setVisible(true);
1251                setVariableNameBox(itemType);
1252                break;
1253
1254            case SIGNALHEAD:
1255                _variableStateBox.addActionListener(variableSignalTestStateListener);
1256                loadJComboBoxWithHeadAppearances(_variableSignalBox, _variableNameField.getText().trim());
1257
1258                for (Conditional.Type type : Conditional.Type.getSignalHeadStateMachineItems()) {
1259                    _variableStateBox.addItem(type);
1260                }
1261                _variableNamePanel.setToolTipText(Bundle.getMessage("NameHintSignal"));  // NOI18N
1262                _variableNamePanel.setVisible(true);
1263                _variableStatePanel.setVisible(true);
1264                if (testType == Conditional.Type.SIGNAL_HEAD_APPEARANCE_EQUALS) {
1265                    _variableSignalPanel.setVisible(true);
1266                } else {
1267                    _variableSignalPanel.setVisible(false);
1268                }
1269                setVariableNameBox(itemType);
1270                _variableNameField.addActionListener(variableSignalHeadNameListener);
1271                break;
1272
1273            case SIGNALMAST:
1274                _variableStateBox.addActionListener(variableSignalTestStateListener);
1275                loadJComboBoxWithMastAspects(_variableSignalBox, _variableNameField.getText().trim());
1276
1277                for (Conditional.Type type : Conditional.Type.getSignalMastItems()) {
1278                    _variableStateBox.addItem(type);
1279                }
1280                _variableNamePanel.setToolTipText(Bundle.getMessage("NameHintSignalMast"));  // NOI18N
1281                _variableNamePanel.setVisible(true);
1282                _variableStatePanel.setVisible(true);
1283                if (testType == Conditional.Type.SIGNAL_MAST_ASPECT_EQUALS) {
1284                    _variableSignalPanel.setVisible(true);
1285                } else {
1286                    _variableSignalPanel.setVisible(false);
1287                }
1288                setVariableNameBox(itemType);
1289                _variableNameField.addActionListener(variableSignalMastNameListener);
1290                break;
1291
1292            case MEMORY:
1293                JPanel p = (JPanel) _variableData1Panel.getComponent(0);
1294                JLabel l = (JLabel) p.getComponent(0);
1295                if ((testType == Conditional.Type.MEMORY_COMPARE)
1296                        || (testType == Conditional.Type.MEMORY_COMPARE_INSENSITIVE)) {
1297                    l.setText(Bundle.getMessage("LabelMemoryValue"));  // NOI18N
1298                    _variableData1Panel.setToolTipText(Bundle.getMessage("DataHintMemory"));  // NOI18N
1299                } else {
1300                    l.setText(Bundle.getMessage("LabelLiteralValue"));  // NOI18N
1301                    _variableData1Panel.setToolTipText(Bundle.getMessage("DataHintValue"));  // NOI18N
1302                }
1303                _variableNamePanel.setToolTipText(Bundle.getMessage("NameHintMemory"));  // NOI18N
1304                _variableNamePanel.setVisible(true);
1305                _variableData1Panel.setToolTipText(Bundle.getMessage("DataHintMemory"));  // NOI18N
1306                _variableData1Panel.setVisible(true);
1307                _variableComparePanel.setVisible(true);
1308                setVariableNameBox(itemType);
1309                break;
1310
1311            case CONDITIONAL:
1312                _variableNamePanel.setToolTipText(Bundle.getMessage("NameHintConditional"));  // NOI18N
1313                for (Conditional.Type type : Conditional.Type.getConditionalItems()) {
1314                    _variableStateBox.addItem(type);
1315                }
1316                // Load the Logix and Conditional combo boxes
1317                loadSelectLogixBox(_curVariable);
1318                _selectLogixPanel.setPreferredSize(_selectLogixBox.getPreferredSize());
1319                _selectConditionalPanel.setPreferredSize(_selectConditionalBox.getPreferredSize());
1320                _selectLogixPanel.setVisible(true);
1321                _selectConditionalPanel.setVisible(true);
1322                _variableStatePanel.setVisible(true);
1323                _selectLogixBox.addActionListener(selectLogixBoxListener);
1324                _selectConditionalBox.addActionListener(selectConditionalBoxListener);
1325                break;
1326
1327            case WARRANT:
1328                _variableNamePanel.setToolTipText(Bundle.getMessage("NameHintWarrant"));  // NOI18N
1329                for (Conditional.Type type : Conditional.Type.getWarrantItems()) {
1330                    _variableStateBox.addItem(type);
1331                }
1332                _variableNamePanel.setVisible(true);
1333                _variableStatePanel.setVisible(true);
1334                setVariableNameBox(itemType);
1335                break;
1336
1337            case CLOCK:
1338                p = (JPanel) _variableData1Panel.getComponent(0);
1339                l = (JLabel) p.getComponent(0);
1340                l.setText(Bundle.getMessage("LabelStartTime"));  // NOI18N
1341                _variableData1Panel.setToolTipText(Bundle.getMessage("DataHintTime"));  // NOI18N
1342                _variableData1Panel.setVisible(true);
1343                _variableData2Panel.setVisible(true);
1344                break;
1345
1346            case OBLOCK:
1347                _variableNamePanel.setToolTipText(Bundle.getMessage("NameHintOBlock"));  // NOI18N
1348                _variableNamePanel.setVisible(true);
1349                _variableStateBox.removeAllItems();
1350                for (Conditional.Type type : Conditional.Type.getOBlockItems()) {
1351                    _variableStateBox.addItem(type);
1352                }
1353//                Iterator<String> names = OBlock.getLocalStatusNames();
1354//                while (names.hasNext()) {
1355//                    _variableStateBox.addItem(names.next());
1356//                }
1357                _variableStatePanel.setVisible(true);
1358                setVariableNameBox(itemType);
1359                break;
1360
1361            case ENTRYEXIT:
1362                _variableNamePanel.setToolTipText(Bundle.getMessage("NameHintEntryExit"));  // NOI18N
1363                _variableNameField.setText(_curVariable.getName());
1364                for (Conditional.Type type : Conditional.Type.getEntryExitItems()) {
1365                    _variableStateBox.addItem(type);
1366                }
1367                _variableStatePanel.setVisible(true);
1368                _variableNamePanel.setVisible(true);
1369                setVariableNameBox(itemType);
1370                break;
1371
1372            default:
1373                break;
1374        }
1375        _variableStateBox.setMaximumSize(_variableStateBox.getPreferredSize());
1376    }
1377
1378    /**
1379     * Update the name combo box selection based on the current contents of the
1380     * name field.
1381     *
1382     * @since 4.7.3
1383     * @param itemType The type of name box to be created.
1384     */
1385    void setVariableNameBox(Conditional.ItemType itemType) {
1386        if (_parent._selectionMode != SelectionMode.USECOMBO) {
1387            return;
1388        }
1389        _comboNameBox = _parent.createNameBox(itemType);
1390        if (_comboNameBox == null) {
1391            return;
1392        }
1393        _comboNameBox.setSelectedItemByName(_curVariable.getName());
1394        _comboNameBox.addActionListener(new NameBoxListener(_variableNameField));
1395        _variableComboNamePanel.remove(1);
1396        _variableComboNamePanel.add(_comboNameBox, null, 1);
1397        _variableNamePanel.setVisible(false);
1398        _variableComboNamePanel.setVisible(true);
1399    }
1400
1401    // ------------ Variable detail methods ------------
1402
1403    /**
1404     * Respond to Update Variable button in the Edit Action pane.
1405     */
1406    void updateVariablePressed() {
1407        if (!validateVariable()) {
1408            _editVariableFrame.toFront();
1409            return;
1410        }
1411        _variableTableModel.fireTableRowsUpdated(_curVariableRowNumber, _curVariableRowNumber);
1412        cleanUpVariable();
1413    }
1414
1415    /**
1416     * Respond to Cancel action button and window closer of the Edit Variable
1417     * pane.
1418     * <p>
1419     * Also does cleanup of Update and Delete Variable buttons.
1420     */
1421    void cancelEditVariablePressed() {
1422        if (_newItem) {
1423            deleteVariablePressed(_curVariableRowNumber);
1424        } else {
1425            cleanUpVariable();
1426        }
1427    }
1428
1429    /**
1430     * Clean up Update and Delete Variable buttons.
1431     */
1432    void cleanUpVariable() {
1433        _newItem = false;
1434        if (_editVariableFrame != null) {
1435            _editVariableFrame.setVisible(false);
1436            _editVariableFrame.dispose();
1437            _editVariableFrame = null;
1438            _parent.closeSinglePanelPickList();
1439        }
1440        _curVariableRowNumber = -1;
1441    }
1442
1443    /**
1444     * Respond to Delete action button in the Edit Variable window.
1445     */
1446    void deleteVariablePressed() {
1447        deleteVariablePressed(_curVariableRowNumber);
1448    }
1449
1450    /**
1451     * Respond to the Delete Button in the State Variable Table of the Edit
1452     * Conditional window.
1453     *
1454     * @param row index in table of variable to be deleted
1455     */
1456    void deleteVariablePressed(int row) {
1457        if (row != _curVariableRowNumber && alreadyEditingActionOrVariable()) {
1458            return;
1459        }
1460        if (_variableList.size() < 1 && !_parent._suppressReminder) {
1461            // warning message - last State Variable deleted
1462            JmriJOptionPane.showMessageDialog(this,
1463                    Bundle.getMessage("Warn3"),
1464                    Bundle.getMessage("WarningTitle"), // NOI18N
1465                    JmriJOptionPane.WARNING_MESSAGE);
1466        }
1467        // move remaining state variables if needed
1468        _variableList.remove(row);
1469        _variableTableModel.fireTableRowsDeleted(row, row);
1470        _dataChanged = true;
1471        makeAntecedent();
1472        cleanUpVariable();
1473    }
1474
1475    /**
1476     * Check if Memory type in a Conditional was changed by the user.
1477     * <p>
1478     * Update GUI if it has. Called from {@link #makeEditVariableWindow(int)}
1479     *
1480     * @param selection index of the currently selected type in the
1481     *                  _variableCompareTypeBox
1482     */
1483    private void compareTypeChanged(int selection) {
1484        JPanel p = (JPanel) _variableData1Panel.getComponent(0);
1485        JLabel l = (JLabel) p.getComponent(0);
1486        Conditional.Type testType = Conditional.Type.getMemoryItems().get(selection);
1487        if ((testType == Conditional.Type.MEMORY_COMPARE)
1488                || (testType == Conditional.Type.MEMORY_COMPARE_INSENSITIVE)) {
1489            l.setText(Bundle.getMessage("LabelMemoryValue"));  // NOI18N
1490            _variableData1Panel.setToolTipText(Bundle.getMessage("DataHintMemory"));  // NOI18N
1491        } else {
1492            l.setText(Bundle.getMessage("LabelLiteralValue"));  // NOI18N
1493            _variableData1Panel.setToolTipText(Bundle.getMessage("DataHintValue"));  // NOI18N
1494        }
1495    }
1496
1497
1498    // ------------ Variable update processes ------------
1499
1500    /**
1501     * Validate Variable data from Edit Variable Window, and transfer it to
1502     * current action object as appropriate.
1503     * <p>
1504     * Messages are sent to the user for any errors found. This routine returns
1505     * false immediately after finding the first error, even if there might be
1506     * more errors.
1507     *
1508     * @return true if all data checks out OK, otherwise false
1509     */
1510    boolean validateVariable() {
1511        String name = _variableNameField.getText().trim();
1512        _variableNameField.setText(name);
1513        _curVariable.setDataString("");
1514        _curVariable.setNum1(0);
1515        _curVariable.setNum2(0);
1516        Conditional.ItemType itemType = _variableItemBox.getItemAt(_variableItemBox.getSelectedIndex());
1517        Conditional.Type testType = Conditional.Type.NONE;
1518        if (!checkIsAction(name, itemType) ) {
1519            return false;
1520        }
1521        _dataChanged = true;
1522        switch (itemType) {
1523            case SENSOR:
1524            case TURNOUT:
1525            case LIGHT:
1526            case SIGNALHEAD:
1527            case SIGNALMAST:
1528            case CONDITIONAL:
1529            case WARRANT:
1530            case ENTRYEXIT:
1531                testType = _variableStateBox.getItemAt(_variableStateBox.getSelectedIndex());
1532                break;
1533            case MEMORY:
1534                testType = _variableCompareTypeBox.getItemAt(_variableCompareTypeBox.getSelectedIndex());
1535                break;
1536            case CLOCK:
1537                testType = Conditional.Type.FAST_CLOCK_RANGE;
1538                break;
1539            case OBLOCK:
1540                testType = Conditional.Type.BLOCK_STATUS_EQUALS;
1541                break;
1542            default:
1543                JmriJOptionPane.showMessageDialog(this,
1544                        Bundle.getMessage("ErrorVariableType"),
1545                        Bundle.getMessage("ErrorTitle"), // NOI18N
1546                        JmriJOptionPane.ERROR_MESSAGE);
1547                return false;
1548        }
1549        _curVariable.setType(testType);
1550        log.debug("validateVariable: itemType= {}, testType= {}", itemType, testType);  // NOI18N
1551        switch (itemType) {
1552            case SENSOR:
1553                name = _parent.validateSensorReference(name);
1554                if (name == null) {
1555                    return false;
1556                }
1557                break;
1558            case TURNOUT:
1559                name = _parent.validateTurnoutReference(name);
1560                if (name == null) {
1561                    return false;
1562                }
1563                break;
1564            case CONDITIONAL:
1565                name = _parent.validateConditionalReference(name);
1566                if (name == null) {
1567                    return false;
1568                }
1569                _curVariable.setName(name);
1570                Conditional c = _parent._conditionalManager.getBySystemName(name);
1571                if (c == null) {
1572                    return false;
1573                }
1574                String uName = c.getUserName();
1575                if (uName == null || uName.isEmpty()) {
1576                    _curVariable.setGuiName(c.getSystemName());
1577                } else {
1578                    _curVariable.setGuiName(uName);
1579                }
1580                break;
1581            case LIGHT:
1582                name = _parent.validateLightReference(name);
1583                if (name == null) {
1584                    return false;
1585                }
1586                break;
1587            case MEMORY:
1588                name = _parent.validateMemoryReference(name);
1589                if (name == null) {
1590                    return false;
1591                }
1592                String name2 = _variableData1Field.getText();
1593                if ((testType == Conditional.Type.MEMORY_COMPARE)
1594                        || (testType == Conditional.Type.MEMORY_COMPARE_INSENSITIVE)) {
1595                    name2 = _parent.validateMemoryReference(name2);
1596                    if (name2 == null) {
1597                        return false;
1598                    }
1599                }
1600                _curVariable.setDataString(name2);
1601                _curVariable.setNum1(_variableCompareOpBox.getSelectedIndex() + 1);
1602                break;
1603            case CLOCK:
1604                int beginTime = _parent.parseTime(_variableData1Field.getText());
1605                if (beginTime < 0) {
1606                    // parse error occurred - message has been sent
1607                    return (false);
1608                }
1609                int endTime = _parent.parseTime(_variableData2Field.getText());
1610                if (endTime < 0) {
1611                    return (false);
1612                }
1613                // set beginning and end time (minutes since midnight)
1614                _curVariable.setNum1(beginTime);
1615                _curVariable.setNum2(endTime);
1616                name = "Clock";  // NOI18N
1617                break;
1618            case SIGNALHEAD:
1619                name = _parent.validateSignalHeadReference(name);
1620                if (name == null) {
1621                    return false;
1622                }
1623                if (testType == Conditional.Type.SIGNAL_HEAD_APPEARANCE_EQUALS) {
1624                    String appStr = (String) _variableSignalBox.getSelectedItem();
1625                    Conditional.Type type = ConditionalVariable.stringToVariableTest(appStr);
1626                    if (type == Conditional.Type.ERROR) {
1627                        JmriJOptionPane.showMessageDialog(this,
1628                                Bundle.getMessage("ErrorAppearance"),
1629                                Bundle.getMessage("ErrorTitle"), // NOI18N
1630                                JmriJOptionPane.ERROR_MESSAGE);
1631                        return false;
1632                    }
1633                    _curVariable.setType(type);
1634                    _curVariable.setDataString(appStr);
1635                    log.debug("SignalHead \"{}\" of type '{}' _variableSignalBox.getSelectedItem()= {}",
1636                            name, testType, _variableSignalBox.getSelectedItem()); // NOI18N
1637                }
1638                break;
1639            case SIGNALMAST:
1640                name = _parent.validateSignalMastReference(name);
1641                if (name == null) {
1642                    return false;
1643                }
1644                if (testType == Conditional.Type.SIGNAL_MAST_ASPECT_EQUALS) {
1645                    if (_variableSignalBox.getSelectedIndex() < 0) {
1646                        JmriJOptionPane.showMessageDialog(this,
1647                                Bundle.getMessage("ErrorAspect"),
1648                                Bundle.getMessage("ErrorTitle"), // NOI18N
1649                                JmriJOptionPane.ERROR_MESSAGE);
1650                        return false;
1651                    }
1652                    // save the selected aspect for comparison
1653                    _curVariable.setDataString((String) _variableSignalBox.getSelectedItem());
1654                    //                _curVariable.setType(ConditionalVariable.stringToVariableTest(appStr));
1655                }
1656                break;
1657            case WARRANT:
1658                name = _parent.validateWarrantReference(name);
1659                if (name == null) {
1660                    return false;
1661                }
1662                break;
1663            case OBLOCK:
1664                name = _parent.validateOBlockReference(name);
1665                if (name == null) {
1666                    return false;
1667                }
1668                String str = _variableStateBox.getSelectedItem().toString();
1669                _curVariable.setDataString(OBlock.getSystemStatusName(str));
1670                log.debug("OBlock \"{}\" of type '{}' _variableStateBox.getSelectedItem()= {}",
1671                        name, testType, _variableStateBox.getSelectedItem()); // NOI18N
1672                break;
1673            case ENTRYEXIT:
1674                name = _parent.validateEntryExitReference(name);
1675                if (name == null) {
1676                    return false;
1677                }
1678                break;
1679            default:
1680                JmriJOptionPane.showMessageDialog(this,
1681                        Bundle.getMessage("ErrorVariableType"),
1682                        Bundle.getMessage("ErrorTitle"), // NOI18N
1683                        JmriJOptionPane.ERROR_MESSAGE);
1684                return false;
1685        }
1686        _curVariable.setName(name);
1687        boolean result = _curVariable.evaluate();
1688        log.debug("State Variable \"{}\" of type '{}' state= {} type= {}",  // NOI18N
1689                name, testType.getTestTypeString(), result, _curVariable.getType());
1690        if (_curVariable.getType() == Conditional.Type.NONE) {
1691            JmriJOptionPane.showMessageDialog(this,
1692                    Bundle.getMessage("ErrorVariableState"),
1693                    Bundle.getMessage("ErrorTitle"), // NOI18N
1694                    JmriJOptionPane.ERROR_MESSAGE);
1695            return false;
1696        }
1697        return (true);
1698    }
1699
1700    // ------------ Variable detail listeners ------------
1701
1702    transient ActionListener variableSignalTestStateListener = new ActionListener() {
1703        @Override
1704        public void actionPerformed(ActionEvent e) {
1705            log.debug("variableSignalTestStateListener fires; _variableItemBox.getSelectedIndex()= \"{}\" _variableStateBox.getSelectedIndex()= \"{}\"", // NOI18N
1706                    _variableItemBox.getSelectedIndex(), _variableStateBox.getSelectedIndex());
1707
1708            Conditional.ItemType itemType = _variableItemBox.getItemAt(_variableItemBox.getSelectedIndex());
1709
1710            if (_variableStateBox.getSelectedIndex() == 1) {
1711                if (itemType == Conditional.ItemType.SIGNALHEAD) {
1712                    loadJComboBoxWithHeadAppearances(_variableSignalBox, _variableNameField.getText().trim());
1713                    _variableSignalPanel.setVisible(true);
1714                } else if (itemType == Conditional.ItemType.SIGNALMAST) {
1715                    loadJComboBoxWithMastAspects(_variableSignalBox, _variableNameField.getText().trim());
1716                    _variableSignalPanel.setVisible(true);
1717                } else {
1718                    _variableSignalPanel.setVisible(false);
1719                }
1720            } else {
1721                _variableSignalPanel.setVisible(false);
1722            }
1723
1724            _variableSignalBox.setMaximumSize(_variableSignalBox.getPreferredSize());
1725            if (_editVariableFrame != null) {
1726                _editVariableFrame.pack();
1727            }
1728            _dataChanged = true;
1729        }
1730    };
1731
1732    transient ActionListener variableSignalHeadNameListener = new ActionListener() {
1733        @Override
1734        public void actionPerformed(ActionEvent e) {
1735            // fired when signal head name changes, but only
1736            // while in signal head mode
1737            log.debug("variableSignalHeadNameListener fires; _variableNameField: {}", _variableNameField.getText().trim());
1738            loadJComboBoxWithHeadAppearances(_variableSignalBox, _variableNameField.getText().trim());
1739            _dataChanged = true;
1740        }
1741    };
1742
1743    transient ActionListener variableSignalMastNameListener = new ActionListener() {
1744        @Override
1745        public void actionPerformed(ActionEvent e) {
1746            // fired when signal mast name changes, but only
1747            // while in signal mast mode
1748            log.debug("variableSignalMastNameListener fires; _variableNameField: {}", _variableNameField.getText().trim());  // NOI18N
1749            loadJComboBoxWithMastAspects(_variableSignalBox, _variableNameField.getText().trim());
1750            _dataChanged = true;
1751        }
1752    };
1753
1754    transient ActionListener selectLogixBoxListener = new ActionListener() {
1755        @Override
1756        public void actionPerformed(ActionEvent e) {
1757            String lgxItem = (String) _selectLogixBox.getSelectedItem();
1758            if (lgxItem != null) {
1759                String lgxName = _selectLogixMap.get(lgxItem);
1760                if (lgxName != null) {
1761                    loadSelectConditionalBox(lgxName, _curVariable);
1762                }
1763            }
1764            _dataChanged = true;
1765        }
1766    };
1767
1768    transient ActionListener selectConditionalBoxListener = new ActionListener() {
1769        @Override
1770        public void actionPerformed(ActionEvent e) {
1771            int cdlIndex = _selectConditionalBox.getSelectedIndex();
1772            if (cdlIndex > 0 && cdlIndex < _selectConditionalList.size()) {
1773                String cdlName = _selectConditionalList.get(cdlIndex);
1774                _variableNameField.setText(cdlName);
1775            }
1776            _dataChanged = true;
1777        }
1778    };
1779
1780    // ============ Edit Action Window and Methods ============
1781
1782    /**
1783     * Create and/or initialize the Edit Action window.
1784     * <p>
1785     * Note: you can get here via the New Action button (addActionPressed) or
1786     * via an Edit button in the Action table of the EditConditional window.
1787     *
1788     * @param row index in the table of the Action to be edited
1789     */
1790    void makeEditActionWindow(int row) {
1791        if (alreadyEditingActionOrVariable()) {
1792            return;
1793        }
1794        log.debug("makeEditActionWindow: row = {}", row);
1795        _curActionRowNumber = row;
1796        _curAction = _actionList.get(row);
1797        _editActionFrame = new JmriJFrame(Bundle.getMessage("TitleEditAction"), true, true);  // NOI18N
1798        _editActionFrame.addHelpMenu(
1799                "package.jmri.jmrit.conditional.StateVariableActionList", true);  // NOI18N
1800        JPanel topPanel = makeTopPanel(_editActionFrame, "TitleConsequentPhrase", 600, 160);  // NOI18N
1801
1802        Box panel1 = Box.createHorizontalBox();
1803        panel1.add(Box.createHorizontalGlue());
1804
1805        _actionItemBox = new JComboBox<>();
1806        for (Conditional.ItemType itemType : Conditional.ItemType.values()) {
1807            _actionItemBox.addItem(itemType);
1808        }
1809        JComboBoxUtil.setupComboBoxMaxRows(_actionItemBox);
1810        panel1.add(makeEditPanel(_actionItemBox, "LabelActionItem", "ActionItemHint"));  // NOI18N
1811        panel1.add(Box.createHorizontalStrut(STRUT));
1812
1813        _actionNameField = new JTextField(30);
1814        _actionNamePanel = makeEditPanel(_actionNameField, "LabelItemName", null);  // NOI18N
1815        _actionNamePanel.setMaximumSize(
1816                new Dimension(50, _actionNamePanel.getPreferredSize().height));
1817        _actionNamePanel.setVisible(false);
1818        panel1.add(_actionNamePanel);
1819        panel1.add(Box.createHorizontalStrut(STRUT));
1820
1821        // Arbitrary name combo box to facilitate the panel construction
1822        if (_parent._selectionMode == SelectionMode.USECOMBO) {
1823            _comboNameBox = _parent.createNameBox(Conditional.ItemType.SENSOR);
1824            _actionComboNamePanel = makeEditPanel(_comboNameBox, "LabelItemName", null);  // NOI18N
1825            _actionComboNamePanel.setVisible(false);
1826            panel1.add(_actionComboNamePanel);
1827            panel1.add(Box.createHorizontalStrut(STRUT));
1828        }
1829
1830        _actionTypeBox = new JComboBox<>();
1831        JComboBoxUtil.setupComboBoxMaxRows(_actionTypeBox);
1832        _actionTypeBox.addItem(Conditional.Action.NONE);
1833        _actionTypePanel = makeEditPanel(_actionTypeBox, "LabelActionType", "ActionTypeHint");  // NOI18N
1834        _actionTypePanel.setVisible(false);
1835        panel1.add(_actionTypePanel);
1836        panel1.add(Box.createHorizontalStrut(STRUT));
1837
1838        _actionBox = new JComboBox<String>();
1839        _actionBox.addItem("");
1840        _actionPanel = makeEditPanel(_actionBox, "LabelActionType", "ActionTypeHint");  // NOI18N
1841        _actionPanel.setVisible(false);
1842        panel1.add(_actionPanel);
1843        panel1.add(Box.createHorizontalStrut(STRUT));
1844
1845        _shortActionString = new JTextField(15);
1846        _shortTextPanel = makeEditPanel(_shortActionString, "LabelActionText", null);  // NOI18N
1847        _shortTextPanel.setMaximumSize(
1848                new Dimension(25, _shortTextPanel.getPreferredSize().height));
1849        _shortTextPanel.add(Box.createVerticalGlue());
1850        _shortTextPanel.setVisible(false);
1851        panel1.add(_shortTextPanel);
1852        panel1.add(Box.createHorizontalStrut(STRUT));
1853
1854        _actionOptionBox = new JComboBox<String>();
1855        for (int i = 1; i <= Conditional.NUM_ACTION_OPTIONS; i++) {
1856            _actionOptionBox.addItem(DefaultConditionalAction.getOptionString(i, _triggerOnChangeButton.isSelected()));
1857        }
1858        _optionPanel = makeEditPanel(_actionOptionBox, "LabelActionOption", "ActionOptionHint");  // NOI18N
1859        _optionPanel.setVisible(false);
1860        panel1.add(_optionPanel);
1861        panel1.add(Box.createHorizontalStrut(STRUT));
1862
1863        panel1.add(Box.createHorizontalGlue());
1864        topPanel.add(panel1);
1865        topPanel.add(Box.createVerticalStrut(5));
1866        topPanel.add(Box.createVerticalGlue());
1867
1868        Box panel2 = Box.createHorizontalBox();
1869        panel2.add(Box.createHorizontalGlue());
1870
1871        _setPanel = new JPanel();
1872        _setPanel.setLayout(new BoxLayout(_setPanel, BoxLayout.Y_AXIS));
1873        JPanel p = new JPanel();
1874        p.add(new JLabel(Bundle.getMessage("LabelActionFile")));  // NOI18N
1875        _setPanel.add(p);
1876        JButton _actionSetButton = new JButton("..."); // "File" replaced by ...
1877        _actionSetButton.setMaximumSize(_actionSetButton.getPreferredSize());
1878        _actionSetButton.setToolTipText(Bundle.getMessage("FileButtonHint"));  // NOI18N
1879        _actionSetButton.addActionListener(new ActionListener() {
1880            @Override
1881            public void actionPerformed(ActionEvent e) {
1882                validateAction();
1883                setFileLocation(e);
1884            }
1885        });
1886        _setPanel.add(_actionSetButton);
1887        _setPanel.add(Box.createVerticalGlue());
1888        _setPanel.setVisible(false);
1889        panel2.add(_setPanel);
1890        panel2.add(Box.createHorizontalStrut(5));
1891
1892        _longActionString = new JTextField(50);
1893        _textPanel = makeEditPanel(_longActionString, "LabelActionText", null);  // NOI18N
1894        _textPanel.setMaximumSize(
1895                new Dimension(80, _textPanel.getPreferredSize().height));
1896        _textPanel.add(Box.createVerticalGlue());
1897        _textPanel.setVisible(false);
1898        panel2.add(_textPanel);
1899        panel2.add(Box.createHorizontalGlue());
1900        topPanel.add(panel2);
1901        topPanel.add(Box.createVerticalStrut(5));
1902        topPanel.add(Box.createVerticalGlue());
1903
1904        ActionListener updateListener = new ActionListener() {
1905            @Override
1906            public void actionPerformed(ActionEvent e) {
1907                updateActionPressed();
1908            }
1909        };
1910        ActionListener cancelListener = new ActionListener() {
1911            @Override
1912            public void actionPerformed(ActionEvent e) {
1913                cancelEditActionPressed();
1914            }
1915        };
1916        ActionListener deleteListener = new ActionListener() {
1917            @Override
1918            public void actionPerformed(ActionEvent e) {
1919                deleteActionPressed();
1920            }
1921        };
1922        JPanel panel = makeButtonPanel(updateListener, cancelListener, deleteListener);
1923        topPanel.add(panel);
1924        topPanel.add(Box.createVerticalGlue());
1925
1926        Container contentPane = _editActionFrame.getContentPane();
1927        contentPane.add(topPanel);
1928
1929        _actionItemBox.addActionListener(new ActionListener() {
1930            @Override
1931            public void actionPerformed(ActionEvent e) {
1932                Conditional.ItemType newActionItem = _actionItemBox.getItemAt(_actionItemBox.getSelectedIndex());
1933                log.debug("_actionItemBox Listener: new = {}, curr = {}, row = {}",  // NOI18N
1934                        newActionItem, _curActionItem, _curActionRowNumber);
1935                if (newActionItem != _curActionItem) {
1936                    if (_curActionRowNumber >= 0) {
1937                        _curAction = new DefaultConditionalAction();
1938                        _actionList.set(_curActionRowNumber, _curAction);
1939                    }
1940                    _curActionItem = newActionItem;
1941                }
1942                _dataChanged = true;
1943                actionItemChanged(newActionItem);
1944                _editActionFrame.pack();
1945            }
1946        });
1947        // setup window closing listener
1948        _editActionFrame.addWindowListener(
1949                new java.awt.event.WindowAdapter() {
1950            @Override
1951            public void windowClosing(java.awt.event.WindowEvent e) {
1952                cancelEditActionPressed();
1953            }
1954        });
1955        _curActionItem = _curAction.getType().getItemType();
1956        initializeActionVariables();
1957        _dataChanged = false;
1958        _editActionFrame.setVisible(true);
1959        _editActionFrame.pack();
1960    }
1961
1962    // ----------------- utilities for logix and Conditional variables
1963
1964    /**
1965     * Load the Logix selection box. Set the selection to the current Logix.
1966     *
1967     * @since 4.7.4
1968     * @param curVariable Current ConditionalVariable
1969     */
1970    void loadSelectLogixBox(ConditionalVariable curVariable) {
1971        // Get the current Logix name for selecting the current combo box row
1972        String cdlName = curVariable.getName();
1973        String lgxName;
1974        if (cdlName.length() == 0 || (curVariable.getType() != Conditional.Type.CONDITIONAL_TRUE
1975                && curVariable.getType() != Conditional.Type.CONDITIONAL_FALSE)) {
1976            // Use the current logix name for "add" state variable
1977            lgxName = _parent._curLogix.getSystemName();
1978        } else {
1979            Logix x = _parent._conditionalManager.getParentLogix(cdlName);
1980            if (x == null) {
1981                log.error("Unable to find the Logix for {}, using the current Logix", cdlName);  // NOI18N
1982                lgxName = _parent._curLogix.getSystemName();
1983            } else {
1984                lgxName = x.getSystemName();
1985            }
1986        }
1987
1988        _selectLogixBox.removeAllItems();
1989        _selectLogixMap.clear();
1990
1991        // Create Logix list sorted by a custom display name
1992        String itemKey = "";
1993        for (Logix lgx : _parent._logixManager.getNamedBeanSet()) {
1994            String sName = lgx.getSystemName();
1995            if (sName.equals("SYS")) {  // NOI18N
1996                // Cannot refer to sensor name groups
1997                continue;
1998            }
1999            String uName = lgx.getUserName();
2000            String itemName = "";
2001            if (uName == null || uName.length() < 1) {
2002                itemName = sName;
2003            } else {
2004                itemName = uName + " ( " + sName + " )";
2005            }
2006            _selectLogixMap.put(itemName, sName);
2007            if (lgxName.equals(sName)) {
2008                itemKey = itemName;
2009            }
2010        }
2011
2012        // Load the combo box
2013        for (String item : _selectLogixMap.keySet()) {
2014            _selectLogixBox.addItem(item);
2015        }
2016
2017        JComboBoxUtil.setupComboBoxMaxRows(_selectLogixBox);
2018        _selectLogixBox.setSelectedItem(itemKey);
2019        loadSelectConditionalBox(lgxName, curVariable);
2020    }
2021
2022    /**
2023     * Load the Conditional selection box. The first row is a prompt.
2024     *
2025     * @since 4.7.4
2026     * @param logixName The Logix system name for selecting the owned
2027     *                  Conditionals
2028     * @param curVariable Current ConditionalVariable
2029     */
2030    void loadSelectConditionalBox(String logixName, ConditionalVariable curVariable) {
2031        // Get the current Conditional name for selecting the current combo box row
2032        String cdlName = curVariable.getName();
2033
2034        _selectConditionalBox.removeAllItems();
2035        _selectConditionalList.clear();
2036
2037        // Create the first row
2038        String itemKey = Bundle.getMessage("SelectFirstRow");  // NOI18N
2039        _selectConditionalBox.addItem(itemKey);
2040        _selectConditionalList.add("-None-");  // NOI18N
2041
2042        Logix x = _parent._logixManager.getBySystemName(logixName);
2043        if (x == null) {
2044            log.error("Logix '{}' not found while building the conditional list", logixName);  // NOI18N
2045            return;
2046        }
2047        if (x.getNumConditionals() == 0) {
2048            return;
2049        }
2050        for (String cName : _parent._conditionalManager.getSystemNameListForLogix(x)) {
2051            Conditional c = _parent._conditionalManager.getConditional(cName);
2052            if (_parent._curConditional.getSystemName().equals(c.getSystemName())) {
2053                // Don't add myself to the list
2054                continue;
2055            }
2056            String uName = c.getUserName();
2057            String itemName = "";
2058            if (uName == null || uName.length() < 1) {
2059                itemName = cName;
2060            } else {
2061                itemName = uName + " ( " + cName + " )";
2062            }
2063            _selectConditionalBox.addItem(itemName);
2064            _selectConditionalList.add(cName);
2065            if (cdlName.equals(cName)) {
2066                itemKey = itemName;
2067            }
2068        }
2069        JComboBoxUtil.setupComboBoxMaxRows(_selectConditionalBox);
2070        _selectConditionalBox.setSelectedItem(itemKey);
2071    }
2072
2073    // ------------ Main Action methods ------------
2074
2075    /**
2076     * Set display to show current action (curAction) parameters.
2077     */
2078    void initializeActionVariables() {
2079        Conditional.Action actionType = _curAction.getType();
2080        Conditional.ItemType itemType = actionType.getItemType();
2081        if (log.isDebugEnabled()) {
2082            log.debug("initializeActionVariables: itemType = {}, actionType = {}", itemType, actionType);  // NOI18N
2083        }
2084        if (actionType == Conditional.Action.NONE) {
2085            return;
2086        }
2087        _actionItemBox.setSelectedItem(itemType);
2088        _actionNameField.setText(_curAction.getDeviceName());
2089        switch (itemType) {
2090            case SENSOR:
2091                _actionTypeBox.setSelectedItem(actionType);
2092                if ((actionType == Conditional.Action.RESET_DELAYED_SENSOR)
2093                        || (actionType == Conditional.Action.DELAYED_SENSOR)) {
2094                    _shortActionString.setText(_curAction.getActionString());
2095                }
2096                if (actionType == Conditional.Action.SET_SENSOR
2097                        || actionType == Conditional.Action.DELAYED_SENSOR
2098                        || actionType == Conditional.Action.RESET_DELAYED_SENSOR) {
2099                    if (_curAction.getActionData() == Sensor.ACTIVE) {
2100                        _actionBox.setSelectedIndex(0);
2101                    } else if (_curAction.getActionData() == Sensor.INACTIVE) {
2102                        _actionBox.setSelectedIndex(1);
2103                    } else if (_curAction.getActionData() == Route.TOGGLE) {
2104                        _actionBox.setSelectedIndex(2);
2105                    }
2106                }
2107                break;
2108
2109            case TURNOUT:
2110                _actionTypeBox.setSelectedItem(actionType);
2111                if ((actionType == Conditional.Action.RESET_DELAYED_TURNOUT)
2112                        || (actionType == Conditional.Action.DELAYED_TURNOUT)) {
2113                    _shortActionString.setText(_curAction.getActionString());
2114                }
2115                if ((actionType == Conditional.Action.SET_TURNOUT)
2116                        || (actionType == Conditional.Action.RESET_DELAYED_TURNOUT)
2117                        || (actionType == Conditional.Action.DELAYED_TURNOUT)) {
2118                    if (_curAction.getActionData() == Turnout.CLOSED) {
2119                        _actionBox.setSelectedIndex(0);
2120                    } else if (_curAction.getActionData() == Turnout.THROWN) {
2121                        _actionBox.setSelectedIndex(1);
2122                    } else if (_curAction.getActionData() == Route.TOGGLE) {
2123                        _actionBox.setSelectedIndex(2);
2124                    }
2125                } else if (actionType == Conditional.Action.LOCK_TURNOUT) {
2126                    if (_curAction.getActionData() == Turnout.UNLOCKED) {
2127                        _actionBox.setSelectedIndex(0);
2128                    } else if (_curAction.getActionData() == Turnout.LOCKED) {
2129                        _actionBox.setSelectedIndex(1);
2130                    } else if (_curAction.getActionData() == Route.TOGGLE) {
2131                        _actionBox.setSelectedIndex(2);
2132                    }
2133                }
2134                break;
2135
2136            case LIGHT:
2137                _actionTypeBox.setSelectedItem(actionType);
2138                if (actionType == Conditional.Action.SET_LIGHT) {
2139                    if (_curAction.getActionData() == Light.ON) {
2140                        _actionBox.setSelectedIndex(0);
2141                    } else if (_curAction.getActionData() == Light.OFF) {
2142                        _actionBox.setSelectedIndex(1);
2143                    } else if (_curAction.getActionData() == Route.TOGGLE) {
2144                        _actionBox.setSelectedIndex(2);
2145                    }
2146                } else if ((actionType == Conditional.Action.SET_LIGHT_INTENSITY)
2147                        || (actionType == Conditional.Action.SET_LIGHT_TRANSITION_TIME)) {
2148                    _shortActionString.setText(_curAction.getActionString());
2149                }
2150                break;
2151
2152            case CLOCK:
2153                _actionTypeBox.setSelectedItem(actionType);
2154                if (actionType == Conditional.Action.SET_FAST_CLOCK_TIME) {
2155                    int time = _curAction.getActionData();
2156                    _longActionString.setText(ConditionalEditBase.formatTime(time / 60, time - ((time / 60) * 60)));
2157                    _actionNameField.setText("");
2158                }
2159                break;
2160
2161            case MEMORY:
2162                _actionTypeBox.setSelectedItem(actionType);
2163                _shortActionString.setText(_curAction.getActionString());
2164                break;
2165
2166
2167            case WARRANT:
2168                _actionTypeBox.setSelectedItem(actionType);
2169                if (actionType == Conditional.Action.CONTROL_TRAIN) {
2170                    switch (_curAction.getActionData()) {
2171                        case Warrant.HALT:
2172                            _actionBox.setSelectedIndex(0);
2173                            break;
2174                        case Warrant.RESUME:
2175                            _actionBox.setSelectedIndex(1);
2176                            break;
2177                        case Warrant.RETRY_FWD:
2178                            _actionBox.setSelectedIndex(2);
2179                            break;
2180                        case Warrant.SPEED_UP:
2181                            _actionBox.setSelectedIndex(3);
2182                            break;
2183                        case Warrant.STOP:
2184                            _actionBox.setSelectedIndex(4);
2185                            break;
2186                        case Warrant.ESTOP:
2187                            _actionBox.setSelectedIndex(5);
2188                            break;
2189                        case Warrant.ABORT:
2190                            _actionBox.setSelectedIndex(6);
2191                            break;
2192                        default:
2193                            log.warn("Unexpected _curAction.getActionData() of {}", _curAction.getActionData());  // NOI18N
2194                    }
2195                } else if (actionType == Conditional.Action.SET_TRAIN_ID
2196                        || actionType == Conditional.Action.SET_TRAIN_NAME
2197                        || actionType == Conditional.Action.GET_TRAIN_LOCATION) {
2198                    _shortActionString.setText(_curAction.getActionString());
2199                }
2200                break;
2201
2202            case OBLOCK:
2203                _actionTypeBox.setSelectedItem(actionType);
2204                if (actionType == Conditional.Action.SET_BLOCK_VALUE
2205                        || actionType == Conditional.Action.GET_BLOCK_TRAIN_NAME
2206                        || actionType == Conditional.Action.GET_BLOCK_WARRANT) {
2207                    _shortActionString.setText(_curAction.getActionString());
2208                }
2209                break;
2210
2211            case ENTRYEXIT:
2212                _actionTypeBox.setSelectedItem(actionType);
2213                _actionNameField.setText(_curAction.getBean().getUserName());
2214                break;
2215
2216            case AUDIO:
2217                _actionTypeBox.setSelectedItem(actionType);
2218                if (actionType == Conditional.Action.PLAY_SOUND) {
2219                    _longActionString.setText(_curAction.getActionString());
2220                } else if (actionType == Conditional.Action.CONTROL_AUDIO) {
2221                    switch (_curAction.getActionData()) {
2222                        case Audio.CMD_PLAY:
2223                            _actionBox.setSelectedIndex(0);
2224                            break;
2225                        case Audio.CMD_STOP:
2226                            _actionBox.setSelectedIndex(1);
2227                            break;
2228                        case Audio.CMD_PLAY_TOGGLE:
2229                            _actionBox.setSelectedIndex(2);
2230                            break;
2231                        case Audio.CMD_PAUSE:
2232                            _actionBox.setSelectedIndex(3);
2233                            break;
2234                        case Audio.CMD_RESUME:
2235                            _actionBox.setSelectedIndex(4);
2236                            break;
2237                        case Audio.CMD_PAUSE_TOGGLE:
2238                            _actionBox.setSelectedIndex(5);
2239                            break;
2240                        case Audio.CMD_REWIND:
2241                            _actionBox.setSelectedIndex(6);
2242                            break;
2243                        case Audio.CMD_FADE_IN:
2244                            _actionBox.setSelectedIndex(7);
2245                            break;
2246                        case Audio.CMD_FADE_OUT:
2247                            _actionBox.setSelectedIndex(8);
2248                            break;
2249                        case Audio.CMD_RESET_POSITION:
2250                            _actionBox.setSelectedIndex(9);
2251                            break;
2252                        default:
2253                            log.warn("Unexpected _curAction.getActionData() of {}", _curAction.getActionData());  // NOI18N
2254                            break;
2255                    }
2256                }
2257                break;
2258
2259            case SCRIPT:
2260                _actionTypeBox.setSelectedItem(actionType);
2261                if (actionType == Conditional.Action.RUN_SCRIPT) {
2262                    _longActionString.setText(_curAction.getActionString());
2263                } else if (actionType == Conditional.Action.JYTHON_COMMAND) {
2264                    _shortActionString.setText(_curAction.getActionString());
2265                }
2266                break;
2267
2268            case SIGNALHEAD:
2269            case SIGNALMAST:
2270            case LOGIX:
2271            case OTHER: // ACTION_TRIGGER_ROUTE
2272                _actionTypeBox.setSelectedItem(actionType);
2273                break;
2274
2275            default:
2276                log.error("Unhandled type: {}", itemType);  // NOI18N
2277                break;
2278        }
2279        _actionOptionBox.setSelectedIndex(_curAction.getOption() - 1);
2280        _editActionFrame.pack();
2281        _editActionFrame.transferFocusBackward();
2282    }
2283
2284    /**
2285     * Respond to a change in an Action Type comboBox on the Edit Conditional
2286     * Action pane.
2287     * <p>
2288     * Set components visible for the selected type.
2289     *
2290     * @param type index of the newly selected Action type
2291     */
2292    void actionItemChanged(Conditional.ItemType type) {
2293        Conditional.Action actionType = _curAction.getType();
2294        if (log.isDebugEnabled()) {
2295            log.debug("actionItemChanged: itemType = {}, actionType = {}", type, actionType);  // NOI18N
2296        }
2297        _actionTypeBox.removeActionListener(_actionTypeListener);
2298        _actionTypePanel.setVisible(false);
2299        _setPanel.setVisible(false);
2300        _shortTextPanel.setVisible(false);
2301        _shortActionString.setText("");
2302        _textPanel.setVisible(false);
2303        _longActionString.setText("");
2304        _actionNamePanel.setVisible(false);
2305        _actionPanel.setVisible(false);
2306        _optionPanel.setVisible(false);
2307        Conditional.ItemType itemType = actionType.getItemType();
2308        if (type == Conditional.ItemType.NONE && itemType == Conditional.ItemType.NONE) {
2309            return;
2310        }
2311        _actionTypePanel.setVisible(true);
2312        _actionTypeBox.removeAllItems();
2313        _actionBox.removeAllItems();
2314        if (type != Conditional.ItemType.NONE) {  // actionItem listener choice overrides current item
2315            itemType = type;
2316        }
2317        if (itemType != actionType.getItemType()) {
2318            actionType = Conditional.Action.NONE;    // chosen item type does not support action type
2319        }
2320        if (actionType != Conditional.Action.NONE) {
2321            _optionPanel.setVisible(true);    // item type compatible with action type
2322        }
2323        _actionTypeBox.addItem(Conditional.Action.NONE);
2324        _actionNameField.removeActionListener(actionSignalHeadNameListener);
2325        _actionNameField.removeActionListener(actionSignalMastNameListener);
2326
2327        if (_parent._selectionMode == SelectionMode.USECOMBO) {
2328            _actionComboNamePanel.setVisible(false);
2329        } else if (_parent._selectionMode == SelectionMode.USESINGLE) {
2330            _parent.createSinglePanelPickList(itemType, _parent.getPickSingleListener(_actionNameField, itemType), true);
2331        } else {
2332            // Default and USEMULTI
2333            _parent.setPickListTab(itemType, true);
2334        }
2335
2336        switch (itemType) {
2337            case TURNOUT:
2338                for (Conditional.Action action : Conditional.Action.getTurnoutItems()) {
2339                    _actionTypeBox.addItem(action);
2340                }
2341                if ((actionType == Conditional.Action.RESET_DELAYED_TURNOUT)
2342                        || (actionType == Conditional.Action.DELAYED_TURNOUT)) {
2343                    JPanel p = (JPanel) _shortTextPanel.getComponent(0);
2344                    JLabel l = (JLabel) p.getComponent(0);
2345                    l.setText(Bundle.getMessage("LabelDelayTime"));  // NOI18N
2346                    _shortTextPanel.setToolTipText(Bundle.getMessage("DataHintDelayedTurnout"));  // NOI18N
2347                    _shortTextPanel.setVisible(true);
2348                }
2349                JPanel panel = (JPanel) _actionPanel.getComponent(0);
2350                JLabel label = (JLabel) panel.getComponent(0);
2351                if ((actionType == Conditional.Action.SET_TURNOUT)
2352                        || (actionType == Conditional.Action.RESET_DELAYED_TURNOUT)
2353                        || (actionType == Conditional.Action.DELAYED_TURNOUT)) {
2354                    label.setText(Bundle.getMessage("LabelActionTurnout"));  // NOI18N
2355                    _actionBox.addItem(Bundle.getMessage("TurnoutStateClosed"));  // NOI18N
2356                    _actionBox.addItem(Bundle.getMessage("TurnoutStateThrown"));  // NOI18N
2357                    _actionBox.addItem(Bundle.getMessage("Toggle"));  // NOI18N
2358                    _actionPanel.setToolTipText(Bundle.getMessage("TurnoutSetHint"));  // NOI18N
2359                    _actionPanel.setVisible(true);
2360                } else if (actionType == Conditional.Action.LOCK_TURNOUT) {
2361                    label.setText(Bundle.getMessage("LabelActionLock"));  // NOI18N
2362                    _actionBox.addItem(Bundle.getMessage("TurnoutUnlock"));  // NOI18N
2363                    _actionBox.addItem(Bundle.getMessage("TurnoutLock"));  // NOI18N
2364                    _actionBox.addItem(Bundle.getMessage("Toggle"));  // NOI18N
2365                    _actionPanel.setToolTipText(Bundle.getMessage("LockSetHint"));  // NOI18N
2366                    _actionPanel.setVisible(true);
2367                }
2368                _actionNamePanel.setToolTipText(Bundle.getMessage("NameHintTurnout"));  // NOI18N
2369                _actionNamePanel.setVisible(true);
2370                setActionNameBox(itemType);
2371                break;
2372
2373            case SENSOR:
2374                for (Conditional.Action action : Conditional.Action.getSensorItems()) {
2375                    _actionTypeBox.addItem(action);
2376                }
2377                if ((actionType == Conditional.Action.RESET_DELAYED_SENSOR)
2378                        || (actionType == Conditional.Action.DELAYED_SENSOR)) {
2379                    JPanel p = (JPanel) _shortTextPanel.getComponent(0);
2380                    JLabel l = (JLabel) p.getComponent(0);
2381                    l.setText(Bundle.getMessage("LabelDelayTime"));  // NOI18N
2382                    _shortTextPanel.setToolTipText(Bundle.getMessage("DataHintDelayedTurnout"));  // NOI18N
2383                    _shortTextPanel.setVisible(true);
2384                }
2385                if ((actionType == Conditional.Action.SET_SENSOR)
2386                        || (actionType == Conditional.Action.RESET_DELAYED_SENSOR)
2387                        || (actionType == Conditional.Action.DELAYED_SENSOR)) {
2388                    JPanel p = (JPanel) _actionPanel.getComponent(0);
2389                    JLabel l = (JLabel) p.getComponent(0);
2390                    l.setText(Bundle.getMessage("LabelActionSensor"));  // NOI18N
2391                    _actionBox.addItem(Bundle.getMessage("SensorStateActive"));  // NOI18N
2392                    _actionBox.addItem(Bundle.getMessage("SensorStateInactive"));  // NOI18N
2393                    _actionBox.addItem(Bundle.getMessage("Toggle"));  // NOI18N
2394                    _actionPanel.setToolTipText(Bundle.getMessage("SensorSetHint"));  // NOI18N
2395                    _actionPanel.setVisible(true);
2396                }
2397                _actionNamePanel.setToolTipText(Bundle.getMessage("NameHintSensor"));  // NOI18N
2398                _actionNamePanel.setVisible(true);
2399                setActionNameBox(itemType);
2400                break;
2401
2402            case SIGNALHEAD:
2403                for (Conditional.Action action : Conditional.Action.getSignalHeadItems()) {
2404                    _actionTypeBox.addItem(action);
2405                }
2406                if (actionType == Conditional.Action.SET_SIGNAL_APPEARANCE) {
2407                    JPanel p = (JPanel) _actionPanel.getComponent(0);
2408                    JLabel l = (JLabel) p.getComponent(0);
2409                    l.setText(Bundle.getMessage("LabelActionSignal"));  // NOI18N
2410                    loadJComboBoxWithHeadAppearances(_actionBox, _actionNameField.getText().trim());
2411                    _actionBox.setSelectedItem(_curAction.getActionDataString());
2412                    _actionPanel.setToolTipText(Bundle.getMessage("SignalSetHint"));  // NOI18N
2413                    _actionPanel.setVisible(true);
2414                }
2415                _actionNamePanel.setToolTipText(Bundle.getMessage("NameHintSignal"));  // NOI18N
2416                _actionNamePanel.setVisible(true);
2417                setActionNameBox(itemType);
2418                _actionNameField.addActionListener(actionSignalHeadNameListener);
2419                break;
2420
2421            case SIGNALMAST:
2422                for (Conditional.Action action : Conditional.Action.getSignalMastItems()) {
2423                    _actionTypeBox.addItem(action);
2424                }
2425                if (actionType == Conditional.Action.SET_SIGNALMAST_ASPECT) {
2426                    JPanel p = (JPanel) _actionPanel.getComponent(0);
2427                    JLabel l = (JLabel) p.getComponent(0);
2428                    l.setText(Bundle.getMessage("LabelSignalAspect"));  // NOI18N
2429                    loadJComboBoxWithMastAspects(_actionBox, _actionNameField.getText().trim());
2430                    _actionBox.setSelectedItem(_curAction.getActionString());
2431                    _actionPanel.setToolTipText(Bundle.getMessage("SignalMastSetHint"));  // NOI18N
2432                    _actionPanel.setVisible(true);
2433                }
2434                _actionNamePanel.setToolTipText(Bundle.getMessage("NameHintSignalMast"));  // NOI18N
2435                _actionNamePanel.setVisible(true);
2436                setActionNameBox(itemType);
2437                _actionNameField.addActionListener(actionSignalMastNameListener);
2438                break;
2439
2440            case LIGHT:
2441                for (Conditional.Action action : Conditional.Action.getLightItems()) {
2442                    _actionTypeBox.addItem(action);
2443                }
2444                if (actionType == Conditional.Action.SET_LIGHT_INTENSITY) {
2445                    JPanel p = (JPanel) _shortTextPanel.getComponent(0);
2446                    JLabel l = (JLabel) p.getComponent(0);
2447                    l.setText(Bundle.getMessage("LabelLightIntensity"));  // NOI18N
2448                    _shortTextPanel.setToolTipText(Bundle.getMessage("DataHintLightIntensity"));  // NOI18N
2449                    _shortTextPanel.setVisible(true);
2450                } else if (actionType == Conditional.Action.SET_LIGHT_TRANSITION_TIME) {
2451                    JPanel p = (JPanel) _shortTextPanel.getComponent(0);
2452                    JLabel l = (JLabel) p.getComponent(0);
2453                    l.setText(Bundle.getMessage("LabelTransitionTime"));  // NOI18N
2454                    _shortTextPanel.setToolTipText(Bundle.getMessage("DataHintLightTransitionTime"));  // NOI18N
2455                    _shortTextPanel.setVisible(true);
2456                } else if (actionType == Conditional.Action.SET_LIGHT) {
2457                    JPanel p = (JPanel) _actionPanel.getComponent(0);
2458                    JLabel l = (JLabel) p.getComponent(0);
2459                    l.setText(Bundle.getMessage("LabelActionLight"));  // NOI18N
2460                    _actionBox.addItem(Bundle.getMessage("LightOn"));  // NOI18N
2461                    _actionBox.addItem(Bundle.getMessage("LightOff"));  // NOI18N
2462                    _actionBox.addItem(Bundle.getMessage("Toggle"));
2463                    _actionPanel.setToolTipText(Bundle.getMessage("LightSetHint"));  // NOI18N
2464                    _actionPanel.setVisible(true);
2465                }
2466                _actionNamePanel.setToolTipText(Bundle.getMessage("NameHintLight"));  // NOI18N
2467                _actionNamePanel.setVisible(true);
2468                setActionNameBox(itemType);
2469                break;
2470
2471            case MEMORY:
2472                for (Conditional.Action action : Conditional.Action.getMemoryItems()) {
2473                    _actionTypeBox.addItem(action);
2474                }
2475                JPanel p = (JPanel) _shortTextPanel.getComponent(0);
2476                JLabel l = (JLabel) p.getComponent(0);
2477                if (actionType == Conditional.Action.COPY_MEMORY) {
2478                    _shortTextPanel.setToolTipText(Bundle.getMessage("DataHintToMemory"));  // NOI18N
2479                    l.setText(Bundle.getMessage("LabelMemoryLocation"));  // NOI18N
2480                } else {
2481                    _shortTextPanel.setToolTipText(Bundle.getMessage("DataHintMemory"));  // NOI18N
2482                    l.setText(Bundle.getMessage("LabelValue"));
2483                }
2484                _shortTextPanel.setVisible(true);
2485                _actionNamePanel.setToolTipText(Bundle.getMessage("NameHintMemory"));  // NOI18N
2486                _actionNamePanel.setVisible(true);
2487                setActionNameBox(itemType);
2488                break;
2489
2490            case CLOCK:
2491                for (Conditional.Action action : Conditional.Action.getClockItems()) {
2492                    _actionTypeBox.addItem(action);
2493                }
2494                if (actionType == Conditional.Action.SET_FAST_CLOCK_TIME) {
2495                    p = (JPanel) _textPanel.getComponent(0);
2496                    l = (JLabel) p.getComponent(0);
2497                    l.setText(Bundle.getMessage("LabelSetTime"));  // NOI18N
2498                    _textPanel.setToolTipText(Bundle.getMessage("DataHintTime"));  // NOI18N
2499                    _textPanel.setVisible(true);
2500                }
2501                break;
2502
2503            case LOGIX:
2504                for (Conditional.Action action : Conditional.Action.getLogixItems()) {
2505                    _actionTypeBox.addItem(action);
2506                }
2507                _actionNamePanel.setToolTipText(Bundle.getMessage("NameHintLogix"));  // NOI18N
2508                _actionNamePanel.setVisible(true);
2509                setActionNameBox(itemType);
2510                break;
2511
2512            case WARRANT:
2513                for (Conditional.Action action : Conditional.Action.getWarrantItems()) {
2514                    _actionTypeBox.addItem(action);
2515                }
2516                _actionNamePanel.setToolTipText(Bundle.getMessage("NameHintWarrant"));  // NOI18N
2517                _actionNamePanel.setVisible(true);
2518                if (actionType == Conditional.Action.CONTROL_TRAIN) {
2519                    p = (JPanel) _actionPanel.getComponent(0);
2520                    l = (JLabel) p.getComponent(0);
2521                    _actionBox.addItem(Bundle.getMessage("WarrantHalt"));
2522                    _actionBox.addItem(Bundle.getMessage("WarrantResume"));
2523                    _actionBox.addItem(Bundle.getMessage("WarrantMoveToNext"));
2524                    _actionBox.addItem(Bundle.getMessage("WarrantSpeedUp"));
2525                    _actionBox.addItem(Bundle.getMessage("WarrantStop"));
2526                    _actionBox.addItem(Bundle.getMessage("WarrantEStop"));
2527                    _actionBox.addItem(Bundle.getMessage("WarrantAbort"));
2528                    l.setText(Bundle.getMessage("LabelControlTrain"));  // NOI18N
2529                    _actionPanel.setVisible(true);
2530                } else if (actionType == Conditional.Action.SET_TRAIN_ID
2531                        || actionType == Conditional.Action.SET_TRAIN_NAME
2532                        || actionType == Conditional.Action.GET_TRAIN_LOCATION) {
2533                    p = (JPanel) _shortTextPanel.getComponent(0);
2534                    l = (JLabel) p.getComponent(0);
2535                    if (actionType == Conditional.Action.SET_TRAIN_ID) {
2536                        _shortTextPanel.setToolTipText(Bundle.getMessage("DataHintTrainId"));  // NOI18N
2537                        l.setText(Bundle.getMessage("LabelTrainId"));
2538                    } else if (actionType == Conditional.Action.SET_TRAIN_NAME) {
2539                        _shortTextPanel.setToolTipText(Bundle.getMessage("DataHintTrainName"));  // NOI18N
2540                        l.setText(Bundle.getMessage("LabelTrainName"));
2541                    } else if (actionType == Conditional.Action.GET_TRAIN_LOCATION) {
2542                        _shortTextPanel.setToolTipText(Bundle.getMessage("DataHintToMemory"));  // NOI18N
2543                        l.setText(Bundle.getMessage("LabelMemoryLocation"));  // NOI18N
2544                    }
2545                    _shortTextPanel.setVisible(true);
2546                }
2547                setActionNameBox(itemType);
2548                break;
2549
2550            case OBLOCK:
2551                for (Conditional.Action action : Conditional.Action.getOBlockItems()) {
2552                    _actionTypeBox.addItem(action);
2553                }
2554                _actionNamePanel.setToolTipText(Bundle.getMessage("NameHintOBlock"));  // NOI18N
2555                _actionNamePanel.setVisible(true);
2556                if (actionType == Conditional.Action.SET_BLOCK_VALUE
2557                    || actionType == Conditional.Action.GET_BLOCK_TRAIN_NAME
2558                    || actionType == Conditional.Action.GET_BLOCK_WARRANT) {
2559                    p = (JPanel) _shortTextPanel.getComponent(0);
2560                    l = (JLabel) p.getComponent(0);
2561                    if (actionType == Conditional.Action.SET_BLOCK_VALUE) {
2562                        _shortTextPanel.setToolTipText(Bundle.getMessage("DataHintBlockValue"));  // NOI18N
2563                        l.setText(Bundle.getMessage("LabelBlockValue"));  // NOI18N
2564                    } else {
2565                            _shortTextPanel.setToolTipText(Bundle.getMessage("DataHintToMemory"));  // NOI18N
2566                            l.setText(Bundle.getMessage("LabelMemoryLocation"));  // NOI18
2567                    }
2568                    _shortTextPanel.setVisible(true);
2569                }
2570                setActionNameBox(itemType);
2571                break;
2572
2573            case ENTRYEXIT:
2574                for (Conditional.Action action : Conditional.Action.getEntryExitItems()) {
2575                    _actionTypeBox.addItem(action);
2576                }
2577                _actionNamePanel.setToolTipText(Bundle.getMessage("NameHintEntryExit"));  // NOI18N
2578                _actionNamePanel.setVisible(true);
2579                setActionNameBox(itemType);
2580                break;
2581
2582            case AUDIO:
2583                for (Conditional.Action action : Conditional.Action.getAudioItems()) {
2584                    _actionTypeBox.addItem(action);
2585                }
2586                if (actionType == Conditional.Action.PLAY_SOUND) {
2587                    p = (JPanel) _textPanel.getComponent(0);
2588                    l = (JLabel) p.getComponent(0);
2589                    l.setText(Bundle.getMessage("LabelSetFile"));  // NOI18N
2590                    _textPanel.setToolTipText(Bundle.getMessage("SetHintSound"));  // NOI18N
2591                    _textPanel.setVisible(true);
2592                    _setPanel.setVisible(true);
2593                } else if (actionType == Conditional.Action.CONTROL_AUDIO) {
2594                    p = (JPanel) _actionPanel.getComponent(0);
2595                    l = (JLabel) p.getComponent(0);
2596                    l.setText(Bundle.getMessage("LabelActionAudio"));  // NOI18N
2597                    _actionBox.addItem(Bundle.getMessage("AudioSourcePlay"));  // NOI18N
2598                    _actionBox.addItem(Bundle.getMessage("AudioSourceStop"));  // NOI18N
2599                    _actionBox.addItem(Bundle.getMessage("AudioSourcePlayToggle"));  // NOI18N
2600                    _actionBox.addItem(Bundle.getMessage("AudioSourcePause"));  // NOI18N
2601                    _actionBox.addItem(Bundle.getMessage("AudioSourceResume"));  // NOI18N
2602                    _actionBox.addItem(Bundle.getMessage("AudioSourcePauseToggle"));  // NOI18N
2603                    _actionBox.addItem(Bundle.getMessage("AudioSourceRewind"));  // NOI18N
2604                    _actionBox.addItem(Bundle.getMessage("AudioSourceFadeIn"));  // NOI18N
2605                    _actionBox.addItem(Bundle.getMessage("AudioSourceFadeOut"));  // NOI18N
2606                    _actionBox.addItem(Bundle.getMessage("AudioResetPosition"));  // NOI18N
2607                    _actionPanel.setToolTipText(Bundle.getMessage("SetHintAudio"));  // NOI18N
2608                    _actionPanel.setVisible(true);
2609                    _actionNamePanel.setToolTipText(Bundle.getMessage("NameHintAudio"));  // NOI18N
2610                    _actionNamePanel.setVisible(true);
2611                }
2612                break;
2613
2614            case SCRIPT:
2615                for (Conditional.Action action : Conditional.Action.getScriptItems()) {
2616                    _actionTypeBox.addItem(action);
2617                }
2618                if (actionType == Conditional.Action.RUN_SCRIPT) {
2619                    p = (JPanel) _textPanel.getComponent(0);
2620                    l = (JLabel) p.getComponent(0);
2621                    l.setText(Bundle.getMessage("LabelSetFile"));  // NOI18N
2622                    _textPanel.setToolTipText(Bundle.getMessage("SetHintScript"));  // NOI18N
2623                    _textPanel.setVisible(true);
2624                    _setPanel.setVisible(true);
2625                } else if (actionType == Conditional.Action.JYTHON_COMMAND) {
2626                    p = (JPanel) _shortTextPanel.getComponent(0);
2627                    l = (JLabel) p.getComponent(0);
2628                    l.setText(Bundle.getMessage("LabelScriptCommand"));  // NOI18N
2629                    _shortTextPanel.setToolTipText(Bundle.getMessage("SetHintJythonCmd"));  // NOI18N
2630                    _shortTextPanel.setVisible(true);
2631                }
2632                break;
2633
2634            case OTHER:
2635                for (Conditional.Action action : Conditional.Action.getOtherItems()) {
2636                    _actionTypeBox.addItem(action);
2637                }
2638                if (actionType == Conditional.Action.TRIGGER_ROUTE) {
2639                    _actionNamePanel.setToolTipText(Bundle.getMessage("NameHintRoute"));  // NOI18N
2640                    _actionNamePanel.setVisible(true);
2641                    setActionNameBox(itemType);
2642                }
2643                break;
2644            default:
2645                break;
2646        }
2647        _actionTypeBox.setMaximumSize(_actionTypeBox.getPreferredSize());
2648        _actionBox.setMaximumSize(_actionBox.getPreferredSize());
2649        _actionTypeListener.setItemType(itemType);
2650        _actionTypeBox.addActionListener(_actionTypeListener);
2651        _editActionFrame.pack(); // TODO fit all components
2652    }
2653
2654    /**
2655     * Update the name combo box selection based on the current contents of the
2656     * name field. Called by {@link #actionItemChanged(Conditional.ItemType)}.
2657     *
2658     * @since 4.7.3
2659     * @param itemType The type of name box to be created.
2660     */
2661    void setActionNameBox(Conditional.ItemType itemType) {
2662        if (_parent._selectionMode != SelectionMode.USECOMBO) {
2663            return;
2664        }
2665        _comboNameBox = _parent.createNameBox(itemType);
2666        if (_comboNameBox == null) {
2667            return;
2668        }
2669        _comboNameBox.setSelectedItemByName(_curAction.getDeviceName());
2670        _comboNameBox.addActionListener(new NameBoxListener(_actionNameField));
2671        _actionComboNamePanel.remove(1);
2672        _actionComboNamePanel.add(_comboNameBox, null, 1);
2673        _actionNamePanel.setVisible(false);
2674        _actionComboNamePanel.setVisible(true);
2675    }
2676
2677    // ------------ Action detail methods ------------
2678
2679    /**
2680     * Respond to Update Action button in the Edit Action pane.
2681     */
2682    void updateActionPressed() {
2683        if (!validateAction()) {
2684            _editActionFrame.toFront();
2685            return;
2686        }
2687        _actionTableModel.fireTableRowsUpdated(_curActionRowNumber, _curActionRowNumber);
2688        cleanUpAction();
2689    }
2690
2691    /**
2692     * Respond to Cancel action button and window closer of the Edit Action
2693     * window.
2694     * <p>
2695     * Also does cleanup of Update and Delete buttons.
2696     */
2697    void cancelEditActionPressed() {
2698        if (_newItem) {
2699            deleteActionPressed(_curActionRowNumber);
2700        } else {
2701            cleanUpAction();
2702        }
2703    }
2704
2705    /**
2706     * Clean up Update and Delete Action buttons.
2707     */
2708    void cleanUpAction() {
2709        _newItem = false;
2710        if (_editActionFrame != null) {
2711            _actionTypeBox.removeActionListener(_actionTypeListener);
2712            _editActionFrame.setVisible(false);
2713            _editActionFrame.dispose();
2714            _editActionFrame = null;
2715            _parent.closeSinglePanelPickList();
2716        }
2717        _curActionRowNumber = -1;
2718    }
2719
2720    /**
2721     * Respond to Delete action button in the Edit Action window.
2722     */
2723    void deleteActionPressed() {
2724        deleteActionPressed(_curActionRowNumber);
2725    }
2726
2727    /**
2728     * Respond to Delete action button in an action row of the Edit Conditional
2729     * pane.
2730     *
2731     * @param row index in table of action to be deleted
2732     */
2733    void deleteActionPressed(int row) {
2734        if (row != _curActionRowNumber && alreadyEditingActionOrVariable()) {
2735            return;
2736        }
2737        _actionList.remove(row);
2738        _actionTableModel.fireTableRowsDeleted(row, row);
2739        cleanUpAction();
2740        _dataChanged = true;
2741    }
2742
2743    JFileChooser sndFileChooser = null;
2744    ScriptFileChooser scriptFileChooser = null;
2745    JFileChooser defaultFileChooser = null;
2746
2747    /**
2748     * Respond to the [...] button in the Edit Action window action section.
2749     * <p>
2750     * Ask user to select an audio or python script file on disk.
2751     *
2752     * @param e the event heard
2753     */
2754    void setFileLocation(ActionEvent e) {
2755        ConditionalAction action = _actionList.get(_curActionRowNumber);
2756        JFileChooser currentChooser;
2757        Conditional.Action actionType = action.getType();
2758        if (actionType == Conditional.Action.PLAY_SOUND) {
2759            if (sndFileChooser == null) {
2760                sndFileChooser = new jmri.util.swing.JmriJFileChooser(System.getProperty("user.dir") // NOI18N
2761                        + java.io.File.separator + "resources" // NOI18N
2762                        + java.io.File.separator + "sounds");  // NOI18N
2763                sndFileChooser.setFileFilter(new FileNameExtensionFilter("wav sound files", "wav")); // NOI18N
2764            }
2765            currentChooser = sndFileChooser;
2766        } else if (actionType == Conditional.Action.RUN_SCRIPT) {
2767            if (scriptFileChooser == null) {
2768                scriptFileChooser = new ScriptFileChooser(FileUtil.getScriptsPath());
2769            }
2770            currentChooser = scriptFileChooser;
2771        } else {
2772            log.warn("Unexpected actionType[{}] = {}", actionType.name(), actionType.toString());  // NOI18N
2773            if (defaultFileChooser == null) {
2774                defaultFileChooser = new jmri.util.swing.JmriJFileChooser(FileUtil.getUserFilesPath());
2775                defaultFileChooser.setFileFilter(new jmri.util.NoArchiveFileFilter());
2776            }
2777            currentChooser = defaultFileChooser;
2778        }
2779
2780        currentChooser.rescanCurrentDirectory();
2781        int retVal = currentChooser.showOpenDialog(null);
2782        // handle selection or cancel
2783        if (retVal == JFileChooser.APPROVE_OPTION) {
2784            // set selected file location in data string
2785            try {
2786                _longActionString.setText(FileUtil.getPortableFilename(currentChooser.getSelectedFile().getCanonicalPath()));
2787            } catch (java.io.IOException ex) {
2788                if (log.isDebugEnabled()) {
2789                    log.error("exception setting file location", ex);  // NOI18N
2790                }
2791                _longActionString.setText("");
2792            }
2793        }
2794    }
2795
2796    // ------------ Action update processes ------------
2797
2798    /**
2799     * Validate Action data from Edit Action Window, and transfer it to current
2800     * action object as appropriate.
2801     * <p>
2802     * Messages are sent to the user for any errors found. This routine returns
2803     * false immediately after finding an error, even if there might be more
2804     * errors.
2805     *
2806     * @return true if all data checks out OK, otherwise false
2807     */
2808    boolean validateAction() {
2809        Conditional.ItemType itemType = _actionItemBox.getItemAt(_actionItemBox.getSelectedIndex());
2810        Conditional.Action actionType = Conditional.Action.NONE;
2811        Conditional.Action selection = _actionTypeBox.getItemAt(_actionTypeBox.getSelectedIndex());
2812        if (selection == Conditional.Action.NONE) {
2813            JmriJOptionPane.showMessageDialog(this,
2814                    Bundle.getMessage("makeSelection"), // NOI18N
2815                    Bundle.getMessage("WarningTitle"),
2816                    JmriJOptionPane.WARNING_MESSAGE);  // NOI18N
2817            return false;
2818        }
2819        String name = _actionNameField.getText().trim();
2820        String actionString = _shortActionString.getText().trim();
2821        _dataChanged = true;
2822        _curAction.setActionString("");
2823        _curAction.setActionData(-1);
2824        if (!checkReferenceByMemory(name)) {
2825            return false;
2826        }
2827        if (!checkIsVariable(name, itemType) ) {
2828            return false;
2829        }
2830        switch (itemType) {
2831            case SENSOR:
2832                if (!_referenceByMemory) {
2833                    name = _parent.validateSensorReference(name);
2834                    if (name == null) {
2835                        return false;
2836                    }
2837                }
2838                actionType = selection;
2839                if ((actionType == Conditional.Action.RESET_DELAYED_SENSOR)
2840                        || (actionType == Conditional.Action.DELAYED_SENSOR)) {
2841                    if (!_parent.validateTimeReference(actionType, actionString)) {
2842                        return (false);
2843                    }
2844                    _curAction.setActionString(actionString);
2845                }
2846                if ((actionType == Conditional.Action.SET_SENSOR)
2847                        || (actionType == Conditional.Action.RESET_DELAYED_SENSOR)
2848                        || (actionType == Conditional.Action.DELAYED_SENSOR)) {
2849                    if (_actionBox.getSelectedIndex() == 0) {
2850                        _curAction.setActionData(Sensor.ACTIVE);
2851                    } else if (_actionBox.getSelectedIndex() == 1) {
2852                        _curAction.setActionData(Sensor.INACTIVE);
2853                    } else {
2854                        _curAction.setActionData(Route.TOGGLE);
2855                    }
2856                }
2857                _actionNameField.setText(name);
2858                _curAction.setDeviceName(name);
2859                break;
2860            case TURNOUT:
2861                if (!_referenceByMemory) {
2862                    name = _parent.validateTurnoutReference(name);
2863                    if (name == null) {
2864                        return false;
2865                    }
2866                }
2867                actionType = selection;
2868                if ((actionType == Conditional.Action.RESET_DELAYED_TURNOUT)
2869                        || (actionType == Conditional.Action.DELAYED_TURNOUT)) {
2870                    if (!_parent.validateTimeReference(actionType, actionString)) {
2871                        return (false);
2872                    }
2873                    _curAction.setActionString(actionString);
2874                }
2875                if ((actionType == Conditional.Action.SET_TURNOUT)
2876                        || (actionType == Conditional.Action.RESET_DELAYED_TURNOUT)
2877                        || (actionType == Conditional.Action.DELAYED_TURNOUT)) {
2878                    if (_actionBox.getSelectedIndex() == 0) {
2879                        _curAction.setActionData(Turnout.CLOSED);
2880                    } else if (_actionBox.getSelectedIndex() == 1) {
2881                        _curAction.setActionData(Turnout.THROWN);
2882                    } else {
2883                        _curAction.setActionData(Route.TOGGLE);
2884                    }
2885                } else if (actionType == Conditional.Action.LOCK_TURNOUT) {
2886                    if (_actionBox.getSelectedIndex() == 0) {
2887                        _curAction.setActionData(Turnout.UNLOCKED);
2888                    } else if (_actionBox.getSelectedIndex() == 1) {
2889                        _curAction.setActionData(Turnout.LOCKED);
2890                    } else {
2891                        _curAction.setActionData(Route.TOGGLE);
2892                    }
2893                }
2894                _actionNameField.setText(name);
2895                _curAction.setDeviceName(name);
2896                break;
2897            case LIGHT:
2898                if (!_referenceByMemory) {
2899                    name = _parent.validateLightReference(name);
2900                    if (name == null) {
2901                        return false;
2902                    }
2903                }
2904                actionType = selection;
2905                if (actionType == Conditional.Action.SET_LIGHT_INTENSITY) {
2906                    Light lgtx = _parent.getLight(name);
2907                    // check if light user name was entered
2908                    if (lgtx == null) {
2909                        return false;
2910                    }
2911                    if (!(lgtx instanceof VariableLight)) {
2912                        JmriJOptionPane.showMessageDialog(this,
2913                                Bundle.getMessage("Error45", name), // NOI18N
2914                                Bundle.getMessage("ErrorTitle"),
2915                                JmriJOptionPane.ERROR_MESSAGE);  // NOI18N
2916                        return (false);
2917                    }
2918                    if (!_parent.validateIntensityReference(actionType, actionString)) {
2919                        return (false);
2920                    }
2921                    _curAction.setActionString(actionString);
2922                } else if (actionType == Conditional.Action.SET_LIGHT_TRANSITION_TIME) {
2923                    Light lgtx = _parent.getLight(name);
2924                    // check if light user name was entered
2925                    if (lgtx == null) {
2926                        return false;
2927                    }
2928                    if ( !(lgtx instanceof VariableLight) ||
2929                            !((VariableLight)lgtx).isTransitionAvailable()) {
2930                        JmriJOptionPane.showMessageDialog(this,
2931                                Bundle.getMessage("Error40", name), // NOI18N
2932                                Bundle.getMessage("ErrorTitle"),
2933                                JmriJOptionPane.ERROR_MESSAGE);  // NOI18N
2934                        return (false);
2935                    }
2936                    if (!_parent.validateTimeReference(actionType, actionString)) {
2937                        return (false);
2938                    }
2939                    _curAction.setActionString(actionString);
2940                } else if (actionType == Conditional.Action.SET_LIGHT) {
2941                    if (_actionBox.getSelectedIndex() == 0) {
2942                        _curAction.setActionData(Light.ON);
2943                    } else if (_actionBox.getSelectedIndex() == 1) {
2944                        _curAction.setActionData(Light.OFF);
2945                    } else {
2946                        _curAction.setActionData(Route.TOGGLE);
2947                    }
2948                }
2949                _actionNameField.setText(name);
2950                _curAction.setDeviceName(name);
2951                break;
2952            case SIGNALHEAD:
2953                if (!_referenceByMemory) {
2954                    name = _parent.validateSignalHeadReference(name);
2955                    if (name == null) {
2956                        return false;
2957                    }
2958                }
2959                actionType = selection;
2960                if (actionType == Conditional.Action.SET_SIGNAL_APPEARANCE) {
2961                    String appStr = (String) _actionBox.getSelectedItem();
2962                    _curAction.setActionData(DefaultConditionalAction.stringToActionData(appStr));
2963                    _curAction.setActionString(appStr);
2964                }
2965                _actionNameField.setText(name);
2966                _curAction.setDeviceName(name);
2967                break;
2968            case SIGNALMAST:
2969                if (!_referenceByMemory) {
2970                    name = _parent.validateSignalMastReference(name);
2971                    if (name == null) {
2972                        return false;
2973                    }
2974                }
2975                actionType = selection;
2976                if (actionType == Conditional.Action.SET_SIGNALMAST_ASPECT) {
2977                    _curAction.setActionString((String) _actionBox.getSelectedItem());
2978                }
2979                _actionNameField.setText(name);
2980                _curAction.setDeviceName(name);
2981                break;
2982            case MEMORY:
2983                if (_referenceByMemory) {
2984                    JmriJOptionPane.showMessageDialog(_editActionFrame,
2985                            Bundle.getMessage("Warn6"),
2986                            Bundle.getMessage("WarningTitle"), // NOI18N
2987                            JmriJOptionPane.WARNING_MESSAGE);
2988                    return false;
2989                }
2990                name = _parent.validateMemoryReference(name);
2991                if (name == null) {
2992                    return false;
2993                }
2994                actionType = selection;
2995                if (actionType == Conditional.Action.COPY_MEMORY) {
2996                    actionString = _parent.validateMemoryReference(actionString);
2997                    if (actionString == null) {
2998                        return false;
2999                    }
3000                }
3001                _actionNameField.setText(name);
3002                _curAction.setDeviceName(name);
3003                _curAction.setActionString(actionString);
3004                break;
3005            case LOGIX:
3006                if (!_referenceByMemory) {
3007                    name = _parent.validateLogixReference(name);
3008                    if (name == null) {
3009                        return false;
3010                    }
3011                }
3012                actionType = selection;
3013                _actionNameField.setText(name);
3014                _curAction.setDeviceName(name);
3015                break;
3016            case WARRANT:
3017                if (!_referenceByMemory) {
3018                    name = _parent.validateWarrantReference(name);
3019                    if (name == null) {
3020                        return false;
3021                    }
3022                }
3023                actionType = selection;
3024                _actionNameField.setText(name);
3025                _curAction.setDeviceName(name);
3026                if (actionType == Conditional.Action.CONTROL_TRAIN) {
3027                    switch (_actionBox.getSelectedIndex()) {
3028                        case 0:
3029                            _curAction.setActionData(Warrant.HALT);
3030                            break;
3031                        case 1:
3032                            _curAction.setActionData(Warrant.RESUME);
3033                            break;
3034                        case 2:
3035                            _curAction.setActionData(Warrant.RETRY_FWD);
3036                            break;
3037                        case 3:
3038                            _curAction.setActionData(Warrant.SPEED_UP);
3039                            break;
3040                        case 4:
3041                            _curAction.setActionData(Warrant.STOP);
3042                            break;
3043                        case 5:
3044                            _curAction.setActionData(Warrant.ESTOP);
3045                            break;
3046                        case 6:
3047                            _curAction.setActionData(Warrant.ABORT);
3048                            break;
3049                        default:
3050                            log.warn("Unexpected _actionBox.getSelectedIndex() of {}", _actionBox.getSelectedIndex());  // NOI18N
3051                            break;
3052                    }
3053                } else if (actionType == Conditional.Action.SET_TRAIN_ID
3054                        || actionType == Conditional.Action.SET_TRAIN_NAME
3055                        || actionType == Conditional.Action.GET_TRAIN_LOCATION) {
3056                    _curAction.setActionString(actionString);
3057                }
3058                break;
3059            case OBLOCK:
3060                if (!_referenceByMemory) {
3061                    name = _parent.validateOBlockReference(name);
3062                    if (name == null) {
3063                        return false;
3064                    }
3065                }
3066                actionType = selection;
3067                _actionNameField.setText(name);
3068                _curAction.setDeviceName(name);
3069                if (actionType == Conditional.Action.SET_BLOCK_VALUE
3070                    || actionType == Conditional.Action.GET_BLOCK_TRAIN_NAME
3071                    || actionType == Conditional.Action.GET_BLOCK_WARRANT) {
3072                    _curAction.setActionString(actionString);
3073                }
3074                break;
3075            case ENTRYEXIT:
3076                if (!_referenceByMemory) {
3077                    name = _parent.validateEntryExitReference(name);
3078                    if (name == null) {
3079                        return false;
3080                    }
3081                }
3082                actionType = selection;
3083                _actionNameField.setText(name);
3084                _curAction.setDeviceName(name);
3085                break;
3086            case CLOCK:
3087                actionType = selection;
3088                if (actionType == Conditional.Action.SET_FAST_CLOCK_TIME) {
3089                    int time = _parent.parseTime(_longActionString.getText().trim());
3090                    if (time < 0) {
3091                        return (false);
3092                    }
3093                    _curAction.setActionData(time);
3094                }
3095                break;
3096            case AUDIO:
3097                actionType = selection;
3098                if (actionType == Conditional.Action.PLAY_SOUND) {
3099                    _curAction.setActionString(_longActionString.getText().trim());
3100                } else if (actionType == Conditional.Action.CONTROL_AUDIO) {
3101                    if (!_referenceByMemory) {
3102                        name = _parent.validateAudioReference(name);
3103                        if (name == null) {
3104                            return false;
3105                        }
3106                    }
3107                    _actionNameField.setText(name);
3108                    _curAction.setDeviceName(name);
3109                    switch (_actionBox.getSelectedIndex()) {
3110                        case 0:
3111                            _curAction.setActionData(Audio.CMD_PLAY);
3112                            break;
3113                        case 1:
3114                            _curAction.setActionData(Audio.CMD_STOP);
3115                            break;
3116                        case 2:
3117                            _curAction.setActionData(Audio.CMD_PLAY_TOGGLE);
3118                            break;
3119                        case 3:
3120                            _curAction.setActionData(Audio.CMD_PAUSE);
3121                            break;
3122                        case 4:
3123                            _curAction.setActionData(Audio.CMD_RESUME);
3124                            break;
3125                        case 5:
3126                            _curAction.setActionData(Audio.CMD_PAUSE_TOGGLE);
3127                            break;
3128                        case 6:
3129                            _curAction.setActionData(Audio.CMD_REWIND);
3130                            break;
3131                        case 7:
3132                            _curAction.setActionData(Audio.CMD_FADE_IN);
3133                            break;
3134                        case 8:
3135                            _curAction.setActionData(Audio.CMD_FADE_OUT);
3136                            break;
3137                        case 9:
3138                            _curAction.setActionData(Audio.CMD_RESET_POSITION);
3139                            break;
3140                        default:
3141                            log.warn("Unexpected _actionBox.getSelectedIndex() of {}", _actionBox.getSelectedIndex());  // NOI18N
3142                            break;
3143                    }
3144                }
3145                break;
3146            case SCRIPT:
3147                actionType = selection;
3148                if (actionType == Conditional.Action.RUN_SCRIPT) {
3149                    _curAction.setActionString(_longActionString.getText().trim());
3150                } else if (actionType == Conditional.Action.JYTHON_COMMAND) {
3151                    _curAction.setActionString(_shortActionString.getText().trim());
3152                }
3153                break;
3154            case OTHER:
3155                actionType = selection;
3156                if (actionType == Conditional.Action.TRIGGER_ROUTE) {
3157                    if (!_referenceByMemory) {
3158                        name = _parent.validateRouteReference(name);
3159                        if (name == null) {
3160                            return false;
3161                        }
3162                    }
3163                    _actionNameField.setText(name);
3164                    _curAction.setDeviceName(name);
3165                }
3166                break;
3167            default:
3168                break;
3169        }
3170        _curAction.setType(actionType);
3171        if (actionType != Conditional.Action.NONE) {
3172            _curAction.setOption(_actionOptionBox.getSelectedIndex() + 1);
3173        } else {
3174            _curAction.setOption(0);
3175        }
3176        _editActionFrame.pack();
3177        return (true);
3178    }
3179
3180    // ------------ Action detail listeners ------------
3181    /**
3182     * Listener for _actionTypeBox.
3183     */
3184    class ActionTypeListener implements ActionListener {
3185
3186        Conditional.ItemType _itemType;
3187
3188        @Override
3189        public void actionPerformed(ActionEvent e) {
3190            Conditional.ItemType select1 = _actionItemBox.getItemAt(_actionItemBox.getSelectedIndex());
3191            Conditional.Action select2 = _actionTypeBox.getItemAt(_actionTypeBox.getSelectedIndex());
3192            log.debug("ActionTypeListener: actionItemType= {}, _itemType= {}, action= {}",
3193                    select1, _itemType, select2);  // NOI18N
3194            if (select1 != _itemType) {
3195                log.debug("ActionTypeListener actionItem selection ({}) != expected actionItem ({})",
3196                        select1, _itemType);  // NOI18N
3197            }
3198            if (_curAction != null) {
3199                if (select1 != Conditional.ItemType.NONE && _itemType == select1) {
3200                    _curAction.setType(select2);
3201                    if (select1 == _itemType) {
3202                        String text = _actionNameField.getText();
3203                        if (text != null && text.length() > 0) {
3204                            _curAction.setDeviceName(text);
3205                        }
3206                    }
3207                    actionItemChanged(_itemType);
3208                    initializeActionVariables();
3209                    _dataChanged = true;
3210                }
3211            }
3212        }
3213
3214        public void setItemType(Conditional.ItemType type) {
3215            _itemType = type;
3216        }
3217    }
3218    ActionTypeListener _actionTypeListener = new ActionTypeListener();
3219
3220    transient ActionListener actionSignalHeadNameListener = new ActionListener() {
3221        @Override
3222        public void actionPerformed(ActionEvent e) {
3223            // fired when signal head name changes, but only
3224            // while in signal head mode
3225            log.debug("actionSignalHeadNameListener fires; _actionNameField: {}", _actionNameField.getText().trim());  // NOI18N
3226            loadJComboBoxWithHeadAppearances(_actionBox, _actionNameField.getText().trim());
3227            _dataChanged = true;
3228        }
3229    };
3230
3231    transient ActionListener actionSignalMastNameListener = new ActionListener() {
3232        @Override
3233        public void actionPerformed(ActionEvent e) {
3234            // fired when signal mast name changes, but only
3235            // while in signal mast mode
3236            log.debug("actionSignalMastNameListener fires; _actionNameField: {}", _actionNameField.getText().trim());  // NOI18N
3237            loadJComboBoxWithMastAspects(_actionBox, _actionNameField.getText().trim());
3238            _dataChanged = true;
3239        }
3240    };
3241
3242    /**
3243     * Table model for State Variables in Edit Conditional pane.
3244     */
3245    public class VariableTableModel extends AbstractTableModel {
3246
3247        public static final int ROWNUM_COLUMN = 0;
3248        public static final int AND_COLUMN = 1;
3249        public static final int NOT_COLUMN = 2;
3250        public static final int DESCRIPTION_COLUMN = 3;
3251        public static final int STATE_COLUMN = 4;
3252        public static final int TRIGGERS_COLUMN = 5;
3253        public static final int EDIT_COLUMN = 6;
3254        public static final int DELETE_COLUMN = 7;
3255
3256        @Override
3257        public Class<?> getColumnClass(int c) {
3258            switch (c) {
3259                case ROWNUM_COLUMN:
3260                    return String.class;
3261                case AND_COLUMN:
3262                    return JComboBox.class;
3263                case NOT_COLUMN:
3264                    return JComboBox.class;
3265                case DESCRIPTION_COLUMN:
3266                    return String.class;
3267                case STATE_COLUMN:
3268                    return String.class;
3269                case TRIGGERS_COLUMN:
3270                    return Boolean.class;
3271                case EDIT_COLUMN:
3272                case DELETE_COLUMN:
3273                    return JButton.class;
3274                default:
3275                    // fall through
3276                    break;
3277            }
3278            return String.class;
3279        }
3280
3281        @Override
3282        public int getColumnCount() {
3283            return 8;
3284        }
3285
3286        @Override
3287        public int getRowCount() {
3288            return _variableList.size();
3289        }
3290
3291        @Override
3292        public boolean isCellEditable(int r, int c) {
3293            switch (c) {
3294                case ROWNUM_COLUMN:
3295                case DESCRIPTION_COLUMN:
3296                case STATE_COLUMN:
3297                    return (false);
3298                case AND_COLUMN:
3299                    return (_logicType == Conditional.AntecedentOperator.MIXED);
3300                case NOT_COLUMN:
3301                case TRIGGERS_COLUMN:
3302                    return (true);
3303                case EDIT_COLUMN:
3304                    if (_inVarReorder) {
3305                        return false;
3306                    }
3307                    return (true);
3308                case DELETE_COLUMN:
3309                    if (_inVarReorder && r < _nextInOrder) {
3310                        return false;
3311                    }
3312                    return true;
3313                default:
3314                    // fall through
3315                    break;
3316            }
3317            return false;
3318        }
3319
3320        @Override
3321        public String getColumnName(int col) {
3322            switch (col) {
3323                case ROWNUM_COLUMN:
3324                    return (Bundle.getMessage("ColumnLabelRow"));  // NOI18N
3325                case AND_COLUMN:
3326                    return (Bundle.getMessage("ColumnLabelOperator"));  // NOI18N
3327                case NOT_COLUMN:
3328                    return (Bundle.getMessage("ColumnLabelNot"));  // NOI18N
3329                case DESCRIPTION_COLUMN:
3330                    return (Bundle.getMessage("ColumnLabelDescription"));  // NOI18N
3331                case STATE_COLUMN:
3332                    return (Bundle.getMessage("ColumnState"));  // NOI18N
3333                case TRIGGERS_COLUMN:
3334                    return (Bundle.getMessage("ColumnLabelTriggersCalculation"));  // NOI18N
3335                case EDIT_COLUMN:
3336                    return "";
3337                case DELETE_COLUMN:
3338                    return "";
3339                default:
3340                    // fall through
3341                    break;
3342            }
3343            return "";
3344        }
3345
3346        public int getPreferredWidth(int col) {
3347            if (col == DESCRIPTION_COLUMN) {
3348                return 400;
3349            }
3350            return 10;
3351        }
3352
3353        @Override
3354        public Object getValueAt(int row, int col) {
3355            if (row >= _variableList.size()) {
3356                return null;
3357            }
3358            ConditionalVariable variable = _variableList.get(row);
3359            switch (col) {
3360                case ROWNUM_COLUMN:
3361                    return ("R" + (row + 1)); // NOI18N
3362                case AND_COLUMN:
3363                    if (row == 0) { //removed: || _logicType == Conditional.MIXED
3364                        return "";
3365                    }
3366                    return variable.getOpernString(); // also display Operand selection when set to Mixed
3367                case NOT_COLUMN:
3368                    if (variable.isNegated()) {
3369                        return Bundle.getMessage("LogicNOT");  // NOI18N
3370                    }
3371                    break;
3372                case DESCRIPTION_COLUMN:
3373                    return variable.toString();
3374                case STATE_COLUMN:
3375                    switch (variable.getState()) {
3376                        case Conditional.TRUE:
3377                            return Bundle.getMessage("True");  // NOI18N
3378                        case Conditional.FALSE:
3379                            return Bundle.getMessage("False");  // NOI18N
3380                        case NamedBean.UNKNOWN:
3381                            return Bundle.getMessage("BeanStateUnknown");  // NOI18N
3382                        default:
3383                            log.warn("Unhandled state type: {}", variable.getState());  // NOI18N
3384                            break;
3385                    }
3386                    break;
3387                case TRIGGERS_COLUMN:
3388                    return variable.doTriggerActions();
3389                case EDIT_COLUMN:
3390                    return Bundle.getMessage("ButtonEdit");  // NOI18N
3391                case DELETE_COLUMN:
3392                    if (!_inVarReorder) {
3393                        return Bundle.getMessage("ButtonDelete");  // NOI18N
3394                    } else if (_nextInOrder == 0) {
3395                        return Bundle.getMessage("ButtonFirst");  // NOI18N
3396                    } else if (_nextInOrder <= row) {
3397                        return Bundle.getMessage("ButtonNext");  // NOI18N
3398                    }
3399                    return Integer.toString(row + 1);
3400                default:
3401                    break;
3402            }
3403            return null;
3404        }
3405
3406        @Override
3407        public void setValueAt(Object value, int row, int col) {
3408            if (row >= _variableList.size()) {
3409                return;
3410            }
3411            ConditionalVariable variable = _variableList.get(row);
3412            switch (col) {
3413                case AND_COLUMN:
3414                    variableOperatorChanged(row, (String) value);
3415                    break;
3416                case NOT_COLUMN:
3417                    variableNegationChanged(row, (String) value);
3418                    break;
3419                case STATE_COLUMN:
3420                    String state = ((String) value);
3421                    if (state.equals(Bundle.getMessage("True").toUpperCase().trim())) {  // NOI18N
3422                        variable.setState(State.TRUE.getIntValue());
3423                    } else if (state.equals(Bundle.getMessage("False").toUpperCase().trim())) {  // NOI18N
3424                        variable.setState(State.FALSE.getIntValue());
3425                    } else {
3426                        variable.setState(State.UNKNOWN.getIntValue());
3427                    }
3428                    break;
3429                case TRIGGERS_COLUMN:
3430                    variable.setTriggerActions(!variable.doTriggerActions());
3431                    break;
3432                case EDIT_COLUMN:
3433                    if (LRouteTableAction.getLogixInitializer().equals(_parent._curLogix.getSystemName())) {
3434                        JmriJOptionPane.showMessageDialog(_editVariableFrame,
3435                                Bundle.getMessage("Error49"),
3436                                Bundle.getMessage("ErrorTitle"), // NOI18N
3437                                JmriJOptionPane.ERROR_MESSAGE);
3438                        break;
3439                    }
3440                    // Use separate Runnable so window is created on top
3441                    class WindowMaker implements Runnable {
3442                        int row;
3443                        WindowMaker(int r) {
3444                            row = r;
3445                        }
3446
3447                        @Override
3448                        public void run() {
3449                            makeEditVariableWindow(row);
3450                        }
3451                    }
3452                    WindowMaker t = new WindowMaker(row);
3453                    javax.swing.SwingUtilities.invokeLater(t);
3454                    break;
3455                case DELETE_COLUMN:
3456                    if (_inVarReorder) {
3457                        swapVariables(row);
3458                    } else {
3459                        deleteVariablePressed(row);
3460                    }
3461                    break;
3462                default:
3463                    break;
3464            }
3465        }
3466    }
3467
3468    //------------------- Table Models ----------------------
3469    /**
3470     * Table model for Actions in Edit Conditional pane.
3471     */
3472    public class ActionTableModel extends AbstractTableModel {
3473
3474        public static final int DESCRIPTION_COLUMN = 0;
3475        public static final int EDIT_COLUMN = 1;
3476        public static final int DELETE_COLUMN = 2;
3477
3478        @Override
3479        public Class<?> getColumnClass(int c) {
3480            if (c == EDIT_COLUMN || c == DELETE_COLUMN) {
3481                return JButton.class;
3482            }
3483            return super.getColumnClass(c);
3484        }
3485
3486        @Override
3487        public int getColumnCount() {
3488            return 3;
3489        }
3490
3491        @Override
3492        public int getRowCount() {
3493            return _actionList.size();
3494        }
3495
3496        @Override
3497        public boolean isCellEditable(int r, int c) {
3498            if (c == DESCRIPTION_COLUMN) {
3499                return false;
3500            }
3501            if (_inActReorder && (c == EDIT_COLUMN || r < _nextInOrder)) {
3502                return false;
3503            }
3504            return true;
3505        }
3506
3507        @Override
3508        public String getColumnName(int col) {
3509            if (col == DESCRIPTION_COLUMN) {
3510                return Bundle.getMessage("LabelActionDescription");  // NOI18N
3511            }
3512            return "";
3513        }
3514
3515        public int getPreferredWidth(int col) {
3516            if (col == DESCRIPTION_COLUMN) {
3517                return 800;
3518            }
3519            return 20;
3520        }
3521
3522        @Override
3523        public Object getValueAt(int row, int col) {
3524            if (row >= _actionList.size()) {
3525                return null;
3526            }
3527            switch (col) {
3528                case DESCRIPTION_COLUMN:
3529                    ConditionalAction action = _actionList.get(row);
3530                    return action.description(_triggerOnChangeButton.isSelected());
3531                case EDIT_COLUMN:
3532                    return Bundle.getMessage("ButtonEdit");  // NOI18N
3533                case DELETE_COLUMN:
3534                    if (!_inActReorder) {
3535                        return Bundle.getMessage("ButtonDelete");  // NOI18N
3536                    } else if (_nextInOrder == 0) {
3537                        return Bundle.getMessage("ButtonFirst");  // NOI18N
3538                    } else if (_nextInOrder <= row) {
3539                        return Bundle.getMessage("ButtonNext");  // NOI18N
3540                    }
3541                    return Integer.toString(row + 1);
3542                default:
3543                    // fall through
3544                    break;
3545            }
3546            return null;
3547        }
3548
3549        @Override
3550        public void setValueAt(Object value, int row, int col) {
3551            if (col == EDIT_COLUMN) {
3552                // Use separate Runnable so window is created on top
3553                class WindowMaker implements Runnable {
3554                    private int _row;
3555                    WindowMaker(int r) {
3556                        _row = r;
3557                    }
3558
3559                    @Override
3560                    public void run() {
3561                        makeEditActionWindow(_row);
3562                    }
3563                }
3564                WindowMaker t = new WindowMaker(row);
3565                javax.swing.SwingUtilities.invokeLater(t);
3566            } else if (col == DELETE_COLUMN) {
3567                if (_inActReorder) {
3568                    swapActions(row);
3569                } else {
3570                    deleteActionPressed(row);
3571                }
3572            }
3573        }
3574    }
3575
3576    private final static org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(ConditionalEditFrame.class);
3577
3578}