001package jmri.jmrit.beantable;
002
003import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
004
005import java.awt.*;
006import java.awt.event.ActionEvent;
007import java.util.Objects;
008
009import javax.annotation.CheckForNull;
010import javax.annotation.Nonnull;
011import javax.swing.*;
012import javax.swing.border.Border;
013import javax.swing.border.TitledBorder;
014
015import jmri.*;
016import jmri.implementation.*;
017import jmri.jmrix.acela.*;
018import jmri.jmrix.grapevine.GrapevineSystemConnectionMemo;
019import jmri.jmrix.grapevine.SerialSignalHead;
020import jmri.util.*;
021import jmri.util.swing.*;
022
023/**
024 * Frame for creating / editing Signal Heads.
025 * 
026 * Code originally located within SignalHeadTableAction.java
027 * 
028 * @author Bob Jacobsen Copyright (C) 2003,2006,2007, 2008, 2009
029 * @author Petr Koud'a Copyright (C) 2007
030 * @author Egbert Broerse Copyright (C) 2016
031 * @author Steve Young Copyright (C) 2023
032 */
033public class SignalHeadAddEditFrame extends JmriJFrame {
034
035    public SignalHeadAddEditFrame(@CheckForNull SignalHead head){
036        super(Bundle.getMessage(head==null ? "TitleAddSignalHead" : "TitleEditSignalHead"), false, true);
037        
038        signalHeadBeingEdited = head;
039    }
040
041    private final SignalHead signalHeadBeingEdited;
042
043    private final NamedBeanHandleManager nbhm = InstanceManager.getDefault(NamedBeanHandleManager.class);
044
045    private final JTextField systemNameField = new JTextField(5);
046    private final JTextField userNameField = new JTextField(10);
047
048    private final JLabel systemNameLabel = new JLabel("");
049    private final JLabel userNameLabel = new JLabel("");
050
051    private JPanel dccOptionsPanel = new JPanel();
052    private JPanel dccAppearanceNumberingPanel = new JPanel();
053
054    private JPanel acelaHeadPanel = new JPanel();
055
056    // we share input fields across boxes so that
057    // entries in one don't disappear when the user switches
058    // to a different type
059    private JPanel centrePanel1 = new JPanel();
060    private JPanel centrePanel2 = new JPanel();
061    private JPanel centrePanel3 = new JPanel();
062    private JPanel centrePanel4 = new JPanel();
063    private JPanel centrePanel5 = new JPanel();
064    private JPanel centrePanel6 = new JPanel();
065    private JPanel centrePanel7 = new JPanel();
066
067    private final FlowLayout defaultFlow = new FlowLayout(FlowLayout.CENTER, 5, 0);
068    private final Border blackline = BorderFactory.createLineBorder(Color.black);
069
070    private final TitledBorder centrePanBorder1 = BorderFactory.createTitledBorder(blackline);
071    private final TitledBorder centrePanBorder2 = BorderFactory.createTitledBorder(blackline);
072    private final TitledBorder centrePanBorder3 = BorderFactory.createTitledBorder(blackline);
073    private final TitledBorder centrePanBorder4 = BorderFactory.createTitledBorder(blackline);
074    private final TitledBorder centrePanBorder5 = BorderFactory.createTitledBorder(blackline);
075    private final TitledBorder centrePanBorder6 = BorderFactory.createTitledBorder(blackline);
076    private final TitledBorder centrePanBorder7 = BorderFactory.createTitledBorder(blackline);
077
078    private BeanSelectCreatePanel<Turnout> turnoutSelect1;
079    private BeanSelectCreatePanel<Turnout> turnoutSelect2;
080    private BeanSelectCreatePanel<Turnout> turnoutSelect3;
081    private BeanSelectCreatePanel<Turnout> turnoutSelect4;
082    private BeanSelectCreatePanel<Turnout> turnoutSelect5;
083    private BeanSelectCreatePanel<Turnout> turnoutSelect6;
084    private BeanSelectCreatePanel<Turnout> turnoutSelect7;
085
086    private final static String TURNOUT_STATE_THROWN = InstanceManager.getDefault(TurnoutManager.class).getThrownText();
087    private final static String TURNOUT_STATE_CLOSED = InstanceManager.getDefault(TurnoutManager.class).getClosedText();
088
089    private final static int[] TURNOUT_STATE_VALUES = new int[]{Turnout.CLOSED, Turnout.THROWN};
090    private final static String[] TURNOUT_STATE_STRINGS = new String[]{TURNOUT_STATE_CLOSED, TURNOUT_STATE_THROWN};
091
092    private final static String[] SIGNAL_STATE_STRINGS = new String[]{
093        Bundle.getMessage("SignalHeadStateDark"),
094        Bundle.getMessage("SignalHeadStateRed"),
095        Bundle.getMessage("SignalHeadStateLunar"),
096        Bundle.getMessage("SignalHeadStateYellow"),
097        Bundle.getMessage("SignalHeadStateGreen")
098    };
099
100    private final static int[] SIGNAL_STATE_VALUES = new int[]{
101        SignalHead.DARK,
102        SignalHead.RED,
103        SignalHead.LUNAR,
104        SignalHead.YELLOW,
105        SignalHead.GREEN
106    };
107
108    private final static String ACELA_ASPECT = Bundle.getMessage("StringAcelaaspect");
109    private final static String SE8C4_ASPECT = Bundle.getMessage("StringSE8c4aspect");
110    private final static String TRIPLE_OUTPUT = Bundle.getMessage("StringTripleOutput");
111    private final static String QUAD_OUTPUT = Bundle.getMessage("StringQuadOutput");
112    private final static String SINGLE_TURNOUT = Bundle.getMessage("StringSingle");
113    private final static String DOUBLE_TURNOUT = Bundle.getMessage("StringDoubleTurnout");
114    private final static String TRIPLE_TURNOUT = Bundle.getMessage("StringTripleTurnout");
115    private final static String VIRTUAL_HEAD = Bundle.getMessage("StringVirtual");
116    private final static String GRAPEVINE = Bundle.getMessage("StringGrapevine");
117    private final static String LSDEC = Bundle.getMessage("StringLsDec");
118    private final static String DCC_SIGNAL_DECODER = Bundle.getMessage("StringDccSigDec");
119    private final static String MERG_SIGNAL_DRIVER = Bundle.getMessage("StringMerg");
120
121    private final static String ACELA_SIG_HEAD_DOUBLE = Bundle.getMessage("StringSignalheadDouble");
122    private final static String ACELA_SIG_HEAD_TRIPLE = Bundle.getMessage("StringSignalheadTriple");
123    // private final static String ACELA_SIG_HEAD_RGB = Bundle.getMessage("StringSignalheadRGB");
124    private final static String ACELA_SIG_HEAD_BIPLOAR = Bundle.getMessage("StringSignalheadBiPolar");
125    private final static String ACELA_SIG_HEAD_WIGWAG = Bundle.getMessage("StringSignalheadWigwag");
126
127    private final static String[] ACELA_SIG_HEAD_TYPES = new String[]{ACELA_SIG_HEAD_DOUBLE, ACELA_SIG_HEAD_TRIPLE,
128        ACELA_SIG_HEAD_BIPLOAR, ACELA_SIG_HEAD_WIGWAG};
129
130    private final static int[] ACELA_SIG_HEAD_TYPE_VALUES = new int[]{AcelaNode.DOUBLE, AcelaNode.TRIPLE,
131        AcelaNode.BPOLAR, AcelaNode.WIGWAG};
132
133    private final static String[] UK_SEMAPHORE_TYPES = new String[]{Bundle.getMessage("HomeSignal"), Bundle.getMessage("DistantSignal")};
134    private final static String[] UK_SIGNAL_ASPECTS =  new String[]{"2", "3", "4"}; // NOI18N
135
136    private final JLabel dccPacketSendCount = new JLabel(Bundle.getMessage("DCCMastPacketSendCount"));
137    private final JSpinner dccPacketSendCountSpinner = new JSpinner();
138
139    private JSpinner[] dccAspectSpinners;
140    private final JCheckBox dccOffSetAddressCheckBox = new JCheckBox(Bundle.getMessage("DccAccessoryAddressOffSet"));
141
142    private JComboBox<String> headTypeBox;
143    private final JLabel headTypeLabel = new JLabel();
144
145    private final JComboBox<String> prefixBox = new JComboBox<>();
146    private final JLabel prefixBoxLabel = new JLabel(Bundle.getMessage("MakeLabel", Bundle.getMessage("DCCSystem")));
147
148    private final JLabel stateLabel1 = new JLabel(Bundle.getMessage("MakeLabel", Bundle.getMessage("TurnoutState")));
149    private final JLabel stateLabel2 = new JLabel(stateLabel1.getText()); // faster than Bundle?
150    private final JLabel stateLabel3 = new JLabel(stateLabel1.getText());
151    private final JLabel stateLabel4 = new JLabel(stateLabel1.getText());
152    private final JLabel stateLabel5 = new JLabel(stateLabel1.getText());
153    private final JLabel stateLabel6 = new JLabel(stateLabel1.getText());
154    private final JLabel stateLabel7 = new JLabel(stateLabel1.getText());
155
156    private final JComboBox<String> turnoutStateBox1 = new JComboBox<>(TURNOUT_STATE_STRINGS);
157    private final JComboBox<String> turnoutStateBox2 = new JComboBox<>(TURNOUT_STATE_STRINGS);
158    private final JComboBox<String> turnoutStateBox3 = new JComboBox<>(TURNOUT_STATE_STRINGS);
159    private final JComboBox<String> turnoutStateBox4 = new JComboBox<>(TURNOUT_STATE_STRINGS);
160    private final JComboBox<String> turnoutStateBox5 = new JComboBox<>(TURNOUT_STATE_STRINGS);
161    private final JComboBox<String> turnoutStateBox6 = new JComboBox<>(TURNOUT_STATE_STRINGS);
162    private final JComboBox<String> turnoutStateBox7 = new JComboBox<>(TURNOUT_STATE_STRINGS);
163
164    private final JComboBox<String> signalStateBox2 = new JComboBox<>(SIGNAL_STATE_STRINGS);
165    private final JComboBox<String> signalStateBox3 = new JComboBox<>(SIGNAL_STATE_STRINGS);
166
167    private final JComboBox<String> acelaHeadTypeBox = new JComboBox<>(ACELA_SIG_HEAD_TYPES);
168
169    private final JComboBox<String> ukSignalSemaphoreTypeBox = new JComboBox<>(UK_SEMAPHORE_TYPES);
170    private final JComboBox<String> numberUkAspectsBox = new JComboBox<>(UK_SIGNAL_ASPECTS);
171
172    protected SignalHead getSignalHead(){
173        return signalHeadBeingEdited;
174    }
175
176    protected void resetAddressFields(){
177        this.systemNameField.setText("");
178        this.userNameField.setText("");
179    }
180
181    @Override
182    public void initComponents(){
183
184        addHelpMenu("package.jmri.jmrit.beantable.SignalAddEdit", true);
185
186        for (CommandStation station : InstanceManager.getList(CommandStation.class)) {
187            prefixBox.addItem(station.getUserName());
188        }
189
190        initDccAppearancePanel();
191        turnoutSelect1 = new BeanSelectCreatePanel<>(InstanceManager.getDefault(TurnoutManager.class), null);
192        turnoutSelect2 = new BeanSelectCreatePanel<>(InstanceManager.getDefault(TurnoutManager.class), null);
193        turnoutSelect3 = new BeanSelectCreatePanel<>(InstanceManager.getDefault(TurnoutManager.class), null);
194        turnoutSelect4 = new BeanSelectCreatePanel<>(InstanceManager.getDefault(TurnoutManager.class), null);
195        turnoutSelect5 = new BeanSelectCreatePanel<>(InstanceManager.getDefault(TurnoutManager.class), null);
196        turnoutSelect6 = new BeanSelectCreatePanel<>(InstanceManager.getDefault(TurnoutManager.class), null);
197        turnoutSelect7 = new BeanSelectCreatePanel<>(InstanceManager.getDefault(TurnoutManager.class), null);
198
199        getContentPane().setLayout(new BorderLayout());
200        getContentPane().add(getHeaderPanel(), BorderLayout.PAGE_START);
201        getContentPane().add(new JScrollPane(getCentrePanel()), BorderLayout.CENTER);
202        getContentPane().add(getBottomButtonsPanel(), BorderLayout.PAGE_END);
203
204        typeChanged();
205        setHeadToFrame();
206
207        setEscapeKeyClosesWindow(true);
208        pack();
209        setVisible(true);
210    }
211
212    private JPanel getHeaderPanel(){
213
214        JPanel panelHeader = new JPanel();
215        panelHeader.setLayout(new BoxLayout(panelHeader, BoxLayout.Y_AXIS));
216
217        initTypeBox();
218        panelHeader.add(new JSeparator());
219        panelHeader.add(headTypeBox);
220        panelHeader.add(new JSeparator());
221        JPanel labelPanel = new JPanel();
222        labelPanel.setLayout(new GridBagLayout());
223        labelPanel.add(headTypeLabel);
224
225        panelHeader.add(labelPanel);
226        panelHeader.add(new JSeparator());
227
228        JPanel p = new JPanel();
229        p.setLayout(new FlowLayout());
230        p.add(prefixBoxLabel);
231        prefixBoxLabel.setLabelFor(prefixBox);
232        p.add(prefixBox);
233        panelHeader.add(p);
234
235        p = new JPanel();
236        p.setLayout(new FlowLayout());
237        p.add(systemNameLabel);
238        systemNameLabel.setLabelFor(systemNameField);
239        p.add(systemNameField);
240        panelHeader.add(p);
241
242        p = new JPanel();
243        p.setLayout(new FlowLayout());
244        p.add(userNameLabel);
245        userNameLabel.setLabelFor(userNameField);
246        userNameField.setToolTipText(Bundle.getMessage("SignalHeadUserNameTooltip"));
247        p.add(userNameField);
248        panelHeader.add(p);
249
250        return panelHeader;
251    }
252
253    private JPanel getCentrePanel() {
254
255        JPanel panelCentre = new JPanel();
256        panelCentre.setLayout(new BoxLayout(panelCentre, BoxLayout.Y_AXIS));
257
258        dccOptionsPanel = new JPanel();
259        dccOptionsPanel.add(dccOffSetAddressCheckBox);
260        dccOffSetAddressCheckBox.setToolTipText(Bundle.getMessage("DccOffsetTooltip"));
261        dccOptionsPanel.add(dccPacketSendCount);
262        dccPacketSendCountSpinner.setModel(new SpinnerNumberModel(3, 1, 4, 1));
263        dccPacketSendCountSpinner.setToolTipText(Bundle.getMessage("DCCMastPacketSendCountToolTip"));
264        dccOptionsPanel.add(dccPacketSendCountSpinner);
265        panelCentre.add(dccOptionsPanel);
266
267        centrePanel1 = new JPanel();
268        centrePanel1.setLayout(defaultFlow);
269        centrePanel1.add(turnoutSelect1);
270        centrePanel1.add(stateLabel1);
271        centrePanel1.add(turnoutStateBox1);
272        turnoutStateBox1.setToolTipText(Bundle.getMessage("SignalHeadStateTooltip"));
273        centrePanel1.add(numberUkAspectsBox);
274        numberUkAspectsBox.setToolTipText(Bundle.getMessage("SignalHeadMergTooltip"));
275        numberUkAspectsBox.addActionListener(e -> ukAspectChange());
276        centrePanel1.setBorder(centrePanBorder1);
277        panelCentre.add(centrePanel1);
278
279        centrePanel2 = new JPanel();
280        centrePanel2.setLayout(defaultFlow);
281        centrePanel2.add(turnoutSelect2);
282        centrePanel2.add(stateLabel2);
283        centrePanel2.add(turnoutStateBox2);
284        turnoutStateBox2.setToolTipText(Bundle.getMessage("SignalHeadStateTooltip"));
285        centrePanel2.add(signalStateBox2);
286        centrePanel2.add(ukSignalSemaphoreTypeBox);
287        ukSignalSemaphoreTypeBox.setToolTipText(Bundle.getMessage("SignalHeadUseTooltip"));
288        centrePanel2.add(dccAppearanceNumberingPanel);
289        centrePanel2.setBorder(centrePanBorder2);
290        panelCentre.add(centrePanel2);
291
292        centrePanel3 = new JPanel();
293        centrePanel3.setLayout(defaultFlow);
294        centrePanel3.add(turnoutSelect3);
295        centrePanel3.add(stateLabel3);
296        centrePanel3.add(turnoutStateBox3);
297        turnoutStateBox3.setToolTipText(Bundle.getMessage("SignalHeadStateTooltip"));
298        centrePanel3.add(signalStateBox3);
299        centrePanel3.setBorder(centrePanBorder3);
300        panelCentre.add(centrePanel3);
301
302        centrePanel4 = new JPanel();
303        centrePanel4.setLayout(defaultFlow);
304        centrePanel4.add(turnoutSelect4);
305        centrePanel4.add(stateLabel4);
306        centrePanel4.add(turnoutStateBox4);
307        turnoutStateBox4.setToolTipText(Bundle.getMessage("SignalHeadStateTooltip"));
308        centrePanel4.setBorder(centrePanBorder4);
309        panelCentre.add(centrePanel4);
310
311        centrePanel5 = new JPanel();
312        centrePanel5.setLayout(defaultFlow);
313        centrePanel5.add(turnoutSelect5);
314        centrePanel5.add(stateLabel5);
315        centrePanel5.add(turnoutStateBox5);
316        turnoutStateBox5.setToolTipText(Bundle.getMessage("SignalHeadStateTooltip"));
317        centrePanel5.setBorder(centrePanBorder5);
318        panelCentre.add(centrePanel5);
319
320        centrePanel6 = new JPanel();
321        centrePanel6.setLayout(defaultFlow);
322        centrePanel6.add(turnoutSelect6);
323        centrePanel6.add(stateLabel6);
324        centrePanel6.add(turnoutStateBox6);
325        turnoutStateBox6.setToolTipText(Bundle.getMessage("SignalHeadStateTooltip"));
326        centrePanel6.setBorder(centrePanBorder6);
327        panelCentre.add(centrePanel6);
328
329        centrePanel7 = new JPanel();
330        centrePanel7.setLayout(defaultFlow);
331        centrePanel7.add(turnoutSelect7);
332        centrePanel7.add(stateLabel7);
333        centrePanel7.add(turnoutStateBox7);
334        turnoutStateBox7.setToolTipText(Bundle.getMessage("SignalHeadStateTooltip"));
335        centrePanel7.setBorder(centrePanBorder7);
336        panelCentre.add(centrePanel7);
337
338        acelaHeadPanel = new JPanel();
339        acelaHeadPanel.setLayout(defaultFlow);
340        JLabel aspectTypeLabel = new JLabel(Bundle.getMessage("MakeLabel", Bundle.getMessage("LabelAspectType")));
341        acelaHeadPanel.add(aspectTypeLabel);
342        acelaHeadPanel.add(acelaHeadTypeBox);
343        panelCentre.add(acelaHeadPanel);
344
345        return panelCentre;
346    }
347    
348    private JPanel getBottomButtonsPanel(){
349        JPanel panelBottom = new JPanel();
350        panelBottom.setLayout(new BoxLayout(panelBottom, BoxLayout.Y_AXIS));
351        // add buttons
352        JPanel p = new JPanel();
353        p.setLayout(new FlowLayout(FlowLayout.TRAILING));
354
355        JButton cancel = new JButton(Bundle.getMessage("ButtonCancel"));
356        p.add(cancel);
357        cancel.addActionListener(e1 -> dispose());
358
359        JButton update = new JButton(Bundle.getMessage(
360            signalHeadBeingEdited == null ? "ButtonCreate" : "ButtonUpdate" ));
361        update.addActionListener(this::updateEditPressed);
362        getRootPane().setDefaultButton(update);
363
364        p.add(update );
365
366        panelBottom.add(p);
367        return panelBottom;
368    }
369
370    public void hideAllPanels() {
371
372        prefixBoxLabel.setVisible(false);
373        prefixBox.setVisible(false);
374
375        systemNameField.setVisible(false);
376        systemNameLabel.setVisible(false);
377
378        userNameLabel.setVisible(false);
379        userNameField.setVisible(false);
380
381        dccOptionsPanel.setVisible(false);
382        centrePanel1.setVisible(false);
383        turnoutSelect1.setVisible(false);
384        stateLabel1.setVisible(false);
385        turnoutStateBox1.setVisible(false);
386        numberUkAspectsBox.setVisible(false);
387
388        centrePanel2.setVisible(false);
389        turnoutSelect2.setVisible(false);
390        stateLabel2.setVisible(false);
391        turnoutStateBox2.setVisible(false);
392        signalStateBox2.setVisible(false);
393        ukSignalSemaphoreTypeBox.setVisible(false);
394        dccAppearanceNumberingPanel.setVisible(false);
395
396        centrePanel3.setVisible(false);
397        turnoutSelect3.setVisible(false);
398        stateLabel3.setVisible(false);
399        turnoutStateBox3.setVisible(false);
400        signalStateBox3.setVisible(false);
401
402        centrePanel4.setVisible(false);
403        turnoutSelect4.setVisible(false);
404        stateLabel4.setVisible(false);
405        turnoutStateBox4.setVisible(false);
406
407        centrePanel5.setVisible(false);
408        turnoutSelect5.setVisible(false);
409        stateLabel5.setVisible(false);
410        turnoutStateBox5.setVisible(false);
411
412        centrePanel6.setVisible(false);
413        turnoutSelect6.setVisible(false);
414        stateLabel6.setVisible(false);
415        turnoutStateBox6.setVisible(false);
416
417        centrePanel7.setVisible(false);
418        turnoutSelect7.setVisible(false);
419        stateLabel7.setVisible(false);
420        turnoutStateBox7.setVisible(false);
421
422        acelaHeadPanel.setVisible(false);
423    }
424
425    private void setHeadToFrame() {
426        headTypeLabel.setVisible(signalHeadBeingEdited != null);
427        headTypeBox.setVisible(signalHeadBeingEdited == null);
428        if ( signalHeadBeingEdited == null ){
429            headTypeBox.setSelectedItem(DOUBLE_TURNOUT); // force GUI status consistent. Default set to Double Head type
430            typeChanged();
431            systemNameField.setToolTipText(Bundle.getMessage("SignalHeadSysNameTooltip"));
432            return;
433        }
434        headTypeBox.setSelectedItem(getNameFromClass(signalHeadBeingEdited.getClass().getName()));
435        headTypeLabel.setText("<html><h3>"+ getNameFromClass(signalHeadBeingEdited.getClass().getName())+"</h3></html>");
436
437        typeChanged();
438        systemNameField.setEditable(false);
439        systemNameField.setText(signalHeadBeingEdited.getSystemName());
440        userNameField.setText(signalHeadBeingEdited.getUserName());
441
442        String type = (String)headTypeBox.getSelectedItem();
443        if ( QUAD_OUTPUT.equals(type)) {
444            var greenTt = ((QuadOutputSignalHead) signalHeadBeingEdited).getGreen();
445            var yellowTt =((QuadOutputSignalHead) signalHeadBeingEdited).getYellow();
446            var redTt = ((QuadOutputSignalHead) signalHeadBeingEdited).getRed();
447            var lunarTt = ((QuadOutputSignalHead) signalHeadBeingEdited).getLunar();
448            if (greenTt !=null) turnoutSelect1.setDefaultNamedBean(greenTt.getBean());
449            if (yellowTt!=null) turnoutSelect2.setDefaultNamedBean(yellowTt.getBean());
450            if (redTt   !=null) turnoutSelect3.setDefaultNamedBean(redTt.getBean());
451            if (lunarTt !=null) turnoutSelect4.setDefaultNamedBean(lunarTt.getBean());
452        } else if (TRIPLE_TURNOUT.equals(type)) {
453            var greenTt = ((TripleTurnoutSignalHead) signalHeadBeingEdited).getGreen();
454            var yellowTt =((TripleTurnoutSignalHead) signalHeadBeingEdited).getYellow();
455            var redTt = ((TripleTurnoutSignalHead) signalHeadBeingEdited).getRed();
456            if (greenTt !=null) turnoutSelect1.setDefaultNamedBean(greenTt.getBean());
457            if (yellowTt!=null) turnoutSelect2.setDefaultNamedBean(yellowTt.getBean());
458            if (redTt   !=null) turnoutSelect3.setDefaultNamedBean(redTt.getBean());
459        } else if ( TRIPLE_OUTPUT.equals(type)) {
460            var greenTt = ((TripleOutputSignalHead) signalHeadBeingEdited).getGreen();
461            var blueTt =((TripleOutputSignalHead) signalHeadBeingEdited).getBlue();
462            var redTt = ((TripleOutputSignalHead) signalHeadBeingEdited).getRed();
463            if (greenTt !=null) turnoutSelect1.setDefaultNamedBean(greenTt.getBean());
464            if (blueTt!=null) turnoutSelect2.setDefaultNamedBean(blueTt.getBean());
465            if (redTt   !=null) turnoutSelect3.setDefaultNamedBean(redTt.getBean());
466        } else if ( DOUBLE_TURNOUT.equals(type)) {
467            var greenTt = ((DoubleTurnoutSignalHead) signalHeadBeingEdited).getGreen();
468            var redTt = ((DoubleTurnoutSignalHead) signalHeadBeingEdited).getRed();
469            if (greenTt !=null) turnoutSelect1.setDefaultNamedBean(greenTt.getBean());
470            if (redTt   !=null) turnoutSelect2.setDefaultNamedBean(redTt.getBean());
471        } else if ( SINGLE_TURNOUT.equals(type)) {
472            var tTt = ((SingleTurnoutSignalHead) signalHeadBeingEdited).getOutput();
473            if (tTt !=null) turnoutSelect1.setDefaultNamedBean(tTt.getBean());
474            setSignalStateInBox(signalStateBox2, ((SingleTurnoutSignalHead) signalHeadBeingEdited).getOnAppearance());
475            setSignalStateInBox(signalStateBox3, ((SingleTurnoutSignalHead) signalHeadBeingEdited).getOffAppearance());
476        } else if (LSDEC.equals(type)) {  // LDT LS-DEC
477            var greenT = ((LsDecSignalHead) signalHeadBeingEdited).getGreen();
478            var yellowT = ((LsDecSignalHead) signalHeadBeingEdited).getYellow();
479            var redT = ((LsDecSignalHead) signalHeadBeingEdited).getRed();
480            var greenTFlash = ((LsDecSignalHead) signalHeadBeingEdited).getFlashGreen();
481            var yellowTFlash = ((LsDecSignalHead) signalHeadBeingEdited).getFlashYellow();
482            var redTFlash = ((LsDecSignalHead) signalHeadBeingEdited).getFlashRed();
483            var darkT = ((LsDecSignalHead) signalHeadBeingEdited).getDark();
484            if (greenT!=null) turnoutSelect1.setDefaultNamedBean(greenT.getBean());
485            setTurnoutStateInBox(turnoutStateBox1, ((LsDecSignalHead) signalHeadBeingEdited).getGreenState(), TURNOUT_STATE_VALUES);
486            if (yellowT!=null) turnoutSelect2.setDefaultNamedBean(yellowT.getBean());
487            setTurnoutStateInBox(turnoutStateBox2, ((LsDecSignalHead) signalHeadBeingEdited).getYellowState(), TURNOUT_STATE_VALUES);
488            if (redT!=null) turnoutSelect3.setDefaultNamedBean(redT.getBean());
489            setTurnoutStateInBox(turnoutStateBox3, ((LsDecSignalHead) signalHeadBeingEdited).getRedState(), TURNOUT_STATE_VALUES);
490            if (greenTFlash!=null) turnoutSelect4.setDefaultNamedBean(greenTFlash.getBean());
491            setTurnoutStateInBox(turnoutStateBox4, ((LsDecSignalHead) signalHeadBeingEdited).getFlashGreenState(), TURNOUT_STATE_VALUES);
492            if (yellowTFlash!=null) turnoutSelect5.setDefaultNamedBean(yellowTFlash.getBean());
493            setTurnoutStateInBox(turnoutStateBox5, ((LsDecSignalHead) signalHeadBeingEdited).getFlashYellowState(), TURNOUT_STATE_VALUES);
494            if (redTFlash!=null) turnoutSelect6.setDefaultNamedBean(redTFlash.getBean());
495            setTurnoutStateInBox(turnoutStateBox6, ((LsDecSignalHead) signalHeadBeingEdited).getFlashRedState(), TURNOUT_STATE_VALUES);
496            if (darkT!=null) turnoutSelect7.setDefaultNamedBean(darkT.getBean());
497            setTurnoutStateInBox(turnoutStateBox7, ((LsDecSignalHead) signalHeadBeingEdited).getDarkState(), TURNOUT_STATE_VALUES);
498        } else if (ACELA_ASPECT.equals(type)) {
499            AcelaNode tNode = AcelaAddress.getNodeFromSystemName(signalHeadBeingEdited.getSystemName(), InstanceManager.getDefault(AcelaSystemConnectionMemo.class));
500            if (tNode == null) {
501                // node does not exist, ignore call
502                log.error("Can't find new Acela Signal with name '{}", signalHeadBeingEdited.getSystemName());
503                return;
504            }
505            int headnumber = Integer.parseInt(signalHeadBeingEdited.getSystemName().substring(2));
506            setSignalheadTypeInBox(acelaHeadTypeBox, tNode.getOutputSignalHeadType(headnumber), ACELA_SIG_HEAD_TYPE_VALUES);
507        } else if (DCC_SIGNAL_DECODER.equals(type)) {
508            for (int i = 0; i < DccSignalHead.getDefaultValidStates().length; i++) {
509                dccAspectSpinners[i].setValue(((DccSignalHead) signalHeadBeingEdited).getOutputForAppearance(signalHeadBeingEdited.getValidStates()[i]));
510            }
511            dccOffSetAddressCheckBox.setSelected(((DccSignalHead) signalHeadBeingEdited).useAddressOffSet());
512            dccPacketSendCountSpinner.setValue(((DccSignalHead) signalHeadBeingEdited).getDccSignalHeadPacketSendCount());
513
514            for (CommandStation cs : InstanceManager.getList(CommandStation.class)) {
515                if ( signalHeadBeingEdited.getSystemName().startsWith(cs.getSystemPrefix())) {
516                    prefixBox.setSelectedItem(cs.getUserName());
517                }
518            }
519        } else if (MERG_SIGNAL_DRIVER.equals(type)) {
520            setUkSignalAspectsFromBox(numberUkAspectsBox, ((MergSD2SignalHead) signalHeadBeingEdited).getAspects());
521            
522            if (((MergSD2SignalHead) signalHeadBeingEdited).getHome()) {
523                setUkSignalType(ukSignalSemaphoreTypeBox, Bundle.getMessage("HomeSignal")); // "Home"
524            } else {
525                setUkSignalType(ukSignalSemaphoreTypeBox, Bundle.getMessage("DistantSignal")); //"Distant"
526            }
527            
528            var input1 = ((MergSD2SignalHead) signalHeadBeingEdited).getInput1();
529            var input2 = ((MergSD2SignalHead) signalHeadBeingEdited).getInput2();
530            var input3 = ((MergSD2SignalHead) signalHeadBeingEdited).getInput3();
531            if (input1!=null) turnoutSelect3.setDefaultNamedBean(input1.getBean());
532            if (input2!=null) turnoutSelect4.setDefaultNamedBean(input2.getBean());
533            if (input3!=null) turnoutSelect5.setDefaultNamedBean(input3.getBean());
534
535        }
536
537    }
538    
539    private String getNameFromClass(@Nonnull String className){
540        switch (className) {
541            case "jmri.implementation.QuadOutputSignalHead":
542                return QUAD_OUTPUT;
543            case "jmri.implementation.TripleTurnoutSignalHead":
544                return TRIPLE_TURNOUT;
545            case "jmri.implementation.TripleOutputSignalHead":
546                return TRIPLE_OUTPUT;
547            case "jmri.implementation.DoubleTurnoutSignalHead":
548                return DOUBLE_TURNOUT;
549            case "jmri.implementation.SingleTurnoutSignalHead":
550                return SINGLE_TURNOUT;
551            case "jmri.implementation.VirtualSignalHead":
552                return VIRTUAL_HEAD;
553            case "jmri.implementation.LsDecSignalHead":  // LDT LS-DEC
554                return LSDEC;
555            case "jmri.implementation.SE8cSignalHead":
556                return SE8C4_ASPECT;
557            case "jmri.jmrix.grapevine.SerialSignalHead":
558                return GRAPEVINE;
559            case "jmri.jmrix.acela.AcelaSignalHead":
560                return ACELA_ASPECT;
561            case "jmri.implementation.DccSignalHead":
562                return DCC_SIGNAL_DECODER;
563            case "jmri.implementation.MergSD2SignalHead":
564                return MERG_SIGNAL_DRIVER;
565            default:
566                throw new IllegalArgumentException("No implementation for " + className);
567        }
568    }
569
570    private void typeChanged() {
571        hideAllPanels();
572
573        if ( signalHeadBeingEdited == null ){
574            systemNameField.setToolTipText(Bundle.getMessage("SignalHeadSysNameTooltip"));
575        } else {
576            systemNameField.setToolTipText(null);
577        }
578        
579        systemNameLabel.setText(Bundle.getMessage("LabelSystemName"));
580        systemNameLabel.setVisible(true);
581        systemNameField.setVisible(true);
582        userNameLabel.setText(Bundle.getMessage("LabelUserName"));
583        userNameLabel.setVisible(true);
584        userNameField.setVisible(true);
585
586        String type = (String)headTypeBox.getSelectedItem();
587        if ( QUAD_OUTPUT.equals(type)) {
588            centrePanBorder1.setTitle(Bundle.getMessage("LabelGreenTurnoutNumber"));
589            centrePanel1.setVisible(true);
590            turnoutSelect1.setVisible(true);
591            centrePanBorder2.setTitle(Bundle.getMessage("LabelYellowTurnoutNumber"));
592            centrePanel2.setVisible(true);
593            turnoutSelect2.setVisible(true);
594            centrePanBorder3.setTitle(Bundle.getMessage("LabelRedTurnoutNumber"));
595            centrePanel3.setVisible(true);
596            turnoutSelect3.setVisible(true);
597            centrePanBorder4.setTitle(Bundle.getMessage("LabelLunarTurnoutNumber"));
598            centrePanel4.setVisible(true);
599            turnoutSelect4.setVisible(true);
600        } else if (TRIPLE_TURNOUT.equals(type)) {
601            centrePanBorder1.setTitle(Bundle.getMessage("LabelGreenTurnoutNumber"));
602            centrePanel1.setVisible(true);
603            turnoutSelect1.setVisible(true);
604            centrePanBorder2.setTitle(Bundle.getMessage("LabelYellowTurnoutNumber"));
605            centrePanel2.setVisible(true);
606            turnoutSelect2.setVisible(true);
607            centrePanBorder3.setTitle(Bundle.getMessage("LabelRedTurnoutNumber"));
608            centrePanel3.setVisible(true);
609            turnoutSelect3.setVisible(true);
610        } else if ( TRIPLE_OUTPUT.equals(type)) {
611            centrePanBorder1.setTitle(Bundle.getMessage("LabelGreenTurnoutNumber"));
612            centrePanel1.setVisible(true);
613            turnoutSelect1.setVisible(true);
614            centrePanBorder2.setTitle(Bundle.getMessage("LabelBlueTurnoutNumber"));
615            centrePanel2.setVisible(true);
616            turnoutSelect2.setVisible(true);
617            centrePanBorder3.setTitle(Bundle.getMessage("LabelRedTurnoutNumber"));
618            centrePanel3.setVisible(true);
619            turnoutSelect3.setVisible(true);
620        } else if ( DOUBLE_TURNOUT.equals(type)) {
621            centrePanBorder1.setTitle(Bundle.getMessage("LabelGreenTurnoutNumber"));
622            centrePanel1.setVisible(true);
623            turnoutSelect1.setVisible(true);
624            centrePanBorder2.setTitle(Bundle.getMessage("LabelRedTurnoutNumber"));
625            centrePanel2.setVisible(true);
626            turnoutSelect2.setVisible(true);
627        } else if ( SINGLE_TURNOUT.equals(type)) {
628            centrePanBorder1.setTitle(Bundle.getMessage("LabelTurnoutNumber"));
629            centrePanel1.setVisible(true);
630            turnoutSelect1.setVisible(true);
631            centrePanBorder2.setTitle(Bundle.getMessage("LabelTurnoutThrownAppearance"));
632            centrePanel2.setVisible(true);
633            signalStateBox2.setVisible(true);
634            centrePanBorder3.setTitle(Bundle.getMessage("LabelTurnoutClosedAppearance"));
635            centrePanel3.setVisible(true);
636            signalStateBox3.setVisible(true);
637        } else if (LSDEC.equals(type)) {  // LDT LS-DEC
638            centrePanBorder1.setTitle(Bundle.getMessage("LabelGreenTurnoutNumber"));
639            centrePanel1.setVisible(true);
640            turnoutSelect1.setVisible(true);
641            stateLabel1.setVisible(true);
642            turnoutStateBox1.setVisible(true);
643
644            centrePanBorder2.setTitle(Bundle.getMessage("LabelYellowTurnoutNumber"));
645            centrePanel2.setVisible(true);
646            turnoutSelect2.setVisible(true);
647            stateLabel2.setVisible(true);
648            turnoutStateBox2.setVisible(true);
649
650            centrePanBorder3.setTitle(Bundle.getMessage("LabelRedTurnoutNumber"));
651            centrePanel3.setVisible(true);
652            turnoutSelect3.setVisible(true);
653            stateLabel3.setVisible(true);
654            turnoutStateBox3.setVisible(true);
655
656            centrePanBorder4.setTitle(Bundle.getMessage("LabelFlashGreenTurnoutNumber"));
657            centrePanel4.setVisible(true);
658            turnoutSelect4.setVisible(true);
659            stateLabel4.setVisible(true);
660            turnoutStateBox4.setVisible(true);
661
662            centrePanBorder5.setTitle(Bundle.getMessage("LabelFlashYellowTurnoutNumber"));
663            centrePanel5.setVisible(true);
664            turnoutSelect5.setVisible(true);
665            stateLabel5.setVisible(true);
666            turnoutStateBox5.setVisible(true);
667
668            centrePanBorder6.setTitle(Bundle.getMessage("LabelFlashRedTurnoutNumber"));
669            centrePanel6.setVisible(true);
670            turnoutSelect6.setVisible(true);
671            stateLabel6.setVisible(true);
672            turnoutStateBox6.setVisible(true);
673
674            centrePanBorder7.setTitle(Bundle.getMessage("LabelDarkTurnoutNumber"));
675            centrePanel7.setVisible(true);
676            turnoutSelect7.setVisible(true);
677            stateLabel7.setVisible(true);
678            turnoutStateBox7.setVisible(true);
679        } else if (ACELA_ASPECT.equals(type)) {
680            acelaHeadPanel.setVisible(true);
681            if ( signalHeadBeingEdited == null ) {
682                systemNameLabel.setText(Bundle.getMessage("LabelSignalheadNumber")); // displays ID instead of -number
683            }
684            systemNameField.setToolTipText(Bundle.getMessage("SignalHeadAcelaTooltip"));
685        } else if (DCC_SIGNAL_DECODER.equals(type)) {
686            if ( signalHeadBeingEdited == null ) {
687                systemNameLabel.setText(Bundle.getMessage("LabelSignalheadNumber")); // displays ID instead of -number
688            }
689            dccOptionsPanel.setVisible(true);
690            prefixBox.setVisible(true);
691            prefixBox.setEnabled(signalHeadBeingEdited==null);
692            prefixBoxLabel.setVisible(true);
693            centrePanBorder2.setTitle(Bundle.getMessage("LabelAspectNumbering"));
694            centrePanel2.setVisible(true);
695            dccAppearanceNumberingPanel.setVisible(true);
696        } else if (MERG_SIGNAL_DRIVER.equals(type)) {
697            centrePanBorder1.setTitle(Bundle.getMessage("NumberOfAppearances")); // same as line 1054
698            centrePanel1.setVisible(true);
699            numberUkAspectsBox.setVisible(true);
700
701            centrePanBorder2.setTitle(Bundle.getMessage("UseAs")); // same as line 1090
702            centrePanel2.setVisible(true);
703            turnoutSelect2.setVisible(false);
704            ukSignalSemaphoreTypeBox.setVisible(true);
705
706            centrePanBorder3.setTitle(Bundle.getMessage("InputNum", " 1 "));
707            centrePanel3.setVisible(true);
708            turnoutSelect3.setVisible(true);
709            centrePanBorder4.setTitle(Bundle.getMessage("InputNum", " 2 "));
710            centrePanel4.setVisible(true);
711            turnoutSelect4.setVisible(true);
712
713            centrePanBorder5.setTitle(Bundle.getMessage("InputNum", " 3 "));
714            centrePanel5.setVisible(true);
715            turnoutSelect5.setVisible(true);
716
717            setUkSignalAspectsFromBox(numberUkAspectsBox, 2);
718            ukAspectChange();
719        } else if ( SE8C4_ASPECT.equals(type)) {
720            systemNameField.setVisible(signalHeadBeingEdited != null);
721            systemNameLabel.setVisible(signalHeadBeingEdited != null);
722
723            centrePanBorder1.setTitle(Bundle.getMessage("LabelTurnoutNumber"));
724            centrePanel1.setVisible(true);
725            turnoutSelect1.setVisible(true);
726
727            centrePanBorder2.setTitle(Bundle.getMessage("LabelSecondNumber"));
728            centrePanel2.setVisible(true);
729            turnoutSelect2.setVisible(true);
730        }
731        else if ( GRAPEVINE.equals(type)) {}
732        else if ( VIRTUAL_HEAD.equals(type)) {}
733        else {
734            log.error("Cannot edit SignalHead of unrecognized type: {}", type);
735        }
736        pack();
737    }
738
739    private void initTypeBox() {
740        headTypeBox = new JComboBox<>(new String[]{ACELA_ASPECT, DCC_SIGNAL_DECODER, DOUBLE_TURNOUT, LSDEC, MERG_SIGNAL_DRIVER, QUAD_OUTPUT, SINGLE_TURNOUT, SE8C4_ASPECT, TRIPLE_TURNOUT, TRIPLE_OUTPUT, VIRTUAL_HEAD});
741        // If no DCC Command station is found, remove the DCC Signal Decoder option.
742        if (prefixBox.getItemCount() == 0) {
743            headTypeBox.removeItem(DCC_SIGNAL_DECODER);
744        }
745        if (!InstanceManager.getList(GrapevineSystemConnectionMemo.class).isEmpty()) {
746            headTypeBox.addItem(GRAPEVINE);
747        }
748        if (InstanceManager.getList(AcelaSystemConnectionMemo.class).isEmpty()) {
749            headTypeBox.removeItem(ACELA_ASPECT);
750        }
751        headTypeBox.addActionListener(e1 -> typeChanged());
752        JComboBoxUtil.setupComboBoxMaxRows(headTypeBox);
753        headTypeBox.setEnabled(signalHeadBeingEdited==null);
754    }
755
756    private void initDccAppearancePanel() {
757        dccAppearanceNumberingPanel = new JPanel();
758        dccAppearanceNumberingPanel.setLayout(new GridLayout(0, 2));
759        dccAspectSpinners = new JSpinner[DccSignalHead.getDefaultValidStates().length];
760        for (int i = 0; i < DccSignalHead.getDefaultValidStates().length; i++) {
761            String aspect = DccSignalHead.getDefaultValidStateNames()[i];
762            dccAppearanceNumberingPanel.add(new JLabel(aspect));
763
764            SpinnerNumberModel DccSpinnerModel = new SpinnerNumberModel(1, 0, 31, 1);
765            JSpinner tmp = new JSpinner(DccSpinnerModel);
766            tmp.setValue(DccSignalHead.getDefaultNumberForAppearance(DccSignalHead.getDefaultValidStates()[i]));
767            dccAspectSpinners[i] = tmp; // store the whole JSpinner
768            dccAppearanceNumberingPanel.add(tmp); // and display that copy on the JPanel
769            tmp.setToolTipText(Bundle.getMessage("DccAccessoryAspect", i));
770        }
771    }
772
773    private void setSignalStateInBox(JComboBox<String> box, int state) {
774        switch (state) {
775            case SignalHead.DARK:
776                box.setSelectedIndex(0);
777                break;
778            case SignalHead.RED:
779                box.setSelectedIndex(1);
780                break;
781            case SignalHead.LUNAR:
782                box.setSelectedIndex(2);
783                break;
784            case SignalHead.YELLOW:
785                box.setSelectedIndex(3);
786                break;
787            case SignalHead.GREEN:
788                box.setSelectedIndex(4);
789                break;
790            case SignalHead.FLASHRED:
791                box.setSelectedIndex(5);
792                break;
793            case SignalHead.FLASHLUNAR:
794                box.setSelectedIndex(6);
795                break;
796            case SignalHead.FLASHYELLOW:
797                box.setSelectedIndex(7);
798                break;
799            case SignalHead.FLASHGREEN:
800                box.setSelectedIndex(8);
801                break;
802            default:
803                log.error("unexpected Signal state value: {}", state);
804        }
805    }
806
807    private void setTurnoutStateInBox(JComboBox<String> box, int state, int[] iTurnoutStates) {
808        if (state == iTurnoutStates[0]) {
809            box.setSelectedIndex(0);
810        } else if (state == iTurnoutStates[1]) {
811            box.setSelectedIndex(1);
812        } else {
813            log.error("unexpected turnout state value: {}", state);
814        }
815    }
816
817    private int turnoutStateFromBox(JComboBox<String> box) {
818        String mode = (String) box.getSelectedItem();
819        int result = StringUtil.getStateFromName(mode, TURNOUT_STATE_VALUES, TURNOUT_STATE_STRINGS);
820        if (result < 0) {
821            log.warn("unexpected mode string in turnoutMode: {}", mode);
822            throw new IllegalArgumentException();
823        }
824        return result;
825    }
826
827    private void setSignalheadTypeInBox(JComboBox<String> box, int state, int[] iSignalheadTypes) {
828        if (state == iSignalheadTypes[0]) {
829            box.setSelectedIndex(0);
830        } else if (state == iSignalheadTypes[1]) {
831            box.setSelectedIndex(1);
832        } else if (state == iSignalheadTypes[2]) {
833            box.setSelectedIndex(2);
834        } else if (state == iSignalheadTypes[3]) {
835            box.setSelectedIndex(3);
836        } else {
837            log.error("unexpected signalhead type value: {}", state);
838        }
839    }
840
841    private int signalStateFromBox(JComboBox<String> box) {
842        String mode = (String) box.getSelectedItem();
843        int result = StringUtil.getStateFromName(mode, SIGNAL_STATE_VALUES, SIGNAL_STATE_STRINGS);
844
845        if (result < 0) {
846            log.warn("unexpected mode string in signalMode: {}", mode);
847            throw new IllegalArgumentException();
848        }
849        return result;
850    }
851
852    private int ukSignalAspectsFromBox(JComboBox<String> box) {
853        //String mode = (String)box.getSelectedItem();
854        switch (box.getSelectedIndex()) {
855            case 0:
856                return 2;
857            case 1:
858                return 3;
859            case 2:
860                return 4;
861            default:
862                log.warn("unexpected appearance{}", box.getSelectedItem());
863                throw new IllegalArgumentException();
864        }
865    }
866
867    private void setUkSignalAspectsFromBox(JComboBox<String> box, int val) {
868        switch (val) {
869            case 2:
870                box.setSelectedIndex(0);
871                break;
872            case 3:
873                box.setSelectedIndex(1);
874                break;
875            case 4:
876                box.setSelectedIndex(2);
877                break;
878            default:
879                log.error("Unexpected Signal Appearance{}", val);
880                break;
881        }
882    }
883
884    private String ukSignalTypeFromBox(JComboBox<String> box) {
885        //String mode = (String)box.getSelectedItem();
886        switch (box.getSelectedIndex()) {
887            case 0:
888                return "Home"; // NOI18N
889            case 1:
890                return "Distant"; // NOI18N
891            default:
892                log.warn("unexpected appearance{}", box.getSelectedItem());
893                throw new IllegalArgumentException();
894        }
895    }
896
897    private void setUkSignalType(JComboBox<String> box, String val) {
898        if (val.equals(UK_SEMAPHORE_TYPES[0])) {
899            box.setSelectedIndex(0);
900        } else if (val.equals(UK_SEMAPHORE_TYPES[1])) {
901            box.setSelectedIndex(1);
902        } else {
903            log.error("Unexpected Signal Type {}", val);
904        }
905    }
906
907    private void ukAspectChange() {
908        switch (ukSignalAspectsFromBox(numberUkAspectsBox)) {
909            case 2:
910                centrePanel2.setVisible(true);
911                centrePanel4.setVisible(false);
912                turnoutSelect4.setVisible(false);
913                centrePanel5.setVisible(false);
914                turnoutSelect5.setVisible(false);
915                ukSignalSemaphoreTypeBox.setVisible(true);
916                break;
917            case 3:
918                centrePanel2.setVisible(false);
919                centrePanel4.setVisible(true);
920                turnoutSelect4.setVisible(true);
921                centrePanel5.setVisible(false);
922                turnoutSelect5.setVisible(false);
923                ukSignalSemaphoreTypeBox.setVisible(false);
924                setUkSignalType(ukSignalSemaphoreTypeBox, Bundle.getMessage("HomeSignal"));
925                break;
926            case 4:
927                centrePanel2.setVisible(false);
928                centrePanel4.setVisible(true);
929                turnoutSelect4.setVisible(true);
930                centrePanel5.setVisible(true);
931                turnoutSelect5.setVisible(true);
932                ukSignalSemaphoreTypeBox.setVisible(false);
933                setUkSignalType(ukSignalSemaphoreTypeBox, Bundle.getMessage("HomeSignal"));
934                break;
935            default:
936                break;
937        }
938        pack();
939    }
940
941    @SuppressWarnings("fallthrough")
942    @SuppressFBWarnings(value = "SF_SWITCH_FALLTHROUGH")
943    private void updateEditPressed(ActionEvent e) {
944        log.debug("newedit {}", e);
945        if ( signalHeadBeingEdited==null ){
946            createNewSigHead();
947            return;
948        }
949        String nam = userNameField.getText();
950        // check if user name changed
951        String uname = signalHeadBeingEdited.getUserName();
952        // TODO: not sure this if statement is right. I think (uname != null && !uname.equals(nam))
953        if (!((uname != null) && (uname.equals(nam)))) {
954            if (checkUserName(nam)) {
955                signalHeadBeingEdited.setUserName(nam);
956            } else {
957                return;
958            }
959        }
960        // update according to class of signal head
961        String className = signalHeadBeingEdited.getClass().getName();
962        switch (className) {
963            case "jmri.implementation.QuadOutputSignalHead": {
964                var headType = ((QuadOutputSignalHead) signalHeadBeingEdited).getGreen();
965                Turnout t1 = updateTurnoutFromPanel(turnoutSelect1, "SignalHead:" + systemNameLabel.getText() + ":Green", 
966                    (headType==null ? null : headType.getBean()), centrePanBorder1.getTitle());
967
968                if (t1 == null) {
969                    return;
970                } else {
971                    ((QuadOutputSignalHead) signalHeadBeingEdited).setGreen(nbhm.getNamedBeanHandle(turnoutSelect1.getDisplayName(), t1));
972                }
973
974                headType = ((QuadOutputSignalHead) signalHeadBeingEdited).getYellow();
975                Turnout t2 = updateTurnoutFromPanel(turnoutSelect2, "SignalHead:" + systemNameLabel.getText() + ":Yellow", 
976                    (headType==null ? null : headType.getBean()), centrePanBorder2.getTitle());
977                if (t2 == null) {
978                    return;
979                } else {
980                    ((QuadOutputSignalHead) signalHeadBeingEdited).setYellow(nbhm.getNamedBeanHandle(turnoutSelect2.getDisplayName(), t2));
981                }
982
983                headType = ((QuadOutputSignalHead) signalHeadBeingEdited).getRed();
984                Turnout t3 = updateTurnoutFromPanel(turnoutSelect3, "SignalHead:" + systemNameLabel.getText() + ":Red",
985                    (headType==null ? null : headType.getBean()), centrePanBorder3.getTitle());
986                if (t3 == null) {
987                    return;
988                } else {
989                    ((QuadOutputSignalHead) signalHeadBeingEdited).setRed(nbhm.getNamedBeanHandle(turnoutSelect3.getDisplayName(), t3));
990                }
991
992                headType = ((QuadOutputSignalHead) signalHeadBeingEdited).getLunar();
993                Turnout t4 = updateTurnoutFromPanel(turnoutSelect4, "SignalHead:" + systemNameLabel.getText() + ":Lunar", 
994                    (headType==null ? null : headType.getBean()), centrePanBorder4.getTitle());
995                if (t4 == null) {
996                    return;
997                } else {
998                    ((QuadOutputSignalHead) signalHeadBeingEdited).setLunar(nbhm.getNamedBeanHandle(turnoutSelect4.getDisplayName(), t4));
999                }
1000                break;
1001            }
1002            case "jmri.implementation.TripleTurnoutSignalHead": {
1003                
1004                var headType = ((TripleTurnoutSignalHead) signalHeadBeingEdited).getGreen();
1005                Turnout t1 = updateTurnoutFromPanel(turnoutSelect1, "SignalHead:" + systemNameLabel.getText() + ":Green", 
1006                    (headType==null ? null : headType.getBean()), centrePanBorder1.getTitle());
1007                if (t1 == null) {
1008                    return;
1009                } else {
1010                    ((TripleTurnoutSignalHead) signalHeadBeingEdited).setGreen(nbhm.getNamedBeanHandle(turnoutSelect1.getDisplayName(), t1));
1011                }
1012
1013                headType = ((TripleTurnoutSignalHead) signalHeadBeingEdited).getYellow();
1014                Turnout t2 = updateTurnoutFromPanel(turnoutSelect2, "SignalHead:" + systemNameLabel.getText() + ":Yellow", 
1015                    (headType==null ? null : headType.getBean()), centrePanBorder2.getTitle());
1016                if (t2 == null) {
1017                    return;
1018                } else {
1019                    ((TripleTurnoutSignalHead) signalHeadBeingEdited).setYellow(nbhm.getNamedBeanHandle(turnoutSelect2.getDisplayName(), t2));
1020                }
1021
1022                headType = ((TripleTurnoutSignalHead) signalHeadBeingEdited).getRed();
1023                Turnout t3 = updateTurnoutFromPanel(turnoutSelect3, "SignalHead:" + systemNameLabel.getText() + ":Red", 
1024                    (headType==null ? null : headType.getBean()), centrePanBorder3.getTitle());
1025                if (t3 == null) {
1026                    return;
1027                } else {
1028                    ((TripleTurnoutSignalHead) signalHeadBeingEdited).setRed(nbhm.getNamedBeanHandle(turnoutSelect3.getDisplayName(), t3));
1029                }
1030                break;
1031            }
1032            case "jmri.implementation.TripleOutputSignalHead": {
1033
1034                var headType = ((TripleOutputSignalHead) signalHeadBeingEdited).getGreen();
1035                Turnout t1 = updateTurnoutFromPanel(turnoutSelect1, "SignalHead:" + systemNameLabel.getText() + ":Green", 
1036                    (headType==null ? null : headType.getBean()), centrePanBorder1.getTitle());
1037                if (t1 == null) {
1038                    return;
1039                } else {
1040                    ((TripleOutputSignalHead) signalHeadBeingEdited).setGreen(nbhm.getNamedBeanHandle(turnoutSelect1.getDisplayName(), t1));
1041                }
1042
1043                headType = ((TripleOutputSignalHead) signalHeadBeingEdited).getBlue();
1044                Turnout t2 = updateTurnoutFromPanel(turnoutSelect2, "SignalHead:" + systemNameLabel.getText() + ":Blue", 
1045                    (headType==null ? null : headType.getBean()), centrePanBorder2.getTitle());
1046                if (t2 == null) {
1047                    return;
1048                } else {
1049                    ((TripleOutputSignalHead) signalHeadBeingEdited).setBlue(nbhm.getNamedBeanHandle(turnoutSelect2.getDisplayName(), t2));
1050                }
1051
1052                headType = ((TripleOutputSignalHead) signalHeadBeingEdited).getRed();
1053                Turnout t3 = updateTurnoutFromPanel(turnoutSelect3, "SignalHead:" + systemNameLabel.getText() + ":Red", 
1054                    (headType==null ? null : headType.getBean()), centrePanBorder3.getTitle());
1055                if (t3 == null) {
1056                    return;
1057                } else {
1058                    ((TripleOutputSignalHead) signalHeadBeingEdited).setRed(nbhm.getNamedBeanHandle(turnoutSelect3.getDisplayName(), t3));
1059                }
1060                break;
1061            }
1062            case "jmri.implementation.DoubleTurnoutSignalHead": {
1063                var headType = ((DoubleTurnoutSignalHead) signalHeadBeingEdited).getGreen();
1064                Turnout t1 = updateTurnoutFromPanel(turnoutSelect1, "SignalHead:" + systemNameLabel.getText() + ":Green", 
1065                    (headType==null ? null : headType.getBean()), centrePanBorder1.getTitle());
1066                headType = ((DoubleTurnoutSignalHead) signalHeadBeingEdited).getRed();
1067                Turnout t2 = updateTurnoutFromPanel(turnoutSelect2, "SignalHead:" + systemNameLabel.getText() + ":Red", 
1068                    (headType==null ? null : headType.getBean()), centrePanBorder2.getTitle());
1069                if (t1 == null) {
1070                    return;
1071                } else {
1072                    ((DoubleTurnoutSignalHead) signalHeadBeingEdited).setGreen(nbhm.getNamedBeanHandle(turnoutSelect1.getDisplayName(), t1));
1073                }
1074                if (t2 == null) {
1075                    return;
1076                } else {
1077                    ((DoubleTurnoutSignalHead) signalHeadBeingEdited).setRed(nbhm.getNamedBeanHandle(turnoutSelect2.getDisplayName(), t2));
1078                }
1079                break;
1080            }
1081            case "jmri.implementation.SingleTurnoutSignalHead": {
1082                var headType = ((SingleTurnoutSignalHead) signalHeadBeingEdited).getOutput();
1083                Turnout t1 = updateTurnoutFromPanel(turnoutSelect1, "SignalHead:" + systemNameLabel.getText() + ":" + signalStateBox2.getSelectedItem() + ":" + signalStateBox3.getSelectedItem(),
1084                    (headType==null ? null : headType.getBean()), centrePanBorder1.getTitle());
1085                if (t1 == null) {
1086                    noTurnoutMessage(centrePanBorder1.getTitle(), turnoutSelect1.getDisplayName());
1087                    return;
1088                }
1089                ((SingleTurnoutSignalHead) signalHeadBeingEdited).setOutput(nbhm.getNamedBeanHandle(turnoutSelect1.getDisplayName(), t1));
1090                ((SingleTurnoutSignalHead) signalHeadBeingEdited).setOnAppearance(signalStateFromBox(signalStateBox2));
1091                ((SingleTurnoutSignalHead) signalHeadBeingEdited).setOffAppearance(signalStateFromBox(signalStateBox3));
1092                break;
1093            }
1094            case "jmri.implementation.LsDecSignalHead": {
1095                var headType = ((LsDecSignalHead) signalHeadBeingEdited).getGreen();
1096                Turnout t1 = updateTurnoutFromPanel(turnoutSelect1, "SignalHead:" + systemNameLabel.getText() + ":Green", 
1097                    (headType==null ? null : headType.getBean()), centrePanBorder1.getTitle());
1098                if (t1 == null) {
1099                    return;
1100                } else {
1101                    ((LsDecSignalHead) signalHeadBeingEdited).setGreen(nbhm.getNamedBeanHandle(turnoutSelect1.getDisplayName(), t1));
1102                    ((LsDecSignalHead) signalHeadBeingEdited).setGreenState(turnoutStateFromBox(turnoutStateBox1));
1103                }
1104
1105                headType = ((LsDecSignalHead) signalHeadBeingEdited).getYellow();
1106                Turnout t2 = updateTurnoutFromPanel(turnoutSelect2, "SignalHead:" + systemNameLabel.getText() + ":Yellow", 
1107                    (headType==null ? null : headType.getBean()), centrePanBorder2.getTitle());
1108                if (t2 == null) {
1109                    return;
1110                } else {
1111                    ((LsDecSignalHead) signalHeadBeingEdited).setYellow(nbhm.getNamedBeanHandle(turnoutSelect2.getDisplayName(), t2));
1112                    ((LsDecSignalHead) signalHeadBeingEdited).setYellowState(turnoutStateFromBox(turnoutStateBox2));
1113                }
1114
1115                headType = ((LsDecSignalHead) signalHeadBeingEdited).getRed();
1116                Turnout t3 = updateTurnoutFromPanel(turnoutSelect3, "SignalHead:" + systemNameLabel.getText() + ":Red", 
1117                    (headType==null ? null : headType.getBean()), centrePanBorder3.getTitle());
1118                if (t3 == null) {
1119                    return;
1120                } else {
1121                    ((LsDecSignalHead) signalHeadBeingEdited).setRed(nbhm.getNamedBeanHandle(turnoutSelect3.getDisplayName(), t3));
1122                    ((LsDecSignalHead) signalHeadBeingEdited).setRedState(turnoutStateFromBox(turnoutStateBox3));
1123                }
1124
1125                headType = ((LsDecSignalHead) signalHeadBeingEdited).getFlashGreen();
1126                Turnout t4 = updateTurnoutFromPanel(turnoutSelect4, "SignalHead:" + systemNameLabel.getText() + ":FlashGreen", 
1127                    (headType==null ? null : headType.getBean()), centrePanBorder4.getTitle());
1128                if (t4 == null) {
1129                    return;
1130                } else {
1131                    ((LsDecSignalHead) signalHeadBeingEdited).setFlashGreen(nbhm.getNamedBeanHandle(turnoutSelect4.getDisplayName(), t4));
1132                    ((LsDecSignalHead) signalHeadBeingEdited).setFlashGreenState(turnoutStateFromBox(turnoutStateBox4));
1133                }
1134
1135                headType = ((LsDecSignalHead) signalHeadBeingEdited).getFlashYellow();
1136                Turnout t5 = updateTurnoutFromPanel(turnoutSelect5, "SignalHead:" + systemNameLabel.getText() + ":FlashYellow", 
1137                    (headType==null ? null : headType.getBean()), centrePanBorder5.getTitle());
1138                if (t5 == null) {
1139                    return;
1140                } else {
1141                    ((LsDecSignalHead) signalHeadBeingEdited).setFlashYellow(nbhm.getNamedBeanHandle(turnoutSelect5.getDisplayName(), t5));
1142                    ((LsDecSignalHead) signalHeadBeingEdited).setFlashYellowState(turnoutStateFromBox(turnoutStateBox5));
1143                }
1144
1145                headType = ((LsDecSignalHead) signalHeadBeingEdited).getFlashRed();
1146                Turnout t6 = updateTurnoutFromPanel(turnoutSelect6, "SignalHead:" + systemNameLabel.getText() + ":FlashRed", 
1147                    (headType==null ? null : headType.getBean()), centrePanBorder6.getTitle());
1148                if (t6 == null) {
1149                    return;
1150                } else {
1151                    ((LsDecSignalHead) signalHeadBeingEdited).setFlashRed(nbhm.getNamedBeanHandle(turnoutSelect6.getDisplayName(), t6));
1152                    ((LsDecSignalHead) signalHeadBeingEdited).setFlashRedState(turnoutStateFromBox(turnoutStateBox6));
1153                }
1154
1155                headType = ((LsDecSignalHead) signalHeadBeingEdited).getDark();
1156                Turnout t7 = updateTurnoutFromPanel(turnoutSelect7, "SignalHead:" + systemNameLabel.getText() + ":Dark", 
1157                    (headType==null ? null : headType.getBean()), centrePanBorder7.getTitle());
1158                if (t7 == null) {
1159                    return;
1160                } else {
1161                    ((LsDecSignalHead) signalHeadBeingEdited).setDark(nbhm.getNamedBeanHandle(turnoutSelect7.getDisplayName(), t7));
1162                    ((LsDecSignalHead) signalHeadBeingEdited).setDarkState(turnoutStateFromBox(turnoutStateBox7));
1163                }
1164                break;
1165            }
1166            case "jmri.jmrix.acela.AcelaSignalHead":
1167                AcelaNode tNode = AcelaAddress.getNodeFromSystemName(signalHeadBeingEdited.getSystemName(), InstanceManager.getDefault(AcelaSystemConnectionMemo.class));
1168                if (tNode == null) {
1169                    // node does not exist, ignore call
1170                    log.error("Can't find new Acela Signal with name '{}'", signalHeadBeingEdited.getSystemName());
1171                    return;
1172                }
1173                int headnumber = Integer.parseInt(signalHeadBeingEdited.getSystemName().substring(2));
1174                tNode.setOutputSignalHeadTypeString(headnumber, Objects.requireNonNull(acelaHeadTypeBox.getSelectedItem()).toString());
1175                break;
1176            case "jmri.implementation.MergSD2SignalHead":
1177                switch (ukSignalAspectsFromBox(numberUkAspectsBox)) {
1178                    case 4:
1179                        var input3 = ((MergSD2SignalHead) signalHeadBeingEdited).getInput3();
1180                        Turnout t3 = updateTurnoutFromPanel(turnoutSelect5, (Bundle.getMessage("OutputComment", 
1181                            Bundle.getMessage("BeanNameSignalHead"), systemNameLabel.getText(), 
1182                            Bundle.getMessage("InputNum", "3"))), (input3==null ? null : input3.getBean()), 
1183                                centrePanBorder5.getTitle());
1184                        if (t3 == null) {
1185                            return;
1186                        } else {
1187                            ((MergSD2SignalHead) signalHeadBeingEdited).setInput3(nbhm.getNamedBeanHandle(turnoutSelect5.getDisplayName(), t3));
1188                        }
1189                        // fall through
1190                    case 3:
1191                        var input2 = ((MergSD2SignalHead) signalHeadBeingEdited).getInput2();
1192                        Turnout t2 = updateTurnoutFromPanel(turnoutSelect4, (Bundle.getMessage("OutputComment", 
1193                            Bundle.getMessage("BeanNameSignalHead"), systemNameLabel.getText(), 
1194                            Bundle.getMessage("InputNum", "2"))), (input2==null ? null : input2.getBean()), 
1195                                centrePanBorder4.getTitle());
1196                        if (t2 == null) {
1197                            return;
1198                        } else {
1199                            ((MergSD2SignalHead) signalHeadBeingEdited).setInput2(nbhm.getNamedBeanHandle(turnoutSelect4.getDisplayName(), t2));
1200                        }
1201                        // fall through
1202                    case 2:
1203                        var input1 = ((MergSD2SignalHead) signalHeadBeingEdited).getInput1();
1204                        Turnout t1 = updateTurnoutFromPanel(turnoutSelect3, (Bundle.getMessage("OutputComment", 
1205                            Bundle.getMessage("BeanNameSignalHead"), systemNameLabel.getText(), 
1206                            Bundle.getMessage("InputNum", "1"))), (input1==null ? null : input1.getBean()), 
1207                                centrePanBorder3.getTitle());
1208                        if (t1 == null) {
1209                            return;
1210                        } else {
1211                            ((MergSD2SignalHead) signalHeadBeingEdited).setInput1(nbhm.getNamedBeanHandle(turnoutSelect3.getDisplayName(), t1));
1212                        }
1213                        ((MergSD2SignalHead) signalHeadBeingEdited).setAspects(ukSignalAspectsFromBox(numberUkAspectsBox));
1214                        ((MergSD2SignalHead) signalHeadBeingEdited).setHome(!ukSignalTypeFromBox(ukSignalSemaphoreTypeBox).equals("Distant"));
1215                        break;
1216                    default:
1217                        break;
1218                }
1219                break;
1220            case "jmri.implementation.DccSignalHead":
1221                for (int i = 0; i < dccAspectSpinners.length; i++) {
1222                    int number = (Integer) dccAspectSpinners[i].getValue();
1223                    try {
1224                        ((DccSignalHead) signalHeadBeingEdited).setOutputForAppearance(signalHeadBeingEdited.getValidStates()[i], number);
1225                    } catch (Exception ex) {
1226                        //in theory JSpinner should already have caught a number conversion error.
1227                        log.error("JSpinner for {} did not catch number conversion error", className, ex);
1228                    }
1229                }
1230                ((DccSignalHead) signalHeadBeingEdited).useAddressOffSet(dccOffSetAddressCheckBox.isSelected());
1231                ((DccSignalHead) signalHeadBeingEdited).setDccSignalHeadPacketSendCount(((int) dccPacketSendCountSpinner.getValue()));
1232                break;
1233            case "jmri.implementation.VirtualSignalHead":
1234            case "jmri.implementation.SE8cSignalHead":
1235            case "jmri.jmrix.grapevine.SerialSignalHead":
1236                break;
1237            default:
1238                log.error("Internal error - cannot update signal of type {}", className );
1239                break;
1240        }
1241        // successful
1242        dispose();
1243    }
1244
1245    private void createNewSigHead() {
1246        if (!checkUserName(userNameField.getText())) {
1247            return;
1248        }
1249        SignalHead s;
1250        try {
1251            if (SE8C4_ASPECT.equals(headTypeBox.getSelectedItem())) {
1252                handleSE8cOkPressed();
1253            } else if (ACELA_ASPECT.equals(headTypeBox.getSelectedItem())) {
1254                String inputusername = userNameField.getText();
1255                String inputsysname = systemNameField.getText();
1256                int headnumber;
1257
1258                if (inputsysname.length() == 0) {
1259                    JmriJOptionPane.showMessageDialog(this, Bundle.getMessage("signalHeadEntryWarning"));
1260                    log.warn("must supply a signalhead number (i.e. AH23) using your prefix");
1261                    return;
1262                }
1263
1264                var acelaMemo = InstanceManager.getNullableDefault(AcelaSystemConnectionMemo.class);
1265                if ( acelaMemo == null ){
1266                    JmriJOptionPane.showMessageDialog(this, Bundle.getMessage("SystemNotActiveWarning", "Acela"));
1267                    log.warn("No active Acela connection to create Signal Head");
1268                    return;
1269                }
1270
1271                String acelaPrefix = acelaMemo.getSystemPrefix();
1272                if (inputsysname.length() > 2) {
1273                    int offset = Manager.getSystemPrefixLength(inputsysname);
1274                    if (inputsysname.startsWith(acelaPrefix)) {
1275                        headnumber = Integer.parseInt(inputsysname.substring(offset));
1276                    } else if (checkIntegerOnly(inputsysname)) {
1277                        headnumber = Integer.parseInt(inputsysname);
1278                    } else {
1279                        log.warn("skipping creation of signal head, '{}' does not start with AxH", inputsysname);
1280                        String msg = Bundle.getMessage("acelaSkippingCreation", systemNameField.getText());
1281                        JmriJOptionPane.showMessageDialog(this, msg,
1282                                Bundle.getMessage("WarningTitle"), JmriJOptionPane.ERROR_MESSAGE);
1283                        return;
1284                    }
1285                } else {
1286                    headnumber = Integer.parseInt(inputsysname);
1287                }
1288
1289                AcelaNode acelaNode = AcelaAddress.getNodeFromSystemName(acelaPrefix + "H" + headnumber, InstanceManager.getDefault(AcelaSystemConnectionMemo.class));
1290                if (acelaNode==null) {
1291                    JmriJOptionPane.showMessageDialog(this, 
1292                        Bundle.getMessage("acelaNoNodeFound",Bundle.getMessage("BeanNameSignalHead"),headnumber),
1293                        Bundle.getMessage("ErrorSignalHeadAddFailed",headnumber), JmriJOptionPane.ERROR_MESSAGE);
1294                    return;
1295                }
1296
1297                if (checkSysNameOkBeforeCreating(acelaPrefix + "H" + headnumber)) {
1298                    if (inputusername.length() == 0) {
1299                        s = new AcelaSignalHead(acelaPrefix + "H" + headnumber, InstanceManager.getDefault(AcelaSystemConnectionMemo.class));
1300                    } else {
1301                        s = new AcelaSignalHead(acelaPrefix + "H" + headnumber, inputusername, InstanceManager.getDefault(AcelaSystemConnectionMemo.class));
1302                    }
1303                    InstanceManager.getDefault(SignalHeadManager.class).register(s);
1304                }
1305
1306                int st = acelaSignalheadTypeFromBox(acelaHeadTypeBox);
1307                switch (st) {
1308                    case 1:
1309                        acelaNode.setOutputSignalHeadType(headnumber, AcelaNode.DOUBLE);
1310                        break;
1311                    case 2:
1312                        acelaNode.setOutputSignalHeadType(headnumber, AcelaNode.TRIPLE);
1313                        break;
1314                    case 3:
1315                        acelaNode.setOutputSignalHeadType(headnumber, AcelaNode.BPOLAR);
1316                        break;
1317                    case 4:
1318                        acelaNode.setOutputSignalHeadType(headnumber, AcelaNode.WIGWAG);
1319                        break;
1320                    default:
1321                        log.warn("Unexpected Acela Aspect type: {}", st);
1322                        acelaNode.setOutputSignalHeadType(headnumber, AcelaNode.UKNOWN);
1323                        break;  // default to triple
1324                }
1325
1326            } else if (GRAPEVINE.equals(headTypeBox.getSelectedItem())) {
1327                // the turnout field must hold a GxH system name (Gx = multichar prefix)
1328                if (systemNameField.getText().length() == 0) {
1329                    JmriJOptionPane.showMessageDialog(this, Bundle.getMessage("signalHeadEntryWarning"));
1330                    log.warn("must supply a signalhead number (i.e. GH23) using your prefix");
1331                    return;
1332                }
1333                String inputsysname = systemNameField.getText();
1334                int offset = Manager.getSystemPrefixLength(inputsysname);
1335                String grapevinePrefix = InstanceManager.getDefault(GrapevineSystemConnectionMemo.class).getSystemPrefix();
1336                if (!inputsysname.startsWith(grapevinePrefix) || inputsysname.charAt(offset) != 'H') {
1337                    log.warn("skipping creation of signal head, '{}' does not start with GxH", inputsysname);
1338                    String msg = Bundle.getMessage("GrapevineSkippingCreation", inputsysname);
1339                    JmriJOptionPane.showMessageDialog(this, msg,
1340                            Bundle.getMessage("WarningTitle"), JmriJOptionPane.ERROR_MESSAGE);
1341                    return;
1342                }
1343                if (checkSysNameOkBeforeCreating(inputsysname)) {
1344                    s = new SerialSignalHead(inputsysname, userNameField.getText(), InstanceManager.getDefault(GrapevineSystemConnectionMemo.class));
1345                    InstanceManager.getDefault(SignalHeadManager.class).register(s);
1346                }
1347            } else if (QUAD_OUTPUT.equals(headTypeBox.getSelectedItem())) {
1348                if (checkSysNameOkBeforeCreating(systemNameField.getText())) {
1349                    Turnout t1 = getTurnoutFromPanel(turnoutSelect1, "SignalHead:" + systemNameField.getText() + ":Green");
1350                    Turnout t2 = getTurnoutFromPanel(turnoutSelect2, "SignalHead:" + systemNameField.getText() + ":Yellow");
1351                    Turnout t3 = getTurnoutFromPanel(turnoutSelect3, "SignalHead:" + systemNameField.getText() + ":Red");
1352                    Turnout t4 = getTurnoutFromPanel(turnoutSelect4, "SignalHead:" + systemNameField.getText() + ":Lunar");
1353
1354                    if (t1 == null) {
1355                        addTurnoutMessage(centrePanBorder1.getTitle(), turnoutSelect1.getDisplayName());
1356                    }
1357                    if (t2 == null) {
1358                        addTurnoutMessage(centrePanBorder2.getTitle(), turnoutSelect2.getDisplayName());
1359                    }
1360                    if (t3 == null) {
1361                        addTurnoutMessage(centrePanBorder3.getTitle(), turnoutSelect3.getDisplayName());
1362                    }
1363                    if (t4 == null) {
1364                        addTurnoutMessage(centrePanBorder4.getTitle(), turnoutSelect4.getDisplayName());
1365                    }
1366                    if (t4 == null || t3 == null || t2 == null || t1 == null) {
1367                        log.warn("skipping creation of signal {} due to error", systemNameField.getText());
1368                        return;
1369                    }
1370                    s = new QuadOutputSignalHead(systemNameField.getText(), userNameField.getText(),
1371                            nbhm.getNamedBeanHandle(turnoutSelect1.getDisplayName(), t1),
1372                            nbhm.getNamedBeanHandle(turnoutSelect2.getDisplayName(), t2),
1373                            nbhm.getNamedBeanHandle(turnoutSelect3.getDisplayName(), t3),
1374                            nbhm.getNamedBeanHandle(turnoutSelect4.getDisplayName(), t4));
1375                    InstanceManager.getDefault(SignalHeadManager.class).register(s);
1376
1377                }
1378            } else if (TRIPLE_TURNOUT.equals(headTypeBox.getSelectedItem())) {
1379                if (checkSysNameOkBeforeCreating(systemNameField.getText())) {
1380                    Turnout t1 = getTurnoutFromPanel(turnoutSelect1, "SignalHead:" + systemNameField.getText() + ":Green");
1381                    Turnout t2 = getTurnoutFromPanel(turnoutSelect2, "SignalHead:" + systemNameField.getText() + ":Yellow");
1382                    Turnout t3 = getTurnoutFromPanel(turnoutSelect3, "SignalHead:" + systemNameField.getText() + ":Red");
1383
1384                    if (t1 == null) {
1385                        addTurnoutMessage(centrePanBorder1.getTitle(), turnoutSelect1.getDisplayName());
1386                    }
1387                    if (t2 == null) {
1388                        addTurnoutMessage(centrePanBorder2.getTitle(), turnoutSelect2.getDisplayName());
1389                    }
1390                    if (t3 == null) {
1391                        addTurnoutMessage(centrePanBorder3.getTitle(), turnoutSelect3.getDisplayName());
1392                    }
1393                    if (t3 == null || t2 == null || t1 == null) {
1394                        log.warn("skipping creation of signal {} due to error", systemNameField.getText());
1395                        return;
1396                    }
1397
1398                    s = new TripleTurnoutSignalHead(systemNameField.getText(), userNameField.getText(),
1399                            nbhm.getNamedBeanHandle(turnoutSelect1.getDisplayName(), t1),
1400                            nbhm.getNamedBeanHandle(turnoutSelect2.getDisplayName(), t2),
1401                            nbhm.getNamedBeanHandle(turnoutSelect3.getDisplayName(), t3));
1402                    InstanceManager.getDefault(SignalHeadManager.class).register(s);
1403                }
1404            } else if (TRIPLE_OUTPUT.equals(headTypeBox.getSelectedItem())) {
1405                if (checkSysNameOkBeforeCreating(systemNameField.getText())) {
1406                    Turnout t1 = getTurnoutFromPanel(turnoutSelect1, "SignalHead:" + systemNameField.getText() + ":Green");
1407                    Turnout t2 = getTurnoutFromPanel(turnoutSelect2, "SignalHead:" + systemNameField.getText() + ":Blue");
1408                    Turnout t3 = getTurnoutFromPanel(turnoutSelect3, "SignalHead:" + systemNameField.getText() + ":Red");
1409
1410                    if (t1 == null) {
1411                        addTurnoutMessage(centrePanBorder1.getTitle(), turnoutSelect1.getDisplayName());
1412                    }
1413                    if (t2 == null) {
1414                        addTurnoutMessage(centrePanBorder2.getTitle(), turnoutSelect2.getDisplayName());
1415                    }
1416                    if (t3 == null) {
1417                        addTurnoutMessage(centrePanBorder3.getTitle(), turnoutSelect3.getDisplayName());
1418                    }
1419                    if (t3 == null || t2 == null || t1 == null) {
1420                        log.warn("skipping creation of signal {} due to error", systemNameField.getText());
1421                        return;
1422                    }
1423
1424                    s = new TripleOutputSignalHead(systemNameField.getText(), userNameField.getText(),
1425                            nbhm.getNamedBeanHandle(turnoutSelect1.getDisplayName(), t1),
1426                            nbhm.getNamedBeanHandle(turnoutSelect2.getDisplayName(), t2),
1427                            nbhm.getNamedBeanHandle(turnoutSelect3.getDisplayName(), t3));
1428                    InstanceManager.getDefault(SignalHeadManager.class).register(s);
1429                }
1430            } else if (DOUBLE_TURNOUT.equals(headTypeBox.getSelectedItem())) {
1431                if (checkSysNameOkBeforeCreating(systemNameField.getText())) {
1432                    Turnout t1 = getTurnoutFromPanel(turnoutSelect1, "SignalHead:" + systemNameField.getText() + ":Green");
1433                    Turnout t2 = getTurnoutFromPanel(turnoutSelect2, "SignalHead:" + systemNameField.getText() + ":Red");
1434
1435                    if (t1 == null) {
1436                        addTurnoutMessage(centrePanBorder1.getTitle(), turnoutSelect1.getDisplayName());
1437                    }
1438                    if (t2 == null) {
1439                        addTurnoutMessage(centrePanBorder2.getTitle(), turnoutSelect2.getDisplayName());
1440                    }
1441                    if (t2 == null || t1 == null) {
1442                        log.warn("skipping creation of signal {} due to error", systemNameField.getText());
1443                        return;
1444                    }
1445
1446                    s = new DoubleTurnoutSignalHead(systemNameField.getText(), userNameField.getText(),
1447                            nbhm.getNamedBeanHandle(turnoutSelect1.getDisplayName(), t1),
1448                            nbhm.getNamedBeanHandle(turnoutSelect2.getDisplayName(), t2));
1449                    InstanceManager.getDefault(SignalHeadManager.class).register(s);
1450                }
1451            } else if (SINGLE_TURNOUT.equals(headTypeBox.getSelectedItem())) {
1452                if (checkSysNameOkBeforeCreating(systemNameField.getText())) {
1453                    Turnout t1 = getTurnoutFromPanel(turnoutSelect1,
1454                            "SignalHead:" + systemNameField.getText() + ":" + signalStateBox2.getSelectedItem() + ":" + signalStateBox3.getSelectedItem());
1455
1456                    int on = signalStateFromBox(signalStateBox2);
1457                    int off = signalStateFromBox(signalStateBox3);
1458                    if (t1 == null) {
1459                        addTurnoutMessage(centrePanBorder1.getTitle(), turnoutSelect1.getDisplayName());
1460                    }
1461                    if (t1 == null) {
1462                        log.warn("skipping creation of signal {} due to error", systemNameField.getText());
1463                        return;
1464                    }
1465
1466                    s = new SingleTurnoutSignalHead(systemNameField.getText(), userNameField.getText(),
1467                            nbhm.getNamedBeanHandle(t1.getDisplayName(), t1), on, off);
1468                    InstanceManager.getDefault(SignalHeadManager.class).register(s);
1469                }
1470            } else if (VIRTUAL_HEAD.equals(headTypeBox.getSelectedItem())) {
1471                if (checkSysNameOkBeforeCreating(systemNameField.getText())) {
1472                    s = new VirtualSignalHead(systemNameField.getText(), userNameField.getText());
1473                    InstanceManager.getDefault(SignalHeadManager.class).register(s);
1474                }
1475            } else if (LSDEC.equals(headTypeBox.getSelectedItem())) { // LDT LS-DEC
1476                if (checkSysNameOkBeforeCreating(systemNameField.getText())) {
1477                    Turnout t1 = getTurnoutFromPanel(turnoutSelect1, "SignalHead:" + systemNameField.getText() + ":Green");
1478                    Turnout t2 = getTurnoutFromPanel(turnoutSelect2, "SignalHead:" + systemNameField.getText() + ":Yellow");
1479                    Turnout t3 = getTurnoutFromPanel(turnoutSelect3, "SignalHead:" + systemNameField.getText() + ":Red");
1480                    Turnout t4 = getTurnoutFromPanel(turnoutSelect4, "SignalHead:" + systemNameField.getText() + ":FlashGreen");
1481                    Turnout t5 = getTurnoutFromPanel(turnoutSelect5, "SignalHead:" + systemNameField.getText() + ":FlashYellow");
1482                    Turnout t6 = getTurnoutFromPanel(turnoutSelect6, "SignalHead:" + systemNameField.getText() + ":FlashRed");
1483                    Turnout t7 = getTurnoutFromPanel(turnoutSelect7, "SignalHead:" + systemNameField.getText() + ":Dark");
1484
1485                    int s1 = turnoutStateFromBox(turnoutStateBox1);
1486                    int s2 = turnoutStateFromBox(turnoutStateBox2);
1487                    int s3 = turnoutStateFromBox(turnoutStateBox3);
1488                    int s4 = turnoutStateFromBox(turnoutStateBox4);
1489                    int s5 = turnoutStateFromBox(turnoutStateBox5);
1490                    int s6 = turnoutStateFromBox(turnoutStateBox6);
1491                    int s7 = turnoutStateFromBox(turnoutStateBox7);
1492
1493                    if (t1 == null) {
1494                        addTurnoutMessage(centrePanBorder1.getTitle(), turnoutSelect1.getDisplayName());
1495                    }
1496                    if (t2 == null) {
1497                        addTurnoutMessage(centrePanBorder2.getTitle(), turnoutSelect2.getDisplayName());
1498                    }
1499                    if (t3 == null) {
1500                        addTurnoutMessage(centrePanBorder3.getTitle(), turnoutSelect3.getDisplayName());
1501                    }
1502                    if (t4 == null) {
1503                        addTurnoutMessage(centrePanBorder4.getTitle(), turnoutSelect4.getDisplayName());
1504                    }
1505                    if (t5 == null) {
1506                        addTurnoutMessage(centrePanBorder5.getTitle(), turnoutSelect5.getDisplayName());
1507                    }
1508                    if (t6 == null) {
1509                        addTurnoutMessage(centrePanBorder6.getTitle(), turnoutSelect6.getDisplayName());
1510                    }
1511                    if (t7 == null) {
1512                        addTurnoutMessage(centrePanBorder7.getTitle(), turnoutSelect7.getDisplayName());
1513                    }
1514                    if (t7 == null || t6 == null || t5 == null || t4 == null || t3 == null || t2 == null || t1 == null) {
1515                        log.warn("skipping creation of signal {} due to error", systemNameField.getText());
1516                        return;
1517                    }
1518                    s = new LsDecSignalHead(systemNameField.getText(),
1519                            nbhm.getNamedBeanHandle(t1.getDisplayName(), t1), s1,
1520                            nbhm.getNamedBeanHandle(t2.getDisplayName(), t2), s2,
1521                            nbhm.getNamedBeanHandle(t3.getDisplayName(), t3), s3,
1522                            nbhm.getNamedBeanHandle(t4.getDisplayName(), t4), s4,
1523                            nbhm.getNamedBeanHandle(t5.getDisplayName(), t5), s5,
1524                            nbhm.getNamedBeanHandle(t6.getDisplayName(), t6), s6,
1525                            nbhm.getNamedBeanHandle(t7.getDisplayName(), t7), s7);
1526                    s.setUserName(userNameField.getText());
1527                    InstanceManager.getDefault(SignalHeadManager.class).register(s);
1528                }
1529            } else if (DCC_SIGNAL_DECODER.equals(headTypeBox.getSelectedItem())) {
1530                handleDCCOkPressed();
1531            } else if (MERG_SIGNAL_DRIVER.equals(headTypeBox.getSelectedItem())) {
1532                handleMergSignalDriverOkPressed();
1533            } else {
1534                throw new UnsupportedOperationException("Unexpected type: " + headTypeBox.getSelectedItem());
1535            }
1536
1537        } catch (NumberFormatException ex) {
1538            handleCreateException(ex, systemNameField.getText());
1539            // return; // without creating
1540        }
1541
1542    }
1543
1544    private void addTurnoutMessage(String s1, String s2) {
1545        log.warn("Could not provide turnout {}", s2);
1546        String msg = Bundle.getMessage("AddNoTurnout", s1, s2);
1547        JmriJOptionPane.showMessageDialog(this, msg,
1548                Bundle.getMessage("WarningTitle") + " " + s1, JmriJOptionPane.ERROR_MESSAGE);
1549    }
1550
1551    private void handleCreateException(Exception ex, String sysName) {
1552        if (ex.getLocalizedMessage() != null) {
1553            JmriJOptionPane.showMessageDialog(this,
1554                    ex.getLocalizedMessage(),
1555                    Bundle.getMessage("ErrorTitle"),
1556                    JmriJOptionPane.ERROR_MESSAGE);
1557        } else if (ex.getMessage() != null) {
1558            JmriJOptionPane.showMessageDialog(this,
1559                    ex.getMessage(),
1560                    Bundle.getMessage("ErrorTitle"),
1561                    JmriJOptionPane.ERROR_MESSAGE);
1562        } else {
1563            JmriJOptionPane.showMessageDialog(this,
1564                    Bundle.getMessage("ErrorSignalHeadAddFailed", sysName) + "\n" + Bundle.getMessage("ErrorAddFailedCheck"),
1565                    Bundle.getMessage("ErrorTitle"),
1566                    JmriJOptionPane.ERROR_MESSAGE);
1567        }
1568    }
1569
1570    private int acelaSignalheadTypeFromBox(JComboBox<String> box) {
1571        String mode = (String) box.getSelectedItem();
1572        int result = StringUtil.getStateFromName(mode, ACELA_SIG_HEAD_TYPE_VALUES, ACELA_SIG_HEAD_TYPES);
1573
1574        if (result < 0) {
1575            log.warn("unexpected mode string in signalhead appearance type: {}", mode);
1576            throw new IllegalArgumentException();
1577        }
1578        return result;
1579    }
1580
1581    private void handleSE8cOkPressed() {
1582
1583        Turnout t1 = getTurnoutFromPanel(turnoutSelect1, "SignalHead:" + systemNameField.getText() + ":low");
1584        Turnout t2 = getTurnoutFromPanel(turnoutSelect2, "SignalHead:" + systemNameField.getText() + ":high");
1585
1586        // check validity
1587        if (t1 != null && t2 != null) {
1588            // OK, process
1589            SignalHead s;
1590            try {
1591                s = new SE8cSignalHead(
1592                        nbhm.getNamedBeanHandle(t1.getSystemName(), t1),
1593                        nbhm.getNamedBeanHandle(t2.getSystemName(), t2),
1594                        userNameField.getText());
1595            } catch (NumberFormatException ex) {
1596                // user input no good
1597                handleCreate2TurnoutException(t1.getSystemName(),
1598                        t2.getSystemName(), userNameField.getText());
1599                return; // without creating any
1600            }
1601            InstanceManager.getDefault(SignalHeadManager.class).register(s);
1602        } else {
1603            // couldn't create turnouts, error
1604            String msg;
1605            if (t1 == null) {
1606                msg = Bundle.getMessage("se8c4SkippingDueToErrorInFirst");
1607            } else {
1608                msg = Bundle.getMessage("se8c4SkippingDueToErrorInSecond");
1609            }
1610            JmriJOptionPane.showMessageDialog(this, msg,
1611                    Bundle.getMessage("WarningTitle"), JmriJOptionPane.ERROR_MESSAGE);
1612        }
1613    }
1614
1615    private void handleDCCOkPressed() {
1616        DccSignalHead s;
1617        String systemNameText = null;
1618        String prefix = (String) prefixBox.getSelectedItem();
1619        if (prefix != null) {
1620            systemNameText = ConnectionNameFromSystemName.getPrefixFromName(prefix);
1621        }
1622        // if we return a null string then we will set it to use internal, thus picking up the default command station at a later date.
1623        if (systemNameText == null) {
1624            systemNameText = "I";
1625        }
1626        systemNameText = systemNameText + "H$" + systemNameField.getText();
1627
1628        if (checkSysNameOkBeforeCreating(systemNameText)) {
1629            s = new DccSignalHead(systemNameText);
1630            s.setUserName(userNameField.getText());
1631            log.debug("dccAspect Length = {}", dccAspectSpinners.length);
1632            for (int i = 0; i < DccSignalHead.getDefaultValidStates().length; i++) { // no need to check DCC ID input when using JSpinner
1633                log.debug("i = {}", i);
1634                int number = (Integer) dccAspectSpinners[i].getValue();
1635                try {
1636                    s.setOutputForAppearance(s.getValidStates()[i], number);
1637                } catch (RuntimeException ex) {
1638                    log.warn("error setting \"{}\" output for appearance \"{}\"", systemNameText, number);
1639                }
1640            }
1641            InstanceManager.getDefault(SignalHeadManager.class).register(s);
1642            s.useAddressOffSet(dccOffSetAddressCheckBox.isSelected());
1643            s.setDccSignalHeadPacketSendCount((int)dccPacketSendCountSpinner.getValue());
1644        }
1645    }
1646
1647    @SuppressWarnings("fallthrough")
1648    @SuppressFBWarnings(value = "SF_SWITCH_FALLTHROUGH")
1649    private void handleMergSignalDriverOkPressed() {
1650        SignalHead s;
1651        // Adding Merg Signal Driver.
1652        Turnout t3;
1653        Turnout t2;
1654        Turnout t1;
1655        NamedBeanHandle<Turnout> nbt1 = null;
1656        NamedBeanHandle<Turnout> nbt2 = null;
1657        NamedBeanHandle<Turnout> nbt3 = null;
1658        if (checkSysNameOkBeforeCreating(systemNameField.getText())) {
1659            switch (ukSignalAspectsFromBox(numberUkAspectsBox)) {
1660                case 4:
1661                    t3 = getTurnoutFromPanel(turnoutSelect5,
1662                            (Bundle.getMessage("OutputComment", Bundle.getMessage("BeanNameSignalHead"), systemNameField.getText(), Bundle.getMessage("InputNum", "3"))));
1663                    if (t3 == null) {
1664                        addTurnoutMessage(centrePanBorder5.getTitle(), turnoutSelect5.getDisplayName());
1665                        log.warn("skipping creation of signal {} due to error", systemNameField.getText());
1666                        return;
1667                    } else {
1668                        nbt3 = nbhm.getNamedBeanHandle(turnoutSelect5.getDisplayName(), t3);
1669                    }
1670
1671                // fall through
1672                case 3:
1673                    t2 = getTurnoutFromPanel(turnoutSelect4,
1674                            (Bundle.getMessage("OutputComment", Bundle.getMessage("BeanNameSignalHead"), systemNameField.getText(), Bundle.getMessage("InputNum", "2"))));
1675                    if (t2 == null) {
1676                        addTurnoutMessage(centrePanBorder4.getTitle(), turnoutSelect4.getDisplayName());
1677                        log.warn("skipping creation of signal {} due to error", systemNameField.getText());
1678                        return;
1679                    } else {
1680                        nbt2 = nbhm.getNamedBeanHandle(turnoutSelect4.getDisplayName(), t2);
1681                    }
1682                // fall through
1683                case 2:
1684                    t1 = getTurnoutFromPanel(turnoutSelect3,
1685                            (Bundle.getMessage("OutputComment", Bundle.getMessage("BeanNameSignalHead"), systemNameField.getText(), Bundle.getMessage("InputNum", "1"))));
1686                    if (t1 == null) {
1687                        addTurnoutMessage(centrePanBorder3.getTitle(), turnoutSelect3.getDisplayName());
1688                        log.warn("skipping creation of signal {} due to error", systemNameField.getText());
1689                        return;
1690                    } else {
1691                        nbt1 = nbhm.getNamedBeanHandle(turnoutSelect3.getDisplayName(), t1);
1692                    }
1693                    break;
1694                default:
1695                    break;
1696            }
1697            boolean home = !ukSignalTypeFromBox(ukSignalSemaphoreTypeBox).equals(Bundle.getMessage("DistantSignal"));
1698
1699            s = new MergSD2SignalHead(systemNameField.getText(), ukSignalAspectsFromBox(numberUkAspectsBox), nbt1, nbt2, nbt3, false, home);
1700            s.setUserName(userNameField.getText());
1701            InstanceManager.getDefault(SignalHeadManager.class).register(s);
1702
1703        }
1704    }
1705    
1706    private boolean checkSysNameOkBeforeCreating(String sysName) {
1707        if (DCC_SIGNAL_DECODER.equals(headTypeBox.getSelectedItem())) {
1708            try {
1709                Integer.valueOf(sysName.substring(sysName.indexOf("$") + 1));
1710            } catch (NumberFormatException ex) {
1711                String msg = Bundle.getMessage("ShouldBeNumber", "Hardware Address");
1712                JmriJOptionPane.showMessageDialog(this, msg,
1713                        Bundle.getMessage("WarningTitle"), JmriJOptionPane.ERROR_MESSAGE);
1714                return false;
1715            }
1716        } else {
1717            boolean ok = true;
1718            try {
1719                int i = Manager.getSystemPrefixLength(sysName);
1720                if (sysName.length() < i+2) {
1721                    ok = false;
1722                } else {
1723                    if (sysName.charAt(i) != 'H') ok = false;
1724                }
1725            } catch (NamedBean.BadSystemNameException e) {
1726                ok = false;
1727            }
1728            if (!ok) {
1729                String msg = Bundle.getMessage("InvalidSignalSystemName", sysName);
1730                JmriJOptionPane.showMessageDialog(this, msg,
1731                        Bundle.getMessage("WarningTitle"), JmriJOptionPane.ERROR_MESSAGE);
1732                return false;
1733            }
1734        }
1735        // check for pre-existing signal head with same system name
1736        SignalHead s = InstanceManager.getDefault(SignalHeadManager.class).getBySystemName(sysName);
1737        // return true if signal head does not exist
1738        if (s == null) {
1739            //Need to check that the Systemname doesn't already exists as a UserName
1740            SignalHead nB = InstanceManager.getDefault(SignalHeadManager.class).getByUserName(sysName);
1741            if (nB != null) {
1742                log.error("System name is not unique {} It already exists as a User name", sysName);
1743                String msg = Bundle.getMessage("WarningSystemNameAsUser", ("" + sysName));
1744                JmriJOptionPane.showMessageDialog(this, msg,
1745                        Bundle.getMessage("WarningTitle"),
1746                        JmriJOptionPane.ERROR_MESSAGE);
1747                return false;
1748            }
1749            return true;
1750        }
1751        // inform the user if signal head already exists, and return false so creation can be bypassed
1752        log.warn("Attempt to create signal with duplicate system name {}", sysName);
1753        String msg = Bundle.getMessage("DuplicateSignalSystemName", sysName);
1754        JmriJOptionPane.showMessageDialog(this, msg,
1755                Bundle.getMessage("WarningTitle"), JmriJOptionPane.ERROR_MESSAGE);
1756        return false;
1757    }
1758
1759    private boolean checkIntegerOnly(String s) {
1760        for (int i = 0; i < s.length(); i++) {
1761            if (!Character.isDigit(s.charAt(i))) {
1762                return false;
1763            }
1764        }
1765        return true;
1766    }
1767
1768    private void handleCreate2TurnoutException(String t1, String t2, String uName) {
1769        JmriJOptionPane.showMessageDialog(this,
1770                Bundle.getMessage("ErrorSe8cAddFailed", uName, t1, t2) + "\n" + Bundle.getMessage("ErrorAddFailedCheck"),
1771                Bundle.getMessage("ErrorTitle"),
1772                JmriJOptionPane.ERROR_MESSAGE);
1773    }
1774
1775    /**
1776     * Update Turnout object for a signal mast output.
1777     *
1778     * @param bp         Pane in which the new output/bean was entered by user
1779     * @param reference  Turnout application description
1780     * @param oldTurnout Previously used output
1781     * @param title      for warning pane
1782     * @return The newly defined output as Turnout object
1783     */
1784    @CheckForNull
1785    private Turnout updateTurnoutFromPanel(@Nonnull BeanSelectCreatePanel<Turnout> bp, String reference, @CheckForNull Turnout oldTurnout, String title) {
1786        Turnout newTurnout = getTurnoutFromPanel(bp, reference);
1787        if (newTurnout == null) {
1788            noTurnoutMessage(title, bp.getDisplayName());
1789        }
1790        String comment;
1791        if (newTurnout != null) {
1792            comment = newTurnout.getComment();
1793            if  (comment == null || comment.isEmpty()) {
1794                newTurnout.setComment(reference); // enter turnout application description into new turnout Comment
1795            }
1796        }
1797        if (oldTurnout == null || newTurnout == oldTurnout) {
1798            return newTurnout;
1799        }
1800        comment = oldTurnout.getComment();
1801        if (comment != null && comment.equals(reference)) {
1802            // wont delete old Turnout Comment if Locale or Bundle was changed in between, but user could have type something in the Comment as well
1803            oldTurnout.setComment(null); // deletes current Comment in bean
1804        }
1805        return newTurnout;
1806    }
1807
1808    /**
1809     * Create Turnout object for a signal mast output.
1810     *
1811     * @param bp        Pane in which the new output/bean was entered by user
1812     * @param reference Turnout application description
1813     * @return The new output as Turnout object
1814     */
1815    @CheckForNull
1816    private Turnout getTurnoutFromPanel(@Nonnull BeanSelectCreatePanel<Turnout> bp, String reference) {
1817        bp.setReference(reference); // pass turnout application description to be put into turnout Comment
1818        try {
1819            return bp.getNamedBean();
1820        } catch (JmriException ex) {
1821            log.warn("skipping creation of turnout not found for {}", reference);
1822            return null;
1823        }
1824    }
1825
1826    private boolean checkUserName(String nam) {
1827        if (!((nam == null) || (nam.isEmpty()))) {
1828            // user name changed, check if new name already exists
1829            NamedBean nB = InstanceManager.getDefault(SignalHeadManager.class).getByUserName(nam);
1830            if (nB != null) {
1831                log.error("User name is not unique {}", nam);
1832                String msg = Bundle.getMessage("WarningUserName", ("" + nam));
1833                JmriJOptionPane.showMessageDialog(this, msg,
1834                        Bundle.getMessage("InvalidUserNameAlreadyExists", Bundle.getMessage("BeanNameSignalHead"),nam),
1835                        JmriJOptionPane.ERROR_MESSAGE);
1836                return false;
1837            }
1838            //Check to ensure that the username doesn't exist as a systemname.
1839            nB = InstanceManager.getDefault(SignalHeadManager.class).getBySystemName(nam);
1840            if (nB != null) {
1841                log.error("User name is not unique {} It already exists as a System name", nam);
1842                String msg = Bundle.getMessage("WarningUserNameAsSystem", ("" + nam));
1843                JmriJOptionPane.showMessageDialog(this, msg,
1844                        Bundle.getMessage("InvalidUserNameAlreadyExists", Bundle.getMessage("BeanNameSignalHead"),nam),
1845                        JmriJOptionPane.ERROR_MESSAGE);
1846                return false;
1847            }
1848        }
1849        return true;
1850    }
1851
1852    private void noTurnoutMessage(String s1, String s2) {
1853        log.warn("Could not provide turnout {}", s2);
1854        String msg = Bundle.getMessage("WarningNoTurnout", s1, s2);
1855        JmriJOptionPane.showMessageDialog(this, msg,
1856                Bundle.getMessage("WarningTitle"), JmriJOptionPane.ERROR_MESSAGE);
1857    }
1858
1859    @Override
1860    public void dispose() {
1861        if (turnoutSelect1 != null) {
1862            turnoutSelect1.dispose();
1863        }
1864        if (turnoutSelect2 != null) {
1865            turnoutSelect2.dispose();
1866        }
1867        if (turnoutSelect3 != null) {
1868            turnoutSelect3.dispose();
1869        }
1870        if (turnoutSelect4 != null) {
1871            turnoutSelect4.dispose();
1872        }
1873        if (turnoutSelect5 != null) {
1874            turnoutSelect5.dispose();
1875        }
1876        if (turnoutSelect6 != null) {
1877            turnoutSelect6.dispose();
1878        }
1879        if (turnoutSelect7 != null) {
1880            turnoutSelect7.dispose();
1881        }
1882        super.dispose();
1883    }
1884
1885    private final static org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(SignalHeadAddEditFrame.class);
1886
1887}