001package jmri.jmrit.dispatcher;
002
003import java.awt.BorderLayout;
004import java.awt.Component;
005import java.awt.Container;
006import java.awt.Dimension;
007import java.awt.FlowLayout;
008import java.awt.event.ActionEvent;
009import java.awt.event.ActionListener;
010import java.awt.event.ItemEvent;
011import java.util.ArrayList;
012import java.util.HashSet;
013import java.util.List;
014import java.util.Locale;
015import java.util.Set;
016
017import javax.swing.BorderFactory;
018import javax.swing.BoxLayout;
019import javax.swing.ButtonGroup;
020import javax.swing.JButton;
021import javax.swing.JCheckBox;
022import javax.swing.JComboBox;
023import javax.swing.JLabel;
024import javax.swing.JPanel;
025import javax.swing.JRadioButton;
026import javax.swing.JScrollPane;
027import javax.swing.JSeparator;
028import javax.swing.JSpinner;
029import javax.swing.JTable;
030import javax.swing.JTextField;
031import javax.swing.ScrollPaneConstants;
032import javax.swing.SpinnerNumberModel;
033import javax.swing.table.DefaultTableModel;
034import javax.swing.table.TableCellRenderer;
035import javax.swing.table.TableColumnModel;
036
037import jmri.Block;
038import jmri.jmrit.display.layoutEditor.LayoutBlock;
039import jmri.jmrit.display.layoutEditor.LayoutBlockManager;
040import jmri.InstanceManager;
041import jmri.Sensor;
042import jmri.Transit;
043import jmri.TransitManager;
044import jmri.jmrit.dispatcher.ActiveTrain.TrainDetection;
045import jmri.jmrit.dispatcher.ActiveTrain.TrainLengthUnits;
046import jmri.jmrit.dispatcher.DispatcherFrame.TrainsFrom;
047import jmri.jmrit.operations.trains.Train;
048import jmri.jmrit.operations.trains.TrainManager;
049import jmri.jmrit.roster.RosterEntry;
050import jmri.jmrit.roster.swing.RosterEntryComboBox;
051import jmri.swing.NamedBeanComboBox;
052import jmri.util.JmriJFrame;
053import jmri.util.swing.JComboBoxUtil;
054import jmri.util.swing.JmriJOptionPane;
055
056/**
057 * Displays the Activate New Train Frame and processes information entered
058 * there.
059 * <p>
060 * This module works with Dispatcher, which initiates the display of this Frame.
061 * Dispatcher also creates the ActiveTrain.
062 * <p>
063 * This file is part of JMRI.
064 * <p>
065 * JMRI is open source software; you can redistribute it and/or modify it under
066 * the terms of version 2 of the GNU General Public License as published by the
067 * Free Software Foundation. See the "COPYING" file for a copy of this license.
068 * <p>
069 * JMRI is distributed in the hope that it will be useful, but WITHOUT ANY
070 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
071 * A PARTICULAR PURPOSE. See the GNU General Public License for more details.
072 *
073 * @author Dave Duchamp Copyright (C) 2009
074 */
075public class ActivateTrainFrame extends JmriJFrame {
076
077    public ActivateTrainFrame(DispatcherFrame d) {
078        super(true,true);
079        _dispatcher = d;
080        _tiFile = new TrainInfoFile();
081    }
082
083    // operational instance variables
084    private DispatcherFrame _dispatcher = null;
085    private TrainInfoFile _tiFile = null;
086    private final TransitManager _TransitManager = InstanceManager.getDefault(jmri.TransitManager.class);
087    private String _trainInfoName = "";
088
089    // initiate train window variables
090    private Transit selectedTransit = null;
091    //private String selectedTrain = "";
092    private JmriJFrame initiateFrame = null;
093    private Container initiatePane = null;
094    private final jmri.swing.NamedBeanComboBox<Transit> transitSelectBox = new jmri.swing.NamedBeanComboBox<>(_TransitManager);
095    private final JComboBox<Object> trainSelectBox = new JComboBox<>();
096    // private final List<RosterEntry> trainBoxList = new ArrayList<>();
097    private RosterEntryComboBox rosterComboBox = null;
098    private final JLabel trainFieldLabel = new JLabel(Bundle.getMessage("TrainBoxLabel") + ":");
099    private final JTextField trainNameField = new JTextField(10);
100    private final JLabel dccAddressFieldLabel = new JLabel("     " + Bundle.getMessage("DccAddressFieldLabel") + ":");
101    private final JSpinner dccAddressSpinner = new JSpinner(new SpinnerNumberModel(3, 1, 9999, 1));
102    private final JCheckBox inTransitBox = new JCheckBox(Bundle.getMessage("TrainInTransit"));
103    private final JComboBox<String> startingBlockBox = new JComboBox<>();
104    private final JComboBox<String> viaBlockBox = new JComboBox<>();
105    private final JLabel viaBlockBoxLabel = new JLabel(Bundle.getMessage("ViaBlockBoxLabel"));
106    private List<Block> startingBlockBoxList = new ArrayList<>();
107    private final List<Block> viaBlockBoxList = new ArrayList<>();
108    private List<Integer> startingBlockSeqList = new ArrayList<>();
109    private final JComboBox<String> destinationBlockBox = new JComboBox<>();
110
111    private List<Block> destinationBlockBoxList = new ArrayList<>();
112    private List<Integer> destinationBlockSeqList = new ArrayList<>();
113    private JButton addNewTrainButton = null;
114    private JButton loadButton = null;
115    private JButton saveButton = null;
116    private JButton saveAsTemplateButton  = null;
117    private JButton deleteButton = null;
118    private final JCheckBox autoRunBox = new JCheckBox(Bundle.getMessage("AutoRun"));
119    private final JCheckBox loadAtStartupBox = new JCheckBox(Bundle.getMessage("LoadAtStartup"));
120
121    private final JRadioButton radioTrainsFromRoster = new JRadioButton(Bundle.getMessage("TrainsFromRoster"));
122    private final JRadioButton radioTrainsFromOps = new JRadioButton(Bundle.getMessage("TrainsFromTrains"));
123    private final JRadioButton radioTrainsFromUser = new JRadioButton(Bundle.getMessage("TrainsFromUser"));
124    private final JRadioButton radioTrainsFromSetLater = new JRadioButton(Bundle.getMessage("TrainsFromSetLater"));
125    private final ButtonGroup trainsFromButtonGroup = new ButtonGroup();
126
127    private final JRadioButton radioTransitsPredefined = new JRadioButton(Bundle.getMessage("TransitsPredefined"));
128    private final JRadioButton radioTransitsAdHoc = new JRadioButton(Bundle.getMessage("TransitsAdHoc"));
129    private final ButtonGroup transitsFromButtonGroup = new ButtonGroup();
130    //private final JCheckBox adHocCloseLoop = new JCheckBox(Bundle.getMessage("TransitCloseLoop"));
131
132    private final JRadioButton allocateBySafeRadioButton = new JRadioButton(Bundle.getMessage("ToSafeSections"));
133    private final JRadioButton allocateAllTheWayRadioButton = new JRadioButton(Bundle.getMessage("AsFarAsPos"));
134    private final JRadioButton allocateNumberOfBlocks = new JRadioButton(Bundle.getMessage("NumberOfBlocks") + ":");
135    private final ButtonGroup allocateMethodButtonGroup = new ButtonGroup();
136    private final JSpinner allocateCustomSpinner = new JSpinner(new SpinnerNumberModel(3, 1, 100, 1));
137    private final JCheckBox terminateWhenDoneBox = new JCheckBox(Bundle.getMessage("TerminateWhenDone"));
138    private final JPanel terminateWhenDoneDetails = new JPanel();
139    private final JComboBox<String> nextTrain = new JComboBox<>();
140    private final JLabel nextTrainLabel = new JLabel(Bundle.getMessage("TerminateWhenDoneNextTrain"));
141    private final JSpinner prioritySpinner = new JSpinner(new SpinnerNumberModel(5, 0, 100, 1));
142    private final JCheckBox resetWhenDoneBox = new JCheckBox(Bundle.getMessage("ResetWhenDone"));
143    private final JCheckBox reverseAtEndBox = new JCheckBox(Bundle.getMessage("ReverseAtEnd"));
144
145    int[] delayedStartInt = new int[]{ActiveTrain.NODELAY, ActiveTrain.TIMEDDELAY, ActiveTrain.SENSORDELAY};
146    String[] delayedStartString = new String[]{Bundle.getMessage("DelayedStartNone"), Bundle.getMessage("DelayedStartTimed"), Bundle.getMessage("DelayedStartSensor")};
147
148    private final JComboBox<String> reverseDelayedRestartType = new JComboBox<>(delayedStartString);
149    private final JLabel delayReverseReStartLabel = new JLabel(Bundle.getMessage("DelayRestart"));
150    private final JLabel delayReverseReStartSensorLabel = new JLabel(Bundle.getMessage("RestartSensor"));
151    private final JCheckBox delayReverseResetSensorBox = new JCheckBox(Bundle.getMessage("ResetRestartSensor"));
152    private final NamedBeanComboBox<Sensor> delayReverseReStartSensor = new NamedBeanComboBox<>(InstanceManager.sensorManagerInstance());
153    private final JSpinner delayReverseMinSpinner = new JSpinner(new SpinnerNumberModel(0, 0, 1000, 1));
154    private final JLabel delayReverseMinLabel = new JLabel(Bundle.getMessage("RestartTimed"));
155
156    private final JCheckBox resetStartSensorBox = new JCheckBox(Bundle.getMessage("ResetStartSensor"));
157    private final JComboBox<String> delayedStartBox = new JComboBox<>(delayedStartString);
158    private final JLabel delayedReStartLabel = new JLabel(Bundle.getMessage("DelayRestart"));
159    private final JLabel delayReStartSensorLabel = new JLabel(Bundle.getMessage("RestartSensor"));
160    private final JCheckBox resetRestartSensorBox = new JCheckBox(Bundle.getMessage("ResetRestartSensor"));
161    private final JComboBox<String> delayedReStartBox = new JComboBox<>(delayedStartString);
162    private final NamedBeanComboBox<Sensor> delaySensor = new NamedBeanComboBox<>(InstanceManager.sensorManagerInstance());
163    private final NamedBeanComboBox<Sensor> delayReStartSensor = new NamedBeanComboBox<>(InstanceManager.sensorManagerInstance());
164
165    private final JSpinner departureHrSpinner = new JSpinner(new SpinnerNumberModel(8, 0, 23, 1));
166    private final JSpinner departureMinSpinner = new JSpinner(new SpinnerNumberModel(0, 0, 59, 1));
167    private final JLabel departureTimeLabel = new JLabel(Bundle.getMessage("DepartureTime"));
168    private final JLabel departureSepLabel = new JLabel(":");
169
170    private final JSpinner delayMinSpinner = new JSpinner(new SpinnerNumberModel(0, 0, 1000, 1));
171    private final JLabel delayMinLabel = new JLabel(Bundle.getMessage("RestartTimed"));
172
173    private final JComboBox<String> trainTypeBox = new JComboBox<>();
174    // Note: See also items related to automatically running trains near the end of this module
175
176    boolean transitsFromSpecificBlock = false;
177
178    private TrainInfo trainInfo;
179
180    private final String nameOfTemplateFile="TrainInfoDefaultTemplate.xml";
181    // to be added and removed.
182    private final ActionListener viaBlockBoxListener = e -> handleViaBlockSelectionChanged();
183
184    /**
185     * Open up a new train window for a given roster entry located in a specific
186     * block.
187     *
188     * @param e  the action event triggering the new window
189     * @param re the roster entry to open the new window for
190     * @param b  the block where the train is located
191     */
192    public void initiateTrain(ActionEvent e, RosterEntry re, Block b) {
193        initiateTrain(e);
194        if (trainInfo.getTrainsFrom() == TrainsFrom.TRAINSFROMROSTER && re != null) {
195            setRosterComboBox(rosterComboBox, re.getId());
196            //Add in some bits of code as some point to filter down the transits that can be used.
197        }
198        if (b != null && selectedTransit != null) {
199            List<Transit> transitList = _TransitManager.getListUsingBlock(b);
200            List<Transit> transitEntryList = _TransitManager.getListEntryBlock(b);
201            for (Transit t : transitEntryList) {
202                if (!transitList.contains(t)) {
203                    transitList.add(t);
204                }
205            }
206            transitsFromSpecificBlock = true;
207            initializeFreeTransitsCombo(transitList);
208            List<Block> tmpBlkList = new ArrayList<>();
209            if (selectedTransit.getEntryBlocksList().contains(b)) {
210                tmpBlkList = selectedTransit.getEntryBlocksList();
211                inTransitBox.setSelected(false);
212            } else if (selectedTransit.containsBlock(b)) {
213                tmpBlkList = selectedTransit.getInternalBlocksList();
214                inTransitBox.setSelected(true);
215            }
216            List<Integer> tmpSeqList = selectedTransit.getBlockSeqList();
217            for (int i = 0; i < tmpBlkList.size(); i++) {
218                if (tmpBlkList.get(i) == b) {
219                    setComboBox(startingBlockBox, getBlockName(b) + "-" + tmpSeqList.get(i));
220                    break;
221                }
222            }
223        }
224    }
225
226    /**
227     * Displays a window that allows a new ActiveTrain to be activated.
228     * <p>
229     * Called by Dispatcher in response to the dispatcher clicking the New Train
230     * button.
231     *
232     * @param e the action event triggering the window display
233     */
234    protected void initiateTrain(ActionEvent e) {
235        // set Dispatcher defaults
236        // create window if needed
237        // if template exists open it
238        try {
239            trainInfo = _tiFile.readTrainInfo(nameOfTemplateFile);
240            if (trainInfo == null) {
241                trainInfo = new TrainInfo();
242            }
243        } catch (java.io.IOException ioe) {
244            log.error("IO Exception when reading train info file", ioe);
245            return;
246        } catch (org.jdom2.JDOMException jde) {
247            log.error("JDOM Exception when reading train info file", jde);
248            return;
249        }
250
251        if (initiateFrame == null) {
252            initiateFrame = this;
253            initiateFrame.setTitle(Bundle.getMessage("AddTrainTitle"));
254            initiateFrame.addHelpMenu("package.jmri.jmrit.dispatcher.NewTrain", true);
255            initiatePane = initiateFrame.getContentPane();
256            initiatePane.setLayout(new BoxLayout(initiatePane, BoxLayout.Y_AXIS));
257
258            // add buttons to load and save train information
259            JPanel hdr = new JPanel();
260            hdr.add(loadButton = new JButton(Bundle.getMessage("LoadButton")));
261            loadButton.addActionListener(this::loadTrainInfo);
262            loadButton.setToolTipText(Bundle.getMessage("LoadButtonHint"));
263            hdr.add(saveButton = new JButton(Bundle.getMessage("SaveButton")));
264            saveButton.addActionListener( ev -> saveTrainInfo());
265            saveButton.setToolTipText(Bundle.getMessage("SaveButtonHint"));
266            hdr.add(saveAsTemplateButton = new JButton(Bundle.getMessage("SaveAsTemplateButton")));
267            saveAsTemplateButton.addActionListener( ev -> saveTrainInfoAsTemplate());
268            saveAsTemplateButton.setToolTipText(Bundle.getMessage("SaveAsTemplateButtonHint"));
269            hdr.add(deleteButton = new JButton(Bundle.getMessage("DeleteButton")));
270            deleteButton.addActionListener( ev -> deleteTrainInfo());
271            deleteButton.setToolTipText(Bundle.getMessage("DeleteButtonHint"));
272
273            // add items relating to both manually run and automatic trains.
274
275            // Trains From choices.
276            JPanel p1 = new JPanel();
277            p1.setBorder(BorderFactory.createTitledBorder(Bundle.getMessage("TrainsFrom")));
278            radioTrainsFromRoster.setActionCommand("TRAINSFROMROSTER");
279            trainsFromButtonGroup.add(radioTrainsFromRoster);
280            radioTrainsFromOps.setActionCommand("TRAINSFROMOPS");
281            trainsFromButtonGroup.add(radioTrainsFromOps);
282            radioTrainsFromUser.setActionCommand("TRAINSFROMUSER");
283            trainsFromButtonGroup.add(radioTrainsFromUser);
284            radioTrainsFromSetLater.setActionCommand("TRAINSFROMSETLATER");
285            trainsFromButtonGroup.add(radioTrainsFromSetLater);
286            p1.add(radioTrainsFromRoster);
287            radioTrainsFromRoster.setToolTipText(Bundle.getMessage("TrainsFromRosterHint"));
288            p1.add(radioTrainsFromOps);
289            radioTrainsFromOps.setToolTipText(Bundle.getMessage("TrainsFromTrainsHint"));
290            p1.add(radioTrainsFromUser);
291            radioTrainsFromUser.setToolTipText(Bundle.getMessage("TrainsFromUserHint"));
292            p1.add(radioTrainsFromSetLater);
293            radioTrainsFromSetLater.setToolTipText(Bundle.getMessage("TrainsFromSetLaterHint"));
294
295            radioTrainsFromOps.addItemListener( e1 -> {
296                if (e1.getStateChange() == ItemEvent.SELECTED) {
297                    setTrainsFromOptions(TrainsFrom.TRAINSFROMOPS);
298                }
299            });
300            radioTrainsFromRoster.addItemListener( e1 -> {
301                if (e1.getStateChange() == ItemEvent.SELECTED) {
302                    setTrainsFromOptions(TrainsFrom.TRAINSFROMROSTER);
303                }
304            });
305            radioTrainsFromUser.addItemListener( e1 -> {
306                if (e1.getStateChange() == ItemEvent.SELECTED) {
307                    setTrainsFromOptions(TrainsFrom.TRAINSFROMUSER);
308                }
309            });
310            radioTrainsFromSetLater.addItemListener( e1 -> {
311                if (e1.getStateChange() == ItemEvent.SELECTED) {
312                    setTrainsFromOptions(TrainsFrom.TRAINSFROMSETLATER);
313                }
314            });
315            initiatePane.add(p1);
316
317            // Select train
318            JPanel p2 = new JPanel();
319
320            // Dispatcher train name
321            p2.add(trainFieldLabel);
322            p2.add(trainNameField);
323            trainNameField.setToolTipText(Bundle.getMessage("TrainFieldHint"));
324
325            // Roster combo box
326            rosterComboBox = new RosterEntryComboBox();
327            initializeFreeRosterEntriesCombo();
328            rosterComboBox.addActionListener(this::handleRosterSelectionChanged);
329            p2.add(rosterComboBox);
330
331            // Operations combo box
332            p2.add(trainSelectBox);
333            trainSelectBox.addActionListener( e1 -> handleTrainSelectionChanged());
334            trainSelectBox.setToolTipText(Bundle.getMessage("TrainBoxHint"));
335
336            // DCC address selector
337            p2.add(dccAddressFieldLabel);
338            p2.add(dccAddressSpinner);
339            dccAddressSpinner.setToolTipText(Bundle.getMessage("DccAddressFieldHint"));
340
341            initiatePane.add(p2);
342
343            // Select transit type
344            JPanel p3 = new JPanel();
345            p3.setBorder(BorderFactory.createTitledBorder(Bundle.getMessage("TransitsFrom")));
346            radioTransitsPredefined.setActionCommand("USETRANSITS");
347            transitsFromButtonGroup.add(radioTransitsPredefined);
348            radioTransitsAdHoc.setActionCommand("USEADHOC");
349            transitsFromButtonGroup.add(radioTransitsAdHoc);
350            p3.add(radioTransitsPredefined);
351            radioTransitsPredefined.setToolTipText(Bundle.getMessage("TransitsPredefinedHint"));
352            p3.add(radioTransitsAdHoc);
353            radioTransitsAdHoc.setToolTipText(Bundle.getMessage("TransitsAdHocHint"));
354            radioTransitsPredefined.addItemListener( e1 -> {
355                if (e1.getStateChange() == ItemEvent.SELECTED) {
356                    transitSelectBox.setEnabled(true);
357                    //adHocCloseLoop.setEnabled(false);
358                    inTransitBox.setEnabled(true);
359                    handleInTransitClick();
360                    viaBlockBox.setVisible(false);
361                    viaBlockBoxLabel.setVisible(false);
362                }
363            });
364            radioTransitsAdHoc.addItemListener( e1 -> {
365                if (e1.getStateChange() == ItemEvent.SELECTED) {
366                    checkAdvancedRouting();
367                    transitSelectBox.setEnabled(false);
368                    //adHocCloseLoop.setEnabled(true);
369                    inTransitBox.setEnabled(false);
370                    inTransitBox.setSelected(true);
371                    initializeStartingBlockComboDynamic();
372                    viaBlockBox.setVisible(true);
373                    viaBlockBoxLabel.setVisible(true);
374                }
375            });
376
377            //p3.add(adHocCloseLoop);
378            //adHocCloseLoop.setToolTipText(Bundle.getMessage("TransitCloseLoopHint"));
379
380            p3.add(new JLabel(Bundle.getMessage("TransitBoxLabel") + " :"));
381            p3.add(transitSelectBox);
382            transitSelectBox.addActionListener(this::handleTransitSelectionChanged);
383            transitSelectBox.setToolTipText(Bundle.getMessage("TransitBoxHint"));
384            initiatePane.add(p3);
385
386            // Train in transit
387            JPanel p4 = new JPanel();
388            p4.add(inTransitBox);
389            inTransitBox.addActionListener( ev -> handleInTransitClick());
390            inTransitBox.setToolTipText(Bundle.getMessage("InTransitBoxHint"));
391            initiatePane.add(p4);
392
393            // Starting block, add Via for adhoc transits
394            JPanel p5 = new JPanel();
395            p5.add(new JLabel(Bundle.getMessage("StartingBlockBoxLabel") + " :"));
396            p5.add(startingBlockBox);
397            startingBlockBox.setToolTipText(Bundle.getMessage("StartingBlockBoxHint"));
398            startingBlockBox.addActionListener( ev -> handleStartingBlockSelectionChanged());
399            p5.add(viaBlockBoxLabel);
400            p5.add(viaBlockBox);
401            viaBlockBox.setToolTipText(Bundle.getMessage("ViaBlockBoxHint"));
402            viaBlockBox.addActionListener(viaBlockBoxListener);
403            initiatePane.add(p5);
404
405            // Destination block
406            JPanel p6 = new JPanel();
407            p6.add(new JLabel(Bundle.getMessage("DestinationBlockBoxLabel") + ":"));
408            p6.add(destinationBlockBox);
409            destinationBlockBox.setToolTipText(Bundle.getMessage("DestinationBlockBoxHint"));
410            initiatePane.add(p6);
411
412            // Train detection scope
413            JPanel p7 = new JPanel();
414            p7.add(trainDetectionLabel);
415            initializeTrainDetectionBox();
416            p7.add(trainDetectionComboBox);
417            trainDetectionComboBox.setToolTipText(Bundle.getMessage("TrainDetectionBoxHint"));
418            initiatePane.add(p7);
419
420            // Allocation method
421            JPanel p8 = new JPanel();
422            p8.setBorder(BorderFactory.createTitledBorder(Bundle.getMessage("AllocateMethodLabel")));
423            allocateMethodButtonGroup.add(allocateAllTheWayRadioButton);
424            allocateMethodButtonGroup.add(allocateBySafeRadioButton);
425            allocateMethodButtonGroup.add(allocateNumberOfBlocks);
426            p8.add(allocateAllTheWayRadioButton);
427            allocateAllTheWayRadioButton.setToolTipText(Bundle.getMessage("AllocateAllTheWayHint"));
428            p8.add(allocateBySafeRadioButton);
429            allocateBySafeRadioButton.setToolTipText(Bundle.getMessage("AllocateSafeHint"));
430            p8.add(allocateNumberOfBlocks);
431            allocateNumberOfBlocks.setToolTipText(Bundle.getMessage("AllocateMethodHint"));
432            allocateAllTheWayRadioButton.addActionListener( ev -> handleAllocateAllTheWayButtonChanged());
433            allocateBySafeRadioButton.addActionListener( ev -> handleAllocateBySafeButtonChanged());
434            allocateNumberOfBlocks.addActionListener( ev -> handleAllocateNumberOfBlocksButtonChanged());
435            p8.add(allocateCustomSpinner);
436            allocateCustomSpinner.setToolTipText(Bundle.getMessage("AllocateMethodHint"));
437            initiatePane.add(p8);
438
439            // Restart at end
440            JPanel p9 = new JPanel();
441            p9.add(resetWhenDoneBox);
442            resetWhenDoneBox.addActionListener( ev -> handleResetWhenDoneClick());
443            resetWhenDoneBox.setToolTipText(Bundle.getMessage("ResetWhenDoneBoxHint"));
444            initiatePane.add(p9);
445
446            // Restart using sensor
447            JPanel p9a = new JPanel();
448            ((FlowLayout) p9a.getLayout()).setVgap(1);
449            p9a.add(delayedReStartLabel);
450            p9a.add(delayedReStartBox);
451            p9a.add(resetRestartSensorBox);
452            resetRestartSensorBox.setToolTipText(Bundle.getMessage("ResetRestartSensorHint"));
453            resetRestartSensorBox.setSelected(true);
454            delayedReStartBox.addActionListener( ev -> handleResetWhenDoneClick());
455            delayedReStartBox.setToolTipText(Bundle.getMessage("DelayedReStartHint"));
456            initiatePane.add(p9a);
457
458            // Restart using timer
459            JPanel p9b = new JPanel();
460            ((FlowLayout) p9b.getLayout()).setVgap(1);
461            p9b.add(delayMinLabel);
462            p9b.add(delayMinSpinner); // already set to 0
463            delayMinSpinner.setToolTipText(Bundle.getMessage("RestartTimedHint"));
464            p9b.add(delayReStartSensorLabel);
465            p9b.add(delayReStartSensor);
466            delayReStartSensor.setAllowNull(true);
467            handleResetWhenDoneClick();
468            initiatePane.add(p9b);
469
470            initiatePane.add(new JSeparator());
471
472            // Reverse at end
473            JPanel p10 = new JPanel();
474            p10.add(reverseAtEndBox);
475            reverseAtEndBox.setToolTipText(Bundle.getMessage("ReverseAtEndBoxHint"));
476            initiatePane.add(p10);
477            reverseAtEndBox.addActionListener( ev -> handleReverseAtEndBoxClick());
478
479            // Reverse using sensor
480            JPanel pDelayReverseRestartDetails = new JPanel();
481            ((FlowLayout) pDelayReverseRestartDetails.getLayout()).setVgap(1);
482            pDelayReverseRestartDetails.add(delayReverseReStartLabel);
483            pDelayReverseRestartDetails.add(reverseDelayedRestartType);
484            pDelayReverseRestartDetails.add(delayReverseResetSensorBox);
485            delayReverseResetSensorBox.setToolTipText(Bundle.getMessage("ReverseResetRestartSensorHint"));
486            delayReverseResetSensorBox.setSelected(true);
487            reverseDelayedRestartType.addActionListener( ev -> handleReverseAtEndBoxClick());
488            reverseDelayedRestartType.setToolTipText(Bundle.getMessage("ReverseDelayedReStartHint"));
489            initiatePane.add(pDelayReverseRestartDetails);
490
491            // Reverse using timer
492            JPanel pDelayReverseRestartDetails2 = new JPanel();
493            ((FlowLayout) pDelayReverseRestartDetails2.getLayout()).setVgap(1);
494            pDelayReverseRestartDetails2.add(delayReverseMinLabel);
495            pDelayReverseRestartDetails2.add(delayReverseMinSpinner); // already set to 0
496            delayReverseMinSpinner.setToolTipText(Bundle.getMessage("ReverseRestartTimedHint"));
497            pDelayReverseRestartDetails2.add(delayReverseReStartSensorLabel);
498            pDelayReverseRestartDetails2.add(delayReverseReStartSensor);
499            delayReverseReStartSensor.setAllowNull(true);
500            handleReverseAtEndBoxClick();
501            initiatePane.add(pDelayReverseRestartDetails2);
502
503            initiatePane.add(new JSeparator());
504
505            // Terminate when done option
506            JPanel p11 = new JPanel();
507            p11.setLayout(new FlowLayout());
508            p11.add(terminateWhenDoneBox);
509            terminateWhenDoneBox.addActionListener( ev -> handleTerminateWhenDoneBoxClick());
510            initiatePane.add(p11);
511
512            // Optional next train, tied to terminate when done.
513            terminateWhenDoneDetails.setLayout(new FlowLayout());
514            terminateWhenDoneDetails.add(nextTrainLabel);
515            terminateWhenDoneDetails.add(nextTrain);
516            nextTrain.setToolTipText(Bundle.getMessage("TerminateWhenDoneNextTrainHint"));
517            initiatePane.add(terminateWhenDoneDetails);
518            handleTerminateWhenDoneBoxClick();
519
520            initiatePane.add(new JSeparator());
521
522            // Priority and train type.
523            JPanel p12 = new JPanel();
524            p12.setLayout(new FlowLayout());
525            p12.add(new JLabel(Bundle.getMessage("PriorityLabel") + ":"));
526            p12.add(prioritySpinner); // already set to 5
527            prioritySpinner.setToolTipText(Bundle.getMessage("PriorityHint"));
528            p12.add(new JLabel("     "));
529            p12.add(new JLabel(Bundle.getMessage("TrainTypeBoxLabel")));
530            initializeTrainTypeBox();
531            p12.add(trainTypeBox);
532            trainTypeBox.setSelectedIndex(1);
533            trainTypeBox.setToolTipText(Bundle.getMessage("TrainTypeBoxHint"));
534            initiatePane.add(p12);
535
536            // Delayed start option
537            JPanel p13 = new JPanel();
538            p13.add(new JLabel(Bundle.getMessage("DelayedStart")));
539            p13.add(delayedStartBox);
540            delayedStartBox.setToolTipText(Bundle.getMessage("DelayedStartHint"));
541            delayedStartBox.addActionListener(this::handleDelayStartClick);
542            p13.add(departureTimeLabel);
543            departureHrSpinner.setEditor(new JSpinner.NumberEditor(departureHrSpinner, "00"));
544            p13.add(departureHrSpinner);
545            departureHrSpinner.setValue(8);
546            departureHrSpinner.setToolTipText(Bundle.getMessage("DepartureTimeHrHint"));
547            p13.add(departureSepLabel);
548            departureMinSpinner.setEditor(new JSpinner.NumberEditor(departureMinSpinner, "00"));
549            p13.add(departureMinSpinner);
550            departureMinSpinner.setValue(0);
551            departureMinSpinner.setToolTipText(Bundle.getMessage("DepartureTimeMinHint"));
552            p13.add(delaySensor);
553            delaySensor.setAllowNull(true);
554            p13.add(resetStartSensorBox);
555            resetStartSensorBox.setToolTipText(Bundle.getMessage("ResetStartSensorHint"));
556            resetStartSensorBox.setSelected(true);
557            handleDelayStartClick(null);
558            initiatePane.add(p13);
559
560            // Load at startup option
561            JPanel p14 = new JPanel();
562            p14.setLayout(new FlowLayout());
563            p14.add(loadAtStartupBox);
564            loadAtStartupBox.setToolTipText(Bundle.getMessage("LoadAtStartupBoxHint"));
565            loadAtStartupBox.setSelected(false);
566            initiatePane.add(p14);
567
568            // Auto run option
569            initiatePane.add(new JSeparator());
570            JPanel p15 = new JPanel();
571            p15.add(autoRunBox);
572            autoRunBox.addActionListener( ev -> handleAutoRunClick());
573            autoRunBox.setToolTipText(Bundle.getMessage("AutoRunBoxHint"));
574            autoRunBox.setSelected(false);
575            initiatePane.add(p15);
576            initializeAutoRunItems();
577
578            // Footer buttons
579            JPanel ftr = new JPanel();
580            JButton cancelButton = new JButton(Bundle.getMessage("ButtonCancel"));
581            ftr.add(cancelButton);
582            cancelButton.addActionListener( ev -> cancelInitiateTrain());
583            cancelButton.setToolTipText(Bundle.getMessage("CancelButtonHint"));
584            ftr.add(addNewTrainButton = new JButton(Bundle.getMessage("ButtonCreate")));
585            addNewTrainButton.addActionListener( e1 -> addNewTrain());
586            addNewTrainButton.setToolTipText(Bundle.getMessage("AddNewTrainButtonHint"));
587
588            JPanel mainPane = new JPanel(new BorderLayout());
589            JScrollPane scrPane = new JScrollPane(initiatePane);
590            mainPane.add(hdr, BorderLayout.NORTH);
591            mainPane.add(scrPane, BorderLayout.CENTER);
592            mainPane.add(ftr, BorderLayout.SOUTH);
593            initiateFrame.setContentPane(mainPane);
594            switch (trainInfo.getTrainsFrom()) {
595                case TRAINSFROMROSTER:
596                    radioTrainsFromRoster.setSelected(true);
597                    break;
598                case TRAINSFROMOPS:
599                    radioTrainsFromOps.setSelected(true);
600                    break;
601                case TRAINSFROMUSER:
602                    radioTrainsFromUser.setSelected(true);
603                    break;
604                case TRAINSFROMSETLATER:
605                default:
606                    radioTrainsFromSetLater.setSelected(true);
607            }
608
609        }
610        autoRunBox.setSelected(false);
611        loadAtStartupBox.setSelected(false);
612        initializeFreeTransitsCombo(new ArrayList<>());
613        refreshNextTrainCombo();
614        setTrainsFromOptions(trainInfo.getTrainsFrom());
615        initiateFrame.pack();
616        initiateFrame.setVisible(true);
617
618        trainInfoToDialog(trainInfo);
619    }
620
621    private void refreshNextTrainCombo() {
622        Object saveEntry = null;
623        if (nextTrain.getSelectedIndex() > 0) {
624            saveEntry=nextTrain.getSelectedItem();
625        }
626        nextTrain.removeAllItems();
627        nextTrain.addItem(" ");
628        for (String file: _tiFile.getTrainInfoFileNames()) {
629            nextTrain.addItem(file);
630        }
631        if (saveEntry != null) {
632            nextTrain.setSelectedItem(saveEntry);
633        }
634    }
635
636    private void setTrainsFromOptions(TrainsFrom transFrom) {
637        switch (transFrom) {
638            case TRAINSFROMROSTER:
639                initializeFreeRosterEntriesCombo();
640                rosterComboBox.setVisible(true);
641                trainSelectBox.setVisible(false);
642                trainFieldLabel.setVisible(true);
643                trainNameField.setVisible(true);
644                dccAddressFieldLabel.setVisible(false);
645                dccAddressSpinner.setVisible(false);
646                break;
647            case TRAINSFROMOPS:
648                initializeFreeTrainsCombo();
649                trainSelectBox.setVisible(true);
650                rosterComboBox.setVisible(false);
651                trainFieldLabel.setVisible(true);
652                trainNameField.setVisible(true);
653                dccAddressFieldLabel.setVisible(true);
654                dccAddressSpinner.setVisible(true);
655                setSpeedProfileOptions(trainInfo,false);
656                break;
657            case TRAINSFROMUSER:
658                trainNameField.setText("");
659                trainSelectBox.setVisible(false);
660                rosterComboBox.setVisible(false);
661                trainFieldLabel.setVisible(true);
662                trainNameField.setVisible(true);
663                dccAddressFieldLabel.setVisible(true);
664                dccAddressSpinner.setVisible(true);
665                dccAddressSpinner.setEnabled(true);
666                setSpeedProfileOptions(trainInfo,false);
667                break;
668            case TRAINSFROMSETLATER:
669            default:
670                rosterComboBox.setVisible(false);
671                trainSelectBox.setVisible(false);
672                trainFieldLabel.setVisible(true);
673                trainNameField.setVisible(true);
674                dccAddressFieldLabel.setVisible(false);
675                dccAddressSpinner.setVisible(false);
676        }
677    }
678
679    private void initializeTrainTypeBox() {
680        trainTypeBox.removeAllItems();
681        trainTypeBox.addItem("<" + Bundle.getMessage("None").toLowerCase() + ">"); // <none>
682        trainTypeBox.addItem(Bundle.getMessage("LOCAL_PASSENGER"));
683        trainTypeBox.addItem(Bundle.getMessage("LOCAL_FREIGHT"));
684        trainTypeBox.addItem(Bundle.getMessage("THROUGH_PASSENGER"));
685        trainTypeBox.addItem(Bundle.getMessage("THROUGH_FREIGHT"));
686        trainTypeBox.addItem(Bundle.getMessage("EXPRESS_PASSENGER"));
687        trainTypeBox.addItem(Bundle.getMessage("EXPRESS_FREIGHT"));
688        trainTypeBox.addItem(Bundle.getMessage("MOW"));
689        // NOTE: The above must correspond in order and name to definitions in ActiveTrain.java.
690    }
691
692    private void initializeTrainDetectionBox() {
693        trainDetectionComboBox.addItem(new TrainDetectionItem(Bundle.getMessage("TrainDetectionWholeTrain"),TrainDetection.TRAINDETECTION_WHOLETRAIN));
694        trainDetectionComboBox.addItem(new TrainDetectionItem(Bundle.getMessage("TrainDetectionHeadAndTail"),TrainDetection.TRAINDETECTION_HEADANDTAIL));
695        trainDetectionComboBox.addItem(new TrainDetectionItem(Bundle.getMessage("TrainDetectionHeadOnly"),TrainDetection.TRAINDETECTION_HEADONLY));
696    }
697
698    private void initializeScaleLengthBox() {
699        trainLengthUnitsComboBox.addItem(new TrainLengthUnitsItem(Bundle.getMessage("TrainLengthInScaleFeet"), TrainLengthUnits.TRAINLENGTH_SCALEFEET));
700        trainLengthUnitsComboBox.addItem(new TrainLengthUnitsItem(Bundle.getMessage("TrainLengthInScaleMeters"), TrainLengthUnits.TRAINLENGTH_SCALEMETERS));
701        trainLengthUnitsComboBox.addItem(new TrainLengthUnitsItem(Bundle.getMessage("TrainLengthInActualInchs"), TrainLengthUnits.TRAINLENGTH_ACTUALINCHS));
702        trainLengthUnitsComboBox.addItem(new TrainLengthUnitsItem(Bundle.getMessage("TrainLengthInActualcm"), TrainLengthUnits.TRAINLENGTH_ACTUALCM));
703    }
704
705    private void handleTransitSelectionChanged(ActionEvent e) {
706        int index = transitSelectBox.getSelectedIndex();
707        if (index < 0) {
708            return;
709        }
710        Transit t = transitSelectBox.getSelectedItem();
711        if ((t != null) && (t != selectedTransit)) {
712            selectedTransit = t;
713            initializeStartingBlockCombo();
714            initializeDestinationBlockCombo();
715            initiateFrame.pack();
716        }
717    }
718
719    private void handleInTransitClick() {
720        if (!inTransitBox.isSelected() && selectedTransit.getEntryBlocksList().isEmpty()) {
721            JmriJOptionPane.showMessageDialog(initiateFrame, Bundle
722                    .getMessage("NoEntryBlocks"), Bundle.getMessage("MessageTitle"),
723                    JmriJOptionPane.INFORMATION_MESSAGE);
724            inTransitBox.setSelected(true);
725        }
726        initializeStartingBlockCombo();
727        initializeDestinationBlockCombo();
728        initiateFrame.pack();
729    }
730
731    private void handleTrainSelectionChanged() {
732        if (!trainsFromButtonGroup.getSelection().getActionCommand().equals("TRAINSFROMOPS")) {
733            return;
734        }
735        int ix = trainSelectBox.getSelectedIndex();
736        if (ix < 1) { // no train selected
737            dccAddressSpinner.setEnabled(false);
738            return;
739        }
740        dccAddressSpinner.setEnabled(true);
741        int dccAddress;
742        try {
743            dccAddress = Integer.parseInt((((Train) trainSelectBox.getSelectedItem()).getLeadEngineDccAddress()));
744        } catch (NumberFormatException ex) {
745            JmriJOptionPane.showMessageDialog(initiateFrame, Bundle.getMessage("Error43"),
746                    Bundle.getMessage("ErrorTitle"), JmriJOptionPane.ERROR_MESSAGE);
747            return;
748        }
749        dccAddressSpinner.setValue (dccAddress);
750        trainNameField.setText(((Train) trainSelectBox.getSelectedItem()).getName());
751    }
752
753    private void handleRosterSelectionChanged(ActionEvent e) {
754        if (!trainsFromButtonGroup.getSelection().getActionCommand().equals("TRAINSFROMROSTER")) {
755            return;
756        }
757        int ix = rosterComboBox.getSelectedIndex();
758        if (ix > 0) { // first item is "Select Loco" string
759            RosterEntry r = (RosterEntry) rosterComboBox.getItemAt(ix);
760            // check to see if speed profile exists and is not empty
761            if (r.getSpeedProfile() == null || r.getSpeedProfile().getProfileSize() < 1) {
762                // disable profile boxes etc.
763                setSpeedProfileOptions(trainInfo,false);
764            } else {
765                // enable profile boxes
766                setSpeedProfileOptions(trainInfo,true);
767            }
768            maxSpeedSpinner.setValue(r.getMaxSpeedPCT()/100.0f);
769            trainNameField.setText(r.titleString());
770            if (r.getAttribute("DispatcherTrainType") != null && !r.getAttribute("DispatcherTrainType").equals("")) {
771                trainTypeBox.setSelectedItem(r.getAttribute("DispatcherTrainType"));
772            }
773        } else {
774            setSpeedProfileOptions(trainInfo,false);
775        }
776    }
777
778    private void handleDelayStartClick(ActionEvent e) {
779        departureHrSpinner.setVisible(false);
780        departureMinSpinner.setVisible(false);
781        departureTimeLabel.setVisible(false);
782        departureSepLabel.setVisible(false);
783        delaySensor.setVisible(false);
784        resetStartSensorBox.setVisible(false);
785        if (delayedStartBox.getSelectedItem().equals(Bundle.getMessage("DelayedStartTimed"))) {
786            departureHrSpinner.setVisible(true);
787            departureMinSpinner.setVisible(true);
788            departureTimeLabel.setVisible(true);
789            departureSepLabel.setVisible(true);
790        } else if (delayedStartBox.getSelectedItem().equals(Bundle.getMessage("DelayedStartSensor"))) {
791            delaySensor.setVisible(true);
792            resetStartSensorBox.setVisible(true);
793        }
794        initiateFrame.pack(); // to fit extra hh:mm in window
795    }
796
797    private void handleResetWhenDoneClick() {
798        delayMinSpinner.setVisible(false);
799        delayMinLabel.setVisible(false);
800        delayedReStartLabel.setVisible(false);
801        delayedReStartBox.setVisible(false);
802        delayReStartSensorLabel.setVisible(false);
803        delayReStartSensor.setVisible(false);
804        resetRestartSensorBox.setVisible(false);
805        if (resetWhenDoneBox.isSelected()) {
806            delayedReStartLabel.setVisible(true);
807            delayedReStartBox.setVisible(true);
808            terminateWhenDoneBox.setSelected(false);
809            if (delayedReStartBox.getSelectedItem().equals(Bundle.getMessage("DelayedStartTimed"))) {
810                delayMinSpinner.setVisible(true);
811                delayMinLabel.setVisible(true);
812            } else if (delayedReStartBox.getSelectedItem().equals(Bundle.getMessage("DelayedStartSensor"))) {
813                delayReStartSensor.setVisible(true);
814                delayReStartSensorLabel.setVisible(true);
815                resetRestartSensorBox.setVisible(true);
816            }
817        } else {
818            terminateWhenDoneBox.setEnabled(true);
819        }
820        initiateFrame.pack();
821    }
822
823    private void handleTerminateWhenDoneBoxClick() {
824        if (terminateWhenDoneBox.isSelected()) {
825            refreshNextTrainCombo();
826            resetWhenDoneBox.setSelected(false);
827            terminateWhenDoneDetails.setVisible(true);
828        } else {
829            terminateWhenDoneDetails.setVisible(false);
830        }
831    }
832
833    private void handleReverseAtEndBoxClick() {
834        delayReverseMinSpinner.setVisible(false);
835        delayReverseMinLabel.setVisible(false);
836        delayReverseReStartLabel.setVisible(false);
837        reverseDelayedRestartType.setVisible(false);
838        delayReverseReStartSensorLabel.setVisible(false);
839        delayReverseReStartSensor.setVisible(false);
840        delayReverseResetSensorBox.setVisible(false);
841        if (reverseAtEndBox.isSelected()) {
842            delayReverseReStartLabel.setVisible(true);
843            reverseDelayedRestartType.setVisible(true);
844            if (reverseDelayedRestartType.getSelectedItem().equals(Bundle.getMessage("DelayedStartTimed"))) {
845                delayReverseMinSpinner.setVisible(true);
846                delayReverseMinLabel.setVisible(true);
847            } else if (reverseDelayedRestartType.getSelectedItem().equals(Bundle.getMessage("DelayedStartSensor"))) {
848                delayReverseReStartSensor.setVisible(true);
849                delayReStartSensorLabel.setVisible(true);
850                delayReverseResetSensorBox.setVisible(true);
851            }
852        }
853        initiateFrame.pack();
854
855        if (resetWhenDoneBox.isSelected()) {
856            terminateWhenDoneBox.setSelected(false);
857            terminateWhenDoneBox.setEnabled(false);
858        } else {
859            terminateWhenDoneBox.setEnabled(true);
860        }
861    }
862
863    private void handleAutoRunClick() {
864        showHideAutoRunItems(autoRunBox.isSelected());
865        initiateFrame.pack();
866    }
867
868    private void handleStartingBlockSelectionChanged() {
869        if (radioTransitsAdHoc.isSelected() ) {
870            initializeViaBlockDynamicCombo();
871            initializeDestinationBlockDynamicCombo();
872        } else {
873            initializeDestinationBlockCombo();
874        }
875        initiateFrame.pack();
876    }
877
878    private void handleViaBlockSelectionChanged() {
879        if (radioTransitsAdHoc.isSelected() ) {
880            initializeDestinationBlockDynamicCombo();
881        } else {
882            initializeDestinationBlockCombo();
883        }
884        initiateFrame.pack();
885    }
886
887    private void handleAllocateAllTheWayButtonChanged() {
888        allocateCustomSpinner.setVisible(false);
889    }
890
891    private void handleAllocateBySafeButtonChanged() {
892        allocateCustomSpinner.setVisible(false);
893    }
894
895    private void handleAllocateNumberOfBlocksButtonChanged() {
896        allocateCustomSpinner.setVisible(true);
897    }
898
899    private void cancelInitiateTrain() {
900        _dispatcher.newTrainDone(null);
901    }
902
903    /*
904     * Handles press of "Add New Train" button.
905     * Move data to TrainInfo validating basic information
906     * Call dispatcher to start the train from traininfo which
907     * completes validation.
908     */
909    private void addNewTrain() {
910        try {
911            validateDialog();
912            trainInfo = new TrainInfo();
913            dialogToTrainInfo(trainInfo);
914            if (radioTransitsAdHoc.isSelected()) {
915                int ixStart, ixEnd, ixVia;
916                ixStart = startingBlockBox.getSelectedIndex();
917                ixEnd = destinationBlockBox.getSelectedIndex();
918                ixVia = viaBlockBox.getSelectedIndex();
919                // search for a transit if ones available.
920                Transit tmpTransit = null;
921                int routeCount = 9999;
922                int startBlockSeq = 0;
923                int endBlockSeq = 0;
924                log.debug("Start[{}]Via[{}]Dest[{}}]",
925                        startingBlockBoxList.get(ixStart).getDisplayName(),
926                        viaBlockBoxList.get(ixVia).getDisplayName(),
927                        destinationBlockBoxList.get(ixEnd).getDisplayName());
928                for (Transit tr : InstanceManager.getDefault(jmri.TransitManager.class)
929                        .getListUsingBlock(startingBlockBoxList.get(ixStart))) {
930                    if (tr.getState() == Transit.IDLE
931                            && tr.containsBlock(startingBlockBoxList.get(ixStart))
932                            && tr.containsBlock(viaBlockBoxList.get(ixVia)) &&
933                            tr.containsBlock(destinationBlockBoxList.get(ixEnd))) {
934                        log.debug("[{}]  contains all blocks", tr.getDisplayName());
935                        int ixCountStart = -1, ixCountVia = -1, ixCountDest = -1, ixCount = 0;
936                        List<Block> transitBlocks = tr.getInternalBlocksList();
937                        List<Integer> transitBlockSeq = tr.getBlockSeqList();
938                        for (Block blk : transitBlocks) {
939                            log.debug("Checking Block[{}] t[{}] BlockSequ[{}]",
940                                    blk.getDisplayName(),
941                                    ixCount,
942                                    transitBlockSeq.get(ixCount));
943                            if (ixCountStart == -1 && blk == startingBlockBoxList.get(ixStart)) {
944                                log.trace("ixOne[{}]block[{}]",ixCount,blk.getDisplayName());
945                                ixCountStart = ixCount;
946                            } else if (ixCountStart != -1 && ixCountVia == -1 && blk == viaBlockBoxList.get(ixVia)) {
947                                log.trace("ixTwo[{}]block[{}]",ixCount,blk.getDisplayName());
948                                if (ixCount != ixCountStart + 1) {
949                                    log.debug("AdHoc {}:via and start not ajacent",tr.getDisplayName());
950                                    break;
951                                }
952                                ixCountVia = ixCount;
953                            } else if (ixCountStart != -1 && ixCountVia != -1 && ixCountDest == -1 && blk == destinationBlockBoxList.get(ixEnd)) {
954                                ixCountDest = ixCount;
955                                log.trace("ixThree[{}]block[{}]",ixCountDest,blk.getDisplayName());
956                                break;
957                            }
958                            ixCount++;
959                        }
960                        if (ixCountVia == (ixCountStart + 1) && ixCountDest > ixCountStart) {
961                            log.debug("Canuse [{}", tr.getDisplayName());
962                            Integer routeBlockLength =
963                                    transitBlockSeq.get(ixCountDest) - transitBlockSeq.get(ixCountStart);
964                            if (routeBlockLength < routeCount) {
965                                routeCount = ixCountDest - ixCountStart;
966                                tmpTransit = tr;
967                                startBlockSeq = transitBlockSeq.get(ixCountStart).intValue();
968                                endBlockSeq = transitBlockSeq.get(ixCountDest).intValue();
969                            }
970                        }
971                    }
972                }
973                if (tmpTransit != null &&
974                        (JmriJOptionPane.showConfirmDialog(this, Bundle.getMessage("Question6",tmpTransit.getDisplayName()),
975                                "Question",
976                                JmriJOptionPane.YES_NO_OPTION,
977                                JmriJOptionPane.QUESTION_MESSAGE) == JmriJOptionPane.YES_OPTION)) {
978                    // use transit found
979                    trainInfo.setDynamicTransit(false);
980                    trainInfo.setTransitName(tmpTransit.getDisplayName());
981                    trainInfo.setTransitId(tmpTransit.getDisplayName());
982                    trainInfo.setStartBlockSeq(startBlockSeq);
983                    trainInfo.setStartBlockName(getBlockName(startingBlockBoxList.get(ixStart)) + "-" + startBlockSeq);
984                    trainInfo.setDestinationBlockSeq(endBlockSeq);
985                    trainInfo.setDestinationBlockName(getBlockName(destinationBlockBoxList.get(ixEnd)) + "-" + endBlockSeq);
986                    trainInfoToDialog(trainInfo);
987                } else {
988                    // use a true ad-hoc
989                    List<LayoutBlock> blockList = _dispatcher.getAdHocRoute(startingBlockBoxList.get(ixStart),
990                            destinationBlockBoxList.get(ixEnd),
991                            viaBlockBoxList.get(ixVia));
992                    if (blockList == null) {
993                        JmriJOptionPane.showMessageDialog(initiateFrame, Bundle.getMessage("Error51"),
994                                Bundle.getMessage("ErrorTitle"), JmriJOptionPane.ERROR_MESSAGE);
995                        return;
996                    }
997                }
998            }
999            _dispatcher.loadTrainFromTrainInfoThrowsException(trainInfo,"NONE","");
1000        } catch (IllegalArgumentException ex) {
1001            JmriJOptionPane.showMessageDialog(initiateFrame, ex.getMessage(),
1002                    Bundle.getMessage("ErrorTitle"), JmriJOptionPane.ERROR_MESSAGE);
1003        }
1004    }
1005
1006    private void initializeFreeTransitsCombo(List<Transit> transitList) {
1007        Set<Transit> excludeTransits = new HashSet<>();
1008        for (Transit t : _TransitManager.getNamedBeanSet()) {
1009            if (t.getState() != Transit.IDLE) {
1010                excludeTransits.add(t);
1011            }
1012        }
1013        transitSelectBox.setExcludedItems(excludeTransits);
1014        JComboBoxUtil.setupComboBoxMaxRows(transitSelectBox);
1015
1016        if (transitSelectBox.getItemCount() > 0) {
1017            transitSelectBox.setSelectedIndex(0);
1018            selectedTransit = transitSelectBox.getItemAt(0);
1019        } else {
1020            selectedTransit = null;
1021        }
1022    }
1023
1024    private void initializeFreeRosterEntriesCombo() {
1025        rosterComboBox.update();
1026        // remove used entries
1027        for (int ix = rosterComboBox.getItemCount() - 1; ix > 1; ix--) {  // remove from back first item is the "select loco" message
1028            if ( !_dispatcher.isAddressFree( ((RosterEntry)rosterComboBox.getItemAt(ix)).getDccLocoAddress().getNumber() ) ) {
1029                rosterComboBox.removeItemAt(ix);
1030            }
1031        }
1032    }
1033
1034    private void initializeFreeTrainsCombo() {
1035        Train prevValue = null;
1036        if (trainSelectBox.getSelectedIndex() > 0) {
1037            // item zero is a string
1038            prevValue = (Train)trainSelectBox.getSelectedItem();
1039        }
1040        ActionListener[] als = trainSelectBox.getActionListeners();
1041        for ( ActionListener al: als) {
1042            trainSelectBox.removeActionListener(al);
1043        }
1044        trainSelectBox.removeAllItems();
1045        trainSelectBox.addItem("Select Train");
1046        // initialize free trains from operations
1047        List<Train> trains = InstanceManager.getDefault(TrainManager.class).getTrainsByNameList();
1048        if (trains.size() > 0) {
1049            for (int i = 0; i < trains.size(); i++) {
1050                Train t = trains.get(i);
1051                if (t != null) {
1052                    String tName = t.getName();
1053                    if (_dispatcher.isTrainFree(tName)) {
1054                        trainSelectBox.addItem(t);
1055                    }
1056                }
1057            }
1058        }
1059        if (prevValue != null) {
1060            trainSelectBox.setSelectedItem(prevValue);
1061        }
1062        for ( ActionListener al: als) {
1063            trainSelectBox.addActionListener(al);
1064        }
1065    }
1066
1067    /**
1068     * Sets the labels and inputs for speed profile running
1069     * @param b True if the roster entry has valid speed profile else false
1070     */
1071    private void setSpeedProfileOptions(TrainInfo info,boolean b) {
1072        useSpeedProfileLabel.setEnabled(b);
1073        useSpeedProfileCheckBox.setEnabled(b);
1074        stopBySpeedProfileLabel.setEnabled(b);
1075        stopBySpeedProfileCheckBox.setEnabled(b);
1076        stopBySpeedProfileAdjustLabel.setEnabled(b);
1077        stopBySpeedProfileAdjustSpinner.setEnabled(b);
1078        if (!b) {
1079            useSpeedProfileCheckBox.setSelected(false);
1080            stopBySpeedProfileCheckBox.setSelected(false);
1081
1082        }
1083    }
1084
1085    private void initializeStartingBlockCombo() {
1086        String prevValue = (String)startingBlockBox.getSelectedItem();
1087        startingBlockBox.removeAllItems();
1088        startingBlockBoxList.clear();
1089        if (!inTransitBox.isSelected() && selectedTransit.getEntryBlocksList().isEmpty()) {
1090            inTransitBox.setSelected(true);
1091        }
1092        if (inTransitBox.isSelected()) {
1093            startingBlockBoxList = selectedTransit.getInternalBlocksList();
1094        } else {
1095            startingBlockBoxList = selectedTransit.getEntryBlocksList();
1096        }
1097        startingBlockSeqList = selectedTransit.getBlockSeqList();
1098        boolean found = false;
1099        for (int i = 0; i < startingBlockBoxList.size(); i++) {
1100            Block b = startingBlockBoxList.get(i);
1101            int seq = startingBlockSeqList.get(i).intValue();
1102            startingBlockBox.addItem(getBlockName(b) + "-" + seq);
1103            if (!found && b.getState() == Block.OCCUPIED) {
1104                startingBlockBox.setSelectedItem(getBlockName(b) + "-" + seq);
1105                found = true;
1106            }
1107        }
1108        if (prevValue != null) {
1109            startingBlockBox.setSelectedItem(prevValue);
1110        }
1111        JComboBoxUtil.setupComboBoxMaxRows(startingBlockBox);
1112    }
1113
1114    private void initializeDestinationBlockCombo() {
1115        String prevValue = (String)destinationBlockBox.getSelectedItem();
1116        destinationBlockBox.removeAllItems();
1117        destinationBlockBoxList.clear();
1118        int index = startingBlockBox.getSelectedIndex();
1119        if (index < 0) {
1120            return;
1121        }
1122        Block startBlock = startingBlockBoxList.get(index);
1123        destinationBlockBoxList = selectedTransit.getDestinationBlocksList(
1124                startBlock, inTransitBox.isSelected());
1125        destinationBlockSeqList = selectedTransit.getDestBlocksSeqList();
1126        for (int i = 0; i < destinationBlockBoxList.size(); i++) {
1127            Block b = destinationBlockBoxList.get(i);
1128            String bName = getBlockName(b);
1129            if (selectedTransit.getBlockCount(b) > 1) {
1130                int seq = destinationBlockSeqList.get(i).intValue();
1131                bName = bName + "-" + seq;
1132            }
1133            destinationBlockBox.addItem(bName);
1134        }
1135        if (prevValue != null) {
1136            destinationBlockBox.setSelectedItem(prevValue);
1137        }
1138        JComboBoxUtil.setupComboBoxMaxRows(destinationBlockBox);
1139    }
1140
1141    private String getBlockName(Block b) {
1142        if (b != null) {
1143            return b.getDisplayName();
1144        }
1145        return " ";
1146    }
1147
1148    protected void showActivateFrame() {
1149        if (initiateFrame != null) {
1150            initializeFreeTransitsCombo(new ArrayList<>());
1151            initiateFrame.setVisible(true);
1152        } else {
1153            _dispatcher.newTrainDone(null);
1154        }
1155    }
1156
1157    /**
1158     * Show the Frame.
1159     * @param re currently unused.
1160     */
1161    public void showActivateFrame(RosterEntry re) {
1162        showActivateFrame();
1163    }
1164
1165    protected void loadTrainInfo(ActionEvent e) {
1166        List<TrainInfoFileSummary> names = _tiFile.getTrainInfoFileSummaries();
1167        if (!names.isEmpty()) {
1168            JTable table = new JTable(){
1169                @Override
1170                public Dimension getPreferredScrollableViewportSize() {
1171                  return new Dimension(super.getPreferredSize().width,
1172                      super.getPreferredScrollableViewportSize().height);
1173                }
1174              };
1175            DefaultTableModel tm = new DefaultTableModel(
1176                    new Object[]{
1177                            Bundle.getMessage("FileNameColumnTitle"),
1178                            Bundle.getMessage("TrainColumnTitle"),
1179                            Bundle.getMessage("TransitColumnTitle"),
1180                            Bundle.getMessage("StartBlockColumnTitle"),
1181                            Bundle.getMessage("EndBlockColumnTitle"),
1182                            Bundle.getMessage("DccColumnTitleColumnTitle")
1183                    }, 0) {
1184                @Override
1185                public boolean isCellEditable(int row, int column) {
1186                    //all cells false
1187                    return false;
1188                }
1189            };
1190
1191            table.setModel(tm);
1192            for (TrainInfoFileSummary fs: names) {
1193                tm.addRow(new Object[] {fs.getFileName(),fs.getTrainName(),
1194                        fs.getTransitName(),fs.getStartBlockName()
1195                        ,fs.getEndBlockName(),fs.getDccAddress()});
1196            }
1197            JPanel jp = new JPanel(new BorderLayout());
1198            TableColumnModel columnModel = table.getColumnModel();
1199            table.setAutoResizeMode( JTable.AUTO_RESIZE_OFF );
1200            for (int column = 0; column < table.getColumnCount(); column++) {
1201                int width = 30; // Min width
1202                for (int row = 0; row < table.getRowCount(); row++) {
1203                    TableCellRenderer renderer = table.getCellRenderer(row, column);
1204                    Component comp = table.prepareRenderer(renderer, row, column);
1205                    width = Math.max(comp.getPreferredSize().width +1 , width);
1206                }
1207                if(width > 300)
1208                    width=300;
1209                columnModel.getColumn(column).setPreferredWidth(width);
1210            }
1211            //jp.setPreferredSize(table.getPreferredSize());
1212            jp.add(table);
1213            JScrollPane sp = new JScrollPane(table,
1214                            ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED,
1215                            ScrollPaneConstants.HORIZONTAL_SCROLLBAR_AS_NEEDED);
1216            int optionSelected = JmriJOptionPane.showOptionDialog(initiateFrame,
1217                    sp, Bundle.getMessage("LoadTrainTitle"), JmriJOptionPane.OK_CANCEL_OPTION, JmriJOptionPane.PLAIN_MESSAGE,
1218                    null,null,null);
1219            if (optionSelected != JmriJOptionPane.OK_OPTION) {
1220                //Canceled
1221                return;
1222            }
1223            if (table.getSelectedRow() < 0) {
1224                return;
1225            }
1226            String selName = (String)table.getModel().getValueAt(table.getSelectedRow(),0);
1227            if ((selName == null) || (selName.isEmpty())) {
1228                return;
1229            }
1230            //read xml data from selected filename and move it into the new train dialog box
1231            _trainInfoName = selName;
1232            try {
1233                trainInfo = _tiFile.readTrainInfo( selName);
1234                if (trainInfo != null) {
1235                    // process the information just read
1236                    trainInfoToDialog(trainInfo);
1237                }
1238            } catch (java.io.IOException ioe) {
1239                log.error("IO Exception when reading train info file", ioe);
1240            } catch (org.jdom2.JDOMException jde) {
1241                log.error("JDOM Exception when reading train info file", jde);
1242            }
1243            handleDelayStartClick(null);
1244            handleReverseAtEndBoxClick();
1245        }
1246    }
1247
1248    private void saveTrainInfo() {
1249        saveTrainInfo(false);
1250        refreshNextTrainCombo();
1251    }
1252
1253    private void saveTrainInfoAsTemplate() {
1254        saveTrainInfo(true);
1255    }
1256
1257    private void saveTrainInfo(boolean asTemplate) {
1258        try {
1259            dialogToTrainInfo(trainInfo);
1260        } catch (IllegalArgumentException ide) {
1261            JmriJOptionPane.showMessageDialog(initiateFrame, ide.getMessage(),
1262                    Bundle.getMessage("ErrorTitle"), JmriJOptionPane.ERROR_MESSAGE);
1263            return;
1264        }
1265        // get file name
1266        String fileName;
1267        if (asTemplate) {
1268            fileName = normalizeXmlFileName(nameOfTemplateFile);
1269        } else {
1270            String eName = JmriJOptionPane.showInputDialog(initiateFrame,
1271                    Bundle.getMessage("EnterFileName") + " :", _trainInfoName);
1272            if (eName == null) {  //Cancel pressed
1273                return;
1274            }
1275            if (eName.length() < 1) {
1276                JmriJOptionPane.showMessageDialog(initiateFrame, Bundle.getMessage("Error25"),
1277                        Bundle.getMessage("ErrorTitle"), JmriJOptionPane.ERROR_MESSAGE);
1278                return;
1279            }
1280            fileName = normalizeXmlFileName(eName);
1281            _trainInfoName = fileName;
1282        }
1283        // check if train info file name is in use
1284        String[] names = _tiFile.getTrainInfoFileNames();
1285        if (names.length > 0) {
1286            boolean found = false;
1287            for (int i = 0; i < names.length; i++) {
1288                if (fileName.equals(names[i])) {
1289                    found = true;
1290                }
1291            }
1292            if (found) {
1293                // file by that name is already present
1294                int selectedValue = JmriJOptionPane.showOptionDialog(initiateFrame,
1295                        Bundle.getMessage("Question3", fileName),
1296                        Bundle.getMessage("WarningTitle"), JmriJOptionPane.DEFAULT_OPTION,
1297                        JmriJOptionPane.QUESTION_MESSAGE, null,
1298                        new Object[]{Bundle.getMessage("ButtonReplace"),Bundle.getMessage("ButtonNo")},
1299                        Bundle.getMessage("ButtonNo"));
1300                if (selectedValue != 0 ) { // array position 0 , replace not selected
1301                    return;   // return without writing if "No" response
1302                }
1303            }
1304        }
1305        // write the Train Info file
1306        try {
1307            _tiFile.writeTrainInfo(trainInfo, fileName);
1308        } //catch (org.jdom2.JDOMException jde) {
1309        // log.error("JDOM exception writing Train Info: "+jde);
1310        //}
1311        catch (java.io.IOException ioe) {
1312            log.error("IO exception writing Train Info", ioe);
1313        }
1314    }
1315
1316    private void deleteTrainInfo() {
1317        String[] names = _tiFile.getTrainInfoFileNames();
1318        if (names.length > 0) {
1319            Object selName = JmriJOptionPane.showInputDialog(initiateFrame,
1320                    Bundle.getMessage("DeleteTrainChoice"), Bundle.getMessage("DeleteTrainTitle"),
1321                    JmriJOptionPane.QUESTION_MESSAGE, null, names, names[0]);
1322            if ((selName == null) || (((String) selName).isEmpty())) {
1323                return;
1324            }
1325            _tiFile.deleteTrainInfoFile((String) selName);
1326        }
1327    }
1328
1329    private void trainInfoToDialog(TrainInfo info) {
1330        if (!info.getDynamicTransit()) {
1331            radioTransitsPredefined.setSelected(true);
1332            if (!info.getTransitName().isEmpty()) {
1333                try {
1334                    transitSelectBox.setSelectedItemByName(info.getTransitName());
1335                } catch (Exception ex) {
1336                    log.warn("Transit {} from file not in Transit menu", info.getTransitName());
1337                    JmriJOptionPane.showMessageDialog(initiateFrame,
1338                            Bundle.getMessage("TransitWarn", info.getTransitName()),
1339                            null, JmriJOptionPane.WARNING_MESSAGE);
1340                }
1341            }
1342        } else {
1343            radioTransitsAdHoc.setSelected(true);
1344        }
1345        switch (info.getTrainsFrom()) {
1346            case TRAINSFROMROSTER:
1347                radioTrainsFromRoster.setSelected(true);
1348                if (!info.getRosterId().isEmpty()) {
1349                    if (!setRosterComboBox(rosterComboBox, info.getRosterId())) {
1350                        log.warn("Roster {} from file not in Roster Combo", info.getRosterId());
1351                        JmriJOptionPane.showMessageDialog(initiateFrame,
1352                                Bundle.getMessage("TrainWarn", info.getRosterId()),
1353                                null, JmriJOptionPane.WARNING_MESSAGE);
1354                    }
1355                }
1356                break;
1357            case TRAINSFROMOPS:
1358                radioTrainsFromOps.setSelected(true);
1359                if (!info.getTrainName().isEmpty()) {
1360                    if (!setTrainComboBox(trainSelectBox, info.getTrainName())) {
1361                        log.warn("Train {} from file not in Train Combo", info.getTrainName());
1362                        JmriJOptionPane.showMessageDialog(initiateFrame,
1363                                Bundle.getMessage("TrainWarn", info.getTrainName()),
1364                                null, JmriJOptionPane.WARNING_MESSAGE);
1365                    }
1366                }
1367                break;
1368            case TRAINSFROMUSER:
1369                radioTrainsFromUser.setSelected(true);
1370                dccAddressSpinner.setValue(Integer.valueOf(info.getDccAddress()));
1371                break;
1372            case TRAINSFROMSETLATER:
1373            default:
1374                radioTrainsFromSetLater.setSelected(true);
1375        }
1376        trainNameField.setText(info.getTrainUserName());
1377        trainDetectionComboBox.setSelectedItemByValue(info.getTrainDetection());
1378        inTransitBox.setSelected(info.getTrainInTransit());
1379        if (radioTransitsAdHoc.isSelected()) {
1380            initializeStartingBlockComboDynamic();
1381        } else {
1382            initializeStartingBlockCombo();
1383        }
1384        setComboBox(startingBlockBox, info.getStartBlockName());
1385        if (radioTransitsAdHoc.isSelected()) {
1386            initializeViaBlockDynamicCombo();
1387            setComboBox(viaBlockBox, info.getViaBlockName());
1388        }
1389        if (radioTransitsAdHoc.isSelected()) {
1390            initializeDestinationBlockDynamicCombo();
1391        } else {
1392            initializeDestinationBlockCombo();
1393        }
1394        setComboBox(destinationBlockBox, info.getDestinationBlockName());
1395
1396        setAllocateMethodButtons(info.getAllocationMethod());
1397        prioritySpinner.setValue(info.getPriority());
1398        resetWhenDoneBox.setSelected(info.getResetWhenDone());
1399        reverseAtEndBox.setSelected(info.getReverseAtEnd());
1400        setDelayModeBox(info.getDelayedStart(), delayedStartBox);
1401        //delayedStartBox.setSelected(info.getDelayedStart());
1402        departureHrSpinner.setValue(info.getDepartureTimeHr());
1403        departureMinSpinner.setValue(info.getDepartureTimeMin());
1404        delaySensor.setSelectedItem(info.getDelaySensor());
1405        resetStartSensorBox.setSelected(info.getResetStartSensor());
1406        setDelayModeBox(info.getDelayedRestart(), delayedReStartBox);
1407        delayMinSpinner.setValue(info.getRestartDelayMin());
1408        delayReStartSensor.setSelectedItem(info.getRestartSensor());
1409        resetRestartSensorBox.setSelected(info.getResetRestartSensor());
1410
1411        resetStartSensorBox.setSelected(info.getResetStartSensor());
1412        setDelayModeBox(info.getReverseDelayedRestart(), reverseDelayedRestartType);
1413        delayReverseMinSpinner.setValue(info.getReverseRestartDelayMin());
1414        delayReverseReStartSensor.setSelectedItem(info.getReverseRestartSensor());
1415        delayReverseResetSensorBox.setSelected(info.getReverseResetRestartSensor());
1416
1417        terminateWhenDoneBox.setSelected(info.getTerminateWhenDone());
1418        nextTrain.setSelectedIndex(-1);
1419        try {
1420            nextTrain.setSelectedItem(info.getNextTrain());
1421        } catch (Exception ex){
1422            nextTrain.setSelectedIndex(-1);
1423        }
1424        handleTerminateWhenDoneBoxClick();
1425        setComboBox(trainTypeBox, info.getTrainType());
1426        autoRunBox.setSelected(info.getAutoRun());
1427        loadAtStartupBox.setSelected(info.getLoadAtStartup());
1428        setAllocateMethodButtons(info.getAllocationMethod());
1429        autoTrainInfoToDialog(info);
1430    }
1431
1432    private boolean validateDialog() throws IllegalArgumentException {
1433        int index = transitSelectBox.getSelectedIndex();
1434        if (index < 0) {
1435            throw new IllegalArgumentException(Bundle.getMessage("Error44"));
1436        }
1437        switch (trainsFromButtonGroup.getSelection().getActionCommand()) {
1438            case "TRAINSFROMROSTER":
1439                if (rosterComboBox.getSelectedIndex() < 1 ) {
1440                    throw new IllegalArgumentException(Bundle.getMessage("Error41"));
1441                }
1442                break;
1443            case "TRAINSFROMOPS":
1444                if (trainSelectBox.getSelectedIndex() < 1) {
1445                    throw new IllegalArgumentException(Bundle.getMessage("Error42"));
1446                }
1447                break;
1448            case "TRAINSFROMUSER":
1449                if (trainNameField.getText().isEmpty()) {
1450                    throw new IllegalArgumentException(Bundle.getMessage("Error22"));
1451                }
1452                break;
1453            case "TRAINSFROMSETLATER":
1454            default:
1455        }
1456        index = startingBlockBox.getSelectedIndex();
1457        if (index < 0) {
1458            throw new IllegalArgumentException(Bundle.getMessage("Error13"));
1459        }
1460        index = destinationBlockBox.getSelectedIndex();
1461        if (index < 0) {
1462            throw new IllegalArgumentException(Bundle.getMessage("Error8"));
1463        }
1464        if (radioTransitsAdHoc.isSelected()) {
1465            index = viaBlockBox.getSelectedIndex();
1466            if (index < 0) {
1467                throw new IllegalArgumentException(Bundle.getMessage("Error8"));
1468            }
1469        }
1470        if ((!reverseAtEndBox.isSelected()) && resetWhenDoneBox.isSelected()
1471                && (!selectedTransit.canBeResetWhenDone())) {
1472            resetWhenDoneBox.setSelected(false);
1473            throw new IllegalArgumentException(Bundle.getMessage("NoResetMessage"));
1474        }
1475        int max = Math.round((float) maxSpeedSpinner.getValue()*100.0f);
1476        int min = Math.round((float) minReliableOperatingSpeedSpinner.getValue()*100.0f);
1477        if ((max-min) < 10) {
1478            throw new IllegalArgumentException(Bundle.getMessage("Error49",
1479                    maxSpeedSpinner.getValue(), minReliableOperatingSpeedSpinner.getValue()));
1480        }
1481        return true;
1482    }
1483
1484    private boolean dialogToTrainInfo(TrainInfo info) {
1485        int index = transitSelectBox.getSelectedIndex();
1486        info.setDynamicTransit(radioTransitsAdHoc.isSelected());
1487        if (!info.getDynamicTransit() && index >= 0 ) {
1488            info.setTransitName(transitSelectBox.getSelectedItem().getDisplayName());
1489            info.setTransitId(transitSelectBox.getSelectedItem().getDisplayName());
1490        }
1491        switch (trainsFromButtonGroup.getSelection().getActionCommand()) {
1492            case "TRAINSFROMROSTER":
1493                info.setRosterId(((RosterEntry) rosterComboBox.getSelectedItem()).getId());
1494                info.setDccAddress(((RosterEntry) rosterComboBox.getSelectedItem()).getDccAddress());
1495                trainInfo.setTrainsFrom(TrainsFrom.TRAINSFROMROSTER);
1496                setTrainsFromOptions(trainInfo.getTrainsFrom());
1497                break;
1498            case "TRAINSFROMOPS":
1499                info.setTrainName(((Train) trainSelectBox.getSelectedItem()).toString());
1500                info.setDccAddress(String.valueOf(dccAddressSpinner.getValue()));
1501                trainInfo.setTrainsFrom(TrainsFrom.TRAINSFROMOPS);
1502                setTrainsFromOptions(trainInfo.getTrainsFrom());
1503                break;
1504            case "TRAINSFROMUSER":
1505                trainInfo.setTrainsFrom(TrainsFrom.TRAINSFROMUSER);
1506                info.setDccAddress(String.valueOf(dccAddressSpinner.getValue()));
1507                break;
1508            case "TRAINSFROMSETLATER":
1509            default:
1510                trainInfo.setTrainsFrom(TrainsFrom.TRAINSFROMSETLATER);
1511                info.setTrainName("");
1512                info.setDccAddress("");
1513        }
1514        info.setTrainUserName(trainNameField.getText());
1515        info.setTrainInTransit(inTransitBox.isSelected());
1516        info.setStartBlockName((String) startingBlockBox.getSelectedItem());
1517        index = startingBlockBox.getSelectedIndex();
1518        info.setStartBlockId(startingBlockBoxList.get(index).getDisplayName());
1519        if (info.getDynamicTransit()) {
1520            info.setStartBlockSeq(1);
1521        } else {
1522            info.setStartBlockSeq(startingBlockSeqList.get(index).intValue());
1523        }
1524        index = destinationBlockBox.getSelectedIndex();
1525        info.setDestinationBlockId(destinationBlockBoxList.get(index).getDisplayName());
1526        info.setDestinationBlockName(destinationBlockBoxList.get(index).getDisplayName());
1527        if (info.getDynamicTransit()) {
1528            info.setViaBlockName(viaBlockBoxList.get(viaBlockBox.getSelectedIndex()).getDisplayName());
1529        } else {
1530            info.setDestinationBlockSeq(destinationBlockSeqList.get(index).intValue());
1531        }
1532        info.setPriority((Integer) prioritySpinner.getValue());
1533        info.setTrainDetection(((TrainDetectionItem)trainDetectionComboBox.getSelectedItem()).value);
1534        info.setResetWhenDone(resetWhenDoneBox.isSelected());
1535        info.setReverseAtEnd(reverseAtEndBox.isSelected());
1536        info.setDelayedStart(delayModeFromBox(delayedStartBox));
1537        info.setDelaySensorName(delaySensor.getSelectedItemDisplayName());
1538        info.setResetStartSensor(resetStartSensorBox.isSelected());
1539        info.setDepartureTimeHr((Integer) departureHrSpinner.getValue());
1540        info.setDepartureTimeMin((Integer) departureMinSpinner.getValue());
1541        info.setTrainType((String) trainTypeBox.getSelectedItem());
1542        info.setAutoRun(autoRunBox.isSelected());
1543        info.setLoadAtStartup(loadAtStartupBox.isSelected());
1544        info.setAllocateAllTheWay(false); // force to false next field is now used.
1545        if (allocateAllTheWayRadioButton.isSelected()) {
1546            info.setAllocationMethod(ActiveTrain.ALLOCATE_AS_FAR_AS_IT_CAN);
1547        } else if (allocateBySafeRadioButton.isSelected()) {
1548            info.setAllocationMethod(ActiveTrain.ALLOCATE_BY_SAFE_SECTIONS);
1549        } else {
1550            info.setAllocationMethod((Integer) allocateCustomSpinner.getValue());
1551        }
1552        info.setDelayedRestart(delayModeFromBox(delayedReStartBox));
1553        info.setRestartSensorName(delayReStartSensor.getSelectedItemDisplayName());
1554        info.setResetRestartSensor(resetRestartSensorBox.isSelected());
1555        info.setRestartDelayMin((Integer) delayMinSpinner.getValue());
1556
1557        info.setReverseDelayedRestart(delayModeFromBox(reverseDelayedRestartType));
1558        info.setReverseRestartSensorName(delayReverseReStartSensor.getSelectedItemDisplayName());
1559        info.setReverseResetRestartSensor(delayReverseResetSensorBox.isSelected());
1560        info.setReverseRestartDelayMin((Integer) delayReverseMinSpinner.getValue());
1561
1562        info.setTerminateWhenDone(terminateWhenDoneBox.isSelected());
1563        if (nextTrain.getSelectedIndex() > 0 ) {
1564            info.setNextTrain((String)nextTrain.getSelectedItem());
1565        } else {
1566            info.setNextTrain("None");
1567        }
1568        autoRunItemsToTrainInfo(info);
1569        return true;
1570    }
1571
1572    private boolean setRosterComboBox(RosterEntryComboBox box, String txt) {
1573        boolean found = false;
1574        for (int i = 1; i < box.getItemCount(); i++) {
1575            if (txt.equals(((RosterEntry) box.getItemAt(i)).getId())) {
1576                box.setSelectedIndex(i);
1577                found = true;
1578                break;
1579            }
1580        }
1581        if (!found && box.getItemCount() > 0) {
1582            box.setSelectedIndex(0);
1583        }
1584        return found;
1585    }
1586
1587    // Normalizes a suggested xml file name.  Returns null string if a valid name cannot be assembled
1588    private String normalizeXmlFileName(String name) {
1589        if (name.length() < 1) {
1590            return "";
1591        }
1592        String newName = name;
1593        // strip off .xml or .XML if present
1594        if ((name.endsWith(".xml")) || (name.endsWith(".XML"))) {
1595            newName = name.substring(0, name.length() - 4);
1596            if (newName.length() < 1) {
1597                return "";
1598            }
1599        }
1600        // replace all non-alphanumeric characters with underscore
1601        newName = newName.replaceAll("[\\W]", "_");
1602        return (newName + ".xml");
1603    }
1604
1605    private boolean setTrainComboBox(JComboBox<Object> box, String txt) {
1606        boolean found = false;
1607        for (int i = 1; i < box.getItemCount(); i++) { //skip the select train item
1608            if (txt.equals(box.getItemAt(i).toString())) {
1609                box.setSelectedIndex(i);
1610                found = true;
1611                break;
1612            }
1613        }
1614        if (!found && box.getItemCount() > 0) {
1615            box.setSelectedIndex(0);
1616        }
1617        return found;
1618    }
1619
1620    private boolean setComboBox(JComboBox<String> box, String txt) {
1621        boolean found = false;
1622        for (int i = 0; i < box.getItemCount(); i++) {
1623            if (txt.equals(box.getItemAt(i))) {
1624                box.setSelectedIndex(i);
1625                found = true;
1626                break;
1627            }
1628        }
1629        if (!found && box.getItemCount() > 0) {
1630            box.setSelectedIndex(0);
1631        }
1632        return found;
1633    }
1634
1635    int delayModeFromBox(JComboBox<String> box) {
1636        String mode = (String) box.getSelectedItem();
1637        int result = jmri.util.StringUtil.getStateFromName(mode, delayedStartInt, delayedStartString);
1638
1639        if (result < 0) {
1640            log.warn("unexpected mode string in turnoutMode: {}", mode);
1641            throw new IllegalArgumentException();
1642        }
1643        return result;
1644    }
1645
1646    void setDelayModeBox(int mode, JComboBox<String> box) {
1647        String result = jmri.util.StringUtil.getNameFromState(mode, delayedStartInt, delayedStartString);
1648        box.setSelectedItem(result);
1649    }
1650
1651    /**
1652     * The following are for items that are only for automatic running of
1653     * ActiveTrains They are isolated here to simplify changing them in the
1654     * future.
1655     * <ul>
1656     * <li>initializeAutoRunItems - initializes the display of auto run items in
1657     * this window
1658     * <li>initializeAutoRunValues - initializes the values of auto run items
1659     * from values in a saved train info file hideAutoRunItems - hides all auto
1660     * run items in this window showAutoRunItems - shows all auto run items in
1661     * this window
1662     * <li>autoTrainInfoToDialog - gets auto run items from a train info, puts
1663     * values in items, and initializes auto run dialog items
1664     * <li>autoTrainItemsToTrainInfo - copies values of auto run items to train
1665     * info for saving to a file
1666     * <li>readAutoRunItems - reads and checks values of all auto run items.
1667     * returns true if OK, sends appropriate messages and returns false if not
1668     * OK
1669     * <li>setAutoRunItems - sets the user entered auto run items in the new
1670     * AutoActiveTrain
1671     * </ul>
1672     */
1673    // auto run items in ActivateTrainFrame
1674    private final JPanel pa1 = new JPanel();
1675    private final JLabel speedFactorLabel = new JLabel(Bundle.getMessage("SpeedFactorLabel"));
1676    private final JSpinner speedFactorSpinner = new JSpinner();
1677    private final JLabel minReliableOperatingSpeedLabel = new JLabel(Bundle.getMessage("MinReliableOperatingSpeedLabel"));
1678    private final JSpinner minReliableOperatingSpeedSpinner = new JSpinner();
1679    private final JLabel maxSpeedLabel = new JLabel(Bundle.getMessage("MaxSpeedLabel"));
1680    private final JSpinner maxSpeedSpinner = new JSpinner();
1681    private final JPanel pa2 = new JPanel();
1682    private final JLabel rampRateLabel = new JLabel(Bundle.getMessage("RampRateBoxLabel"));
1683    private final JComboBox<String> rampRateBox = new JComboBox<>();
1684    private final JPanel pa2a = new JPanel();
1685    private final JLabel useSpeedProfileLabel = new JLabel(Bundle.getMessage("UseSpeedProfileLabel"));
1686    private final JCheckBox useSpeedProfileCheckBox = new JCheckBox( );
1687    private final JLabel stopBySpeedProfileLabel = new JLabel(Bundle.getMessage("StopBySpeedProfileLabel"));
1688    private final JCheckBox stopBySpeedProfileCheckBox = new JCheckBox( );
1689    private final JLabel stopBySpeedProfileAdjustLabel = new JLabel(Bundle.getMessage("StopBySpeedProfileAdjustLabel"));
1690    private final JSpinner stopBySpeedProfileAdjustSpinner = new JSpinner();
1691    private final JPanel pa3 = new JPanel();
1692    private final JCheckBox soundDecoderBox = new JCheckBox(Bundle.getMessage("SoundDecoder"));
1693    private final JCheckBox runInReverseBox = new JCheckBox(Bundle.getMessage("RunInReverse"));
1694    private final JPanel pa4 = new JPanel();
1695    private final JLabel fNumberBellLabel = new JLabel(Bundle.getMessage("fnumberbelllabel"));
1696    private final JSpinner fNumberBellSpinner = new JSpinner();
1697    private final JLabel fNumberHornLabel = new JLabel(Bundle.getMessage("fnumberhornlabel"));
1698    private final JSpinner fNumberHornSpinner = new JSpinner();
1699    private final JLabel fNumberLightLabel = new JLabel(Bundle.getMessage("fnumberlightlabel"));
1700    private final JSpinner fNumberLightSpinner = new JSpinner();
1701    private final JPanel pa5_FNumbers = new JPanel();
1702    protected static class TrainDetectionJCombo extends JComboBox<TrainDetectionItem> {
1703        public void setSelectedItemByValue(TrainDetection trainDetVar) {
1704            for ( int ix = 0; ix < getItemCount() ; ix ++ ) {
1705                if (getItemAt(ix).value == trainDetVar) {
1706                    this.setSelectedIndex(ix);
1707                    break;
1708                }
1709            }
1710        }
1711    }
1712
1713    private final JLabel trainDetectionLabel = new JLabel(Bundle.getMessage("TrainDetection"));
1714    public final TrainDetectionJCombo trainDetectionComboBox = new TrainDetectionJCombo();
1715
1716    protected static class TrainLengthUnitsJCombo extends JComboBox<TrainLengthUnitsItem> {
1717        public void setSelectedItemByValue(TrainLengthUnits var) {
1718            for ( int ix = 0; ix < getItemCount() ; ix ++ ) {
1719                if (getItemAt(ix).value == var) {
1720                    this.setSelectedIndex(ix);
1721                    break;
1722                }
1723            }
1724        }
1725    }
1726
1727    public final TrainLengthUnitsJCombo trainLengthUnitsComboBox = new TrainLengthUnitsJCombo();
1728    private final JLabel trainLengthLabel = new JLabel(Bundle.getMessage("MaxTrainLengthLabel"));
1729    private JLabel trainLengthAltLengthLabel; // I18N Label
1730    private final JSpinner maxTrainLengthSpinner = new JSpinner(); // initialized later
1731
1732    private void initializeAutoRunItems() {
1733        initializeRampCombo();
1734        initializeScaleLengthBox();
1735        pa1.setLayout(new FlowLayout());
1736        pa1.add(speedFactorLabel);
1737        speedFactorSpinner.setModel(new SpinnerNumberModel(Float.valueOf(1.0f), Float.valueOf(0.1f), Float.valueOf(2.0f), Float.valueOf(0.01f)));
1738        speedFactorSpinner.setEditor(new JSpinner.NumberEditor(speedFactorSpinner, "# %"));
1739        pa1.add(speedFactorSpinner);
1740        speedFactorSpinner.setToolTipText(Bundle.getMessage("SpeedFactorHint"));
1741        pa1.add(new JLabel("   "));
1742        pa1.add(maxSpeedLabel);
1743        maxSpeedSpinner.setModel(new SpinnerNumberModel(Float.valueOf(1.0f), Float.valueOf(0.1f), Float.valueOf(1.0f), Float.valueOf(0.01f)));
1744        maxSpeedSpinner.setEditor(new JSpinner.NumberEditor(maxSpeedSpinner, "# %"));
1745        pa1.add(maxSpeedSpinner);
1746        maxSpeedSpinner.setToolTipText(Bundle.getMessage("MaxSpeedHint"));
1747        pa1.add(minReliableOperatingSpeedLabel);
1748        minReliableOperatingSpeedSpinner.setModel(new SpinnerNumberModel(Float.valueOf(0.0f), Float.valueOf(0.0f), Float.valueOf(1.0f), Float.valueOf(0.01f)));
1749        minReliableOperatingSpeedSpinner.setEditor(new JSpinner.NumberEditor(minReliableOperatingSpeedSpinner, "# %"));
1750        pa1.add(minReliableOperatingSpeedSpinner);
1751        minReliableOperatingSpeedSpinner.setToolTipText(Bundle.getMessage("MinReliableOperatingSpeedHint"));
1752        initiatePane.add(pa1);
1753        pa2.setLayout(new FlowLayout());
1754        pa2.add(rampRateLabel);
1755        pa2.add(rampRateBox);
1756        rampRateBox.setToolTipText(Bundle.getMessage("RampRateBoxHint"));
1757        pa2.add(useSpeedProfileLabel);
1758        pa2.add(useSpeedProfileCheckBox);
1759        useSpeedProfileCheckBox.setToolTipText(Bundle.getMessage("UseSpeedProfileHint"));
1760        initiatePane.add(pa2);
1761        pa2a.setLayout(new FlowLayout());
1762        pa2a.add(stopBySpeedProfileLabel);
1763        pa2a.add(stopBySpeedProfileCheckBox);
1764        stopBySpeedProfileCheckBox.setToolTipText(Bundle.getMessage("UseSpeedProfileHint")); // reuse identical hint for Stop
1765        pa2a.add(stopBySpeedProfileAdjustLabel);
1766        stopBySpeedProfileAdjustSpinner.setModel(new SpinnerNumberModel( Float.valueOf(1.0f), Float.valueOf(0.1f), Float.valueOf(5.0f), Float.valueOf(0.01f)));
1767        stopBySpeedProfileAdjustSpinner.setEditor(new JSpinner.NumberEditor(stopBySpeedProfileAdjustSpinner, "# %"));
1768        pa2a.add(stopBySpeedProfileAdjustSpinner);
1769        stopBySpeedProfileAdjustSpinner.setToolTipText(Bundle.getMessage("StopBySpeedProfileAdjustHint"));
1770        initiatePane.add(pa2a);
1771        pa3.setLayout(new FlowLayout());
1772        pa3.add(soundDecoderBox);
1773        soundDecoderBox.setToolTipText(Bundle.getMessage("SoundDecoderBoxHint"));
1774        pa3.add(new JLabel("   "));
1775        pa3.add(runInReverseBox);
1776        runInReverseBox.setToolTipText(Bundle.getMessage("RunInReverseBoxHint"));
1777        initiatePane.add(pa3);
1778        maxTrainLengthSpinner.setModel(new SpinnerNumberModel(Float.valueOf(18.0f), Float.valueOf(0.0f), Float.valueOf(10000.0f), Float.valueOf(0.5f)));
1779        maxTrainLengthSpinner.setEditor(new JSpinner.NumberEditor(maxTrainLengthSpinner, "###0.0"));
1780        maxTrainLengthSpinner.setToolTipText(Bundle.getMessage("MaxTrainLengthHint")); // won't be updated while Dispatcher is open
1781        maxTrainLengthSpinner.addChangeListener( e -> handlemaxTrainLengthChangeUnitsLength());
1782        trainLengthUnitsComboBox.addActionListener( e -> handlemaxTrainLengthChangeUnitsLength());
1783        trainLengthAltLengthLabel=new JLabel();
1784        pa4.setLayout(new FlowLayout());
1785        pa4.add(trainLengthLabel);
1786        pa4.add(maxTrainLengthSpinner);
1787        pa4.add(trainLengthUnitsComboBox);
1788        pa4.add(trainLengthAltLengthLabel);
1789        initiatePane.add(pa4);
1790        pa5_FNumbers.setBorder(BorderFactory.createTitledBorder(Bundle.getMessage("fnumbers")));
1791        pa5_FNumbers.setLayout(new FlowLayout());
1792        fNumberLightSpinner.setModel(new SpinnerNumberModel(0,0,100,1));
1793        fNumberLightSpinner.setToolTipText(Bundle.getMessage("fnumberlighthint"));
1794        pa5_FNumbers.add(fNumberLightLabel);
1795        pa5_FNumbers.add(fNumberLightSpinner);
1796        fNumberBellSpinner.setModel(new SpinnerNumberModel(0,0,100,1));
1797        fNumberBellSpinner.setToolTipText(Bundle.getMessage("fnumberbellhint"));
1798        pa5_FNumbers.add(fNumberBellLabel);
1799        pa5_FNumbers.add(fNumberBellSpinner);
1800        fNumberHornSpinner.setModel(new SpinnerNumberModel(0,0,100,1));
1801        fNumberHornSpinner.setToolTipText(Bundle.getMessage("fnumberhornhint"));
1802        pa5_FNumbers.add(fNumberHornLabel);
1803        pa5_FNumbers.add(fNumberHornSpinner);
1804        initiatePane.add(pa5_FNumbers);
1805        showHideAutoRunItems(autoRunBox.isSelected());   // initialize with auto run items hidden
1806    }
1807
1808    private void handlemaxTrainLengthChangeUnitsLength() {
1809        trainLengthAltLengthLabel.setText(maxTrainLengthCalculateAltFormatted(
1810                ((TrainLengthUnitsItem) trainLengthUnitsComboBox.getSelectedItem()).getValue(),
1811                (float) maxTrainLengthSpinner.getValue()));
1812    }
1813
1814    /**
1815     * Get an I18N String of the max TrainLength.
1816     * @param fromUnits the Length Unit.
1817     * @param fromValue the length.
1818     * @return String format of the length.
1819     */
1820    private String maxTrainLengthCalculateAltFormatted(TrainLengthUnits fromUnits, float fromValue) {
1821        float value = maxTrainLengthCalculateAlt(fromUnits, fromValue);
1822        switch (fromUnits) {
1823            case TRAINLENGTH_ACTUALINCHS:
1824                return String.format(Locale.getDefault(), "%.2f %s",
1825                    value, Bundle.getMessage("TrainLengthInScaleFeet"));
1826            case TRAINLENGTH_ACTUALCM:
1827                return String.format(Locale.getDefault(), "%.1f %s",
1828                    value, Bundle.getMessage("TrainLengthInScaleMeters"));
1829            case TRAINLENGTH_SCALEFEET:
1830                return String.format(Locale.getDefault(), "%.1f %s",
1831                    value, Bundle.getMessage("TrainLengthInActualInchs"));
1832            case TRAINLENGTH_SCALEMETERS:
1833                return String.format(Locale.getDefault(), "%.0f %s",
1834                    value, Bundle.getMessage("TrainLengthInActualcm"));
1835            default:
1836                log.error("Invalid TrainLengthUnits must have been updated, fix maxTrainLengthCalculateAltFormatted");
1837        }
1838        return "";
1839    }
1840
1841    private float maxTrainLengthToScaleMeters(TrainLengthUnits fromUnits, float fromValue) {
1842        float value;
1843        // convert to meters.
1844        switch (fromUnits) {
1845            case TRAINLENGTH_ACTUALINCHS:
1846                value = fromValue / 12.0f * (float) _dispatcher.getScale().getScaleRatio();
1847                value = value / 3.28084f;
1848                break;
1849            case TRAINLENGTH_ACTUALCM:
1850                value = fromValue / 100.0f * (float) _dispatcher.getScale().getScaleRatio();
1851                break;
1852           case TRAINLENGTH_SCALEFEET:
1853               value = fromValue / 3.28084f;
1854               break;
1855           case TRAINLENGTH_SCALEMETERS:
1856               value = fromValue;
1857               break;
1858           default:
1859               value = 0;
1860               log.error("Invalid TrainLengthUnits has been updated, fix me");
1861        }
1862        return value;
1863    }
1864
1865    /*
1866     * Calculates the reciprocal unit. Actual to Scale and vice versa
1867     */
1868    private float maxTrainLengthCalculateAlt(TrainLengthUnits fromUnits, float fromValue) {
1869        switch (fromUnits) {
1870            case TRAINLENGTH_ACTUALINCHS:
1871                // calc scale feet
1872                return (float) jmri.util.MathUtil.granulize(fromValue / 12 * (float) _dispatcher.getScale().getScaleRatio(),0.1f);
1873            case TRAINLENGTH_ACTUALCM:
1874                // calc scale meter
1875                return fromValue / 100 * (float) _dispatcher.getScale().getScaleRatio();
1876            case TRAINLENGTH_SCALEFEET:
1877                // calc actual inchs
1878                return fromValue * 12 * (float) _dispatcher.getScale().getScaleFactor();
1879           case TRAINLENGTH_SCALEMETERS:
1880                // calc actual cm.
1881                return fromValue * 100 * (float) _dispatcher.getScale().getScaleFactor();
1882           default:
1883               log.error("Invalid TrainLengthUnits has been updated, fix me");
1884        }
1885        return 0;
1886    }
1887
1888    private void showHideAutoRunItems(boolean value) {
1889        pa1.setVisible(value);
1890        pa2.setVisible(value);
1891        pa2a.setVisible(value);
1892        pa3.setVisible(value);
1893        pa4.setVisible(value);
1894        pa5_FNumbers.setVisible(value);
1895    }
1896
1897    private void autoTrainInfoToDialog(TrainInfo info) {
1898        speedFactorSpinner.setValue(info.getSpeedFactor());
1899        maxSpeedSpinner.setValue(info.getMaxSpeed());
1900        minReliableOperatingSpeedSpinner.setValue(info.getMinReliableOperatingSpeed());
1901        setComboBox(rampRateBox, info.getRampRate());
1902        trainDetectionComboBox.setSelectedItemByValue(info.getTrainDetection());
1903        runInReverseBox.setSelected(info.getRunInReverse());
1904        soundDecoderBox.setSelected(info.getSoundDecoder());
1905        trainLengthUnitsComboBox.setSelectedItemByValue(info.getTrainLengthUnits());
1906        switch (info.getTrainLengthUnits()) {
1907            case TRAINLENGTH_SCALEFEET:
1908                maxTrainLengthSpinner.setValue(info.getMaxTrainLengthScaleFeet());
1909                break;
1910            case TRAINLENGTH_SCALEMETERS:
1911                maxTrainLengthSpinner.setValue(info.getMaxTrainLengthScaleMeters());
1912                break;
1913            case TRAINLENGTH_ACTUALINCHS:
1914                maxTrainLengthSpinner.setValue(info.getMaxTrainLengthScaleFeet() * 12.0f * (float)_dispatcher.getScale().getScaleFactor());
1915                break;
1916            case TRAINLENGTH_ACTUALCM:
1917                maxTrainLengthSpinner.setValue(info.getMaxTrainLengthScaleMeters() * 100.0f * (float)_dispatcher.getScale().getScaleFactor());
1918                break;
1919            default:
1920                maxTrainLengthSpinner.setValue(0.0f);
1921        }
1922        useSpeedProfileCheckBox.setSelected(info.getUseSpeedProfile());
1923        stopBySpeedProfileCheckBox.setSelected(info.getStopBySpeedProfile());
1924        stopBySpeedProfileAdjustSpinner.setValue(info.getStopBySpeedProfileAdjust());
1925        fNumberLightSpinner.setValue(info.getFNumberLight());
1926        fNumberBellSpinner.setValue(info.getFNumberBell());
1927        fNumberHornSpinner.setValue(info.getFNumberHorn());
1928         showHideAutoRunItems(autoRunBox.isSelected());
1929        initiateFrame.pack();
1930    }
1931
1932    private void autoRunItemsToTrainInfo(TrainInfo info) {
1933        info.setSpeedFactor((float) speedFactorSpinner.getValue());
1934        info.setMaxSpeed((float) maxSpeedSpinner.getValue());
1935        info.setMinReliableOperatingSpeed((float) minReliableOperatingSpeedSpinner.getValue());
1936        info.setRampRate((String) rampRateBox.getSelectedItem());
1937        info.setRunInReverse(runInReverseBox.isSelected());
1938        info.setSoundDecoder(soundDecoderBox.isSelected());
1939        info.setTrainLengthUnits(((TrainLengthUnitsItem) trainLengthUnitsComboBox.getSelectedItem()).getValue());
1940        info.setMaxTrainLengthScaleMeters(maxTrainLengthToScaleMeters( info.getTrainLengthUnits(), (float) maxTrainLengthSpinner.getValue()));
1941
1942        // Only use speed profile values if enabled
1943        if (useSpeedProfileCheckBox.isEnabled()) {
1944            info.setUseSpeedProfile(useSpeedProfileCheckBox.isSelected());
1945            info.setStopBySpeedProfile(stopBySpeedProfileCheckBox.isSelected());
1946            info.setStopBySpeedProfileAdjust((float) stopBySpeedProfileAdjustSpinner.getValue());
1947        } else {
1948            info.setUseSpeedProfile(false);
1949            info.setStopBySpeedProfile(false);
1950            info.setStopBySpeedProfileAdjust(1.0f);
1951        }
1952        info.setFNumberLight((int)fNumberLightSpinner.getValue());
1953        info.setFNumberBell((int)fNumberBellSpinner.getValue());
1954        info.setFNumberHorn((int)fNumberHornSpinner.getValue());
1955    }
1956
1957   private void initializeRampCombo() {
1958        rampRateBox.removeAllItems();
1959        rampRateBox.addItem(Bundle.getMessage("RAMP_NONE"));
1960        rampRateBox.addItem(Bundle.getMessage("RAMP_FAST"));
1961        rampRateBox.addItem(Bundle.getMessage("RAMP_MEDIUM"));
1962        rampRateBox.addItem(Bundle.getMessage("RAMP_MED_SLOW"));
1963        rampRateBox.addItem(Bundle.getMessage("RAMP_SLOW"));
1964        rampRateBox.addItem(Bundle.getMessage("RAMP_SPEEDPROFILE"));
1965        // Note: the order above must correspond to the numbers in AutoActiveTrain.java
1966    }
1967
1968    /**
1969     * Sets up the RadioButtons and visability of spinner for the allocation method
1970     *
1971     * @param value 0, Allocate by Safe spots, -1, allocate as far as possible Any
1972     *            other value the number of sections to allocate
1973     */
1974    private void setAllocateMethodButtons(int value) {
1975        switch (value) {
1976            case ActiveTrain.ALLOCATE_BY_SAFE_SECTIONS:
1977                allocateBySafeRadioButton.setSelected(true);
1978                allocateCustomSpinner.setVisible(false);
1979                break;
1980            case ActiveTrain.ALLOCATE_AS_FAR_AS_IT_CAN:
1981                allocateAllTheWayRadioButton.setSelected(true);
1982                allocateCustomSpinner.setVisible(false);
1983                break;
1984            default:
1985                allocateNumberOfBlocks.setSelected(true);
1986                allocateCustomSpinner.setVisible(true);
1987                allocateCustomSpinner.setValue(value);
1988        }
1989    }
1990
1991    /*
1992     * Layout block stuff
1993     */
1994    private ArrayList<LayoutBlock> getOccupiedBlockList() {
1995        LayoutBlockManager lBM = InstanceManager.getDefault(LayoutBlockManager.class);
1996        ArrayList<LayoutBlock> lBlocks = new ArrayList<>();
1997        for (LayoutBlock lB : lBM.getNamedBeanSet()) {
1998            if (lB.getBlock().getState() == Block.OCCUPIED) {
1999                lBlocks.add(lB);
2000            }
2001        }
2002        return lBlocks;
2003    }
2004
2005    private void initializeStartingBlockComboDynamic() {
2006        startingBlockBox.removeAllItems();
2007        startingBlockBoxList.clear();
2008        for (LayoutBlock lB: getOccupiedBlockList()) {
2009            if (!startingBlockBoxList.contains(lB.getBlock())) {
2010                startingBlockBoxList.add(lB.getBlock());
2011                startingBlockBox.addItem(getBlockName(lB.getBlock()));
2012            }
2013        }
2014        JComboBoxUtil.setupComboBoxMaxRows(startingBlockBox);
2015    }
2016
2017    private void initializeViaBlockDynamicCombo() {
2018        String prevValue = (String) viaBlockBox.getSelectedItem();
2019        viaBlockBox.removeActionListener(viaBlockBoxListener);
2020        viaBlockBox.removeAllItems();
2021        viaBlockBoxList.clear();
2022        LayoutBlockManager lBM = InstanceManager.getDefault(LayoutBlockManager.class);
2023        if (startingBlockBox.getSelectedItem() != null) {
2024            LayoutBlock lBSrc;
2025            if (startingBlockBox.getSelectedIndex() >= 0) {
2026                lBSrc = lBM.getByUserName((String) startingBlockBox.getSelectedItem());
2027                if (lBSrc != null) {
2028                    int rX = lBSrc.getNumberOfNeighbours() - 1;
2029                    for (; rX > -1; rX--) {
2030                        viaBlockBox.addItem(lBSrc.getNeighbourAtIndex(rX).getDisplayName());
2031                        viaBlockBoxList.add(lBSrc.getNeighbourAtIndex(rX));
2032                    }
2033                }
2034            }
2035        }
2036        if (prevValue != null) {
2037            viaBlockBox.setSelectedItem(prevValue);
2038        }
2039        viaBlockBox.addActionListener(viaBlockBoxListener);
2040    }
2041
2042    private void initializeDestinationBlockDynamicCombo() {
2043        destinationBlockBox.removeAllItems();
2044        destinationBlockBoxList.clear();
2045        LayoutBlockManager lBM = InstanceManager.getDefault(LayoutBlockManager.class);
2046        if (startingBlockBox.getSelectedItem() != null) {
2047            LayoutBlock lBSrc;
2048            if (startingBlockBox.getSelectedIndex() >= 0
2049                    && viaBlockBox.getSelectedIndex() >= 0) {
2050                lBSrc = lBM.getByUserName((String) startingBlockBox.getSelectedItem());
2051                Block b = viaBlockBoxList.get(viaBlockBox.getSelectedIndex());
2052                if (lBSrc != null) {
2053                    int rX = lBSrc.getNumberOfRoutes() - 1;
2054                    for (; rX > -1; rX--) {
2055                        if (lBSrc.getRouteNextBlockAtIndex(rX) == b) {
2056                            destinationBlockBox.addItem(lBSrc.getRouteDestBlockAtIndex(rX).getDisplayName());
2057                            destinationBlockBoxList.add(lBSrc.getRouteDestBlockAtIndex(rX));
2058                        }
2059                    }
2060                }
2061            }
2062        }
2063    }
2064
2065    /*
2066     * Check Advanced routing
2067    */
2068    private boolean checkAdvancedRouting() {
2069        if (!InstanceManager.getDefault(LayoutBlockManager.class).isAdvancedRoutingEnabled()) {
2070            int response = JmriJOptionPane.showConfirmDialog(this, Bundle.getMessage("AdHocNeedsEnableBlockRouting"),
2071                    Bundle.getMessage("AdHocNeedsBlockRouting"), JmriJOptionPane.YES_NO_OPTION);
2072            if (response == 0) {
2073                InstanceManager.getDefault(LayoutBlockManager.class).enableAdvancedRouting(true);
2074                JmriJOptionPane.showMessageDialog(this, Bundle.getMessage("AdhocNeedsBlockRoutingEnabled"));
2075            } else {
2076                return false;
2077            }
2078        }
2079        return true;
2080    }
2081
2082    /*
2083     * ComboBox item.
2084     */
2085    protected static class TrainDetectionItem {
2086
2087        private final String key;
2088        private TrainDetection value;
2089
2090        public TrainDetectionItem(String text, TrainDetection trainDetection ) {
2091            this.key = text;
2092            this.value = trainDetection;
2093        }
2094
2095        @Override
2096        public String toString() {
2097            return key;
2098        }
2099
2100        public String getKey() {
2101            return key;
2102        }
2103
2104        public TrainDetection getValue() {
2105            return value;
2106        }
2107    }
2108
2109    /*
2110     * ComboBox item.
2111     */
2112    protected static class TrainLengthUnitsItem {
2113
2114        private final String key;
2115        private TrainLengthUnits value;
2116
2117        public TrainLengthUnitsItem(String text, TrainLengthUnits trainLength ) {
2118            this.key = text;
2119            this.value = trainLength;
2120        }
2121
2122        @Override
2123        public String toString() {
2124            return key;
2125        }
2126
2127        public String getKey() {
2128            return key;
2129        }
2130
2131        public TrainLengthUnits getValue() {
2132            return value;
2133        }
2134    }
2135
2136    private static final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(ActivateTrainFrame.class);
2137
2138}