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 dialog and processes information entered
058 * there.
059 * <p>
060 * This module works with Dispatcher, which initiates the display of the dialog.
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<>(jmri.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<>(jmri.InstanceManager.sensorManagerInstance());
163    private final NamedBeanComboBox<Sensor> delayReStartSensor = new NamedBeanComboBox<>(jmri.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    private void setTrainsFromOptions(TrainsFrom transFrom) {
636        switch (transFrom) {
637            case TRAINSFROMROSTER:
638                initializeFreeRosterEntriesCombo();
639                rosterComboBox.setVisible(true);
640                trainSelectBox.setVisible(false);
641                trainFieldLabel.setVisible(true);
642                trainNameField.setVisible(true);
643                dccAddressFieldLabel.setVisible(false);
644                dccAddressSpinner.setVisible(false);
645                break;
646            case TRAINSFROMOPS:
647                initializeFreeTrainsCombo();
648                trainSelectBox.setVisible(true);
649                rosterComboBox.setVisible(false);
650                trainFieldLabel.setVisible(true);
651                trainNameField.setVisible(true);
652                dccAddressFieldLabel.setVisible(true);
653                dccAddressSpinner.setVisible(true);
654                setSpeedProfileOptions(trainInfo,false);
655                break;
656            case TRAINSFROMUSER:
657                trainNameField.setText("");
658                trainSelectBox.setVisible(false);
659                rosterComboBox.setVisible(false);
660                trainFieldLabel.setVisible(true);
661                trainNameField.setVisible(true);
662                dccAddressFieldLabel.setVisible(true);
663                dccAddressSpinner.setVisible(true);
664                dccAddressSpinner.setEnabled(true);
665                setSpeedProfileOptions(trainInfo,false);
666                break;
667            case TRAINSFROMSETLATER:
668            default:
669                rosterComboBox.setVisible(false);
670                trainSelectBox.setVisible(false);
671                trainFieldLabel.setVisible(true);
672                trainNameField.setVisible(true);
673                dccAddressFieldLabel.setVisible(false);
674                dccAddressSpinner.setVisible(false);
675        }
676    }
677
678    private void initializeTrainTypeBox() {
679        trainTypeBox.removeAllItems();
680        trainTypeBox.addItem("<" + Bundle.getMessage("None").toLowerCase() + ">"); // <none>
681        trainTypeBox.addItem(Bundle.getMessage("LOCAL_PASSENGER"));
682        trainTypeBox.addItem(Bundle.getMessage("LOCAL_FREIGHT"));
683        trainTypeBox.addItem(Bundle.getMessage("THROUGH_PASSENGER"));
684        trainTypeBox.addItem(Bundle.getMessage("THROUGH_FREIGHT"));
685        trainTypeBox.addItem(Bundle.getMessage("EXPRESS_PASSENGER"));
686        trainTypeBox.addItem(Bundle.getMessage("EXPRESS_FREIGHT"));
687        trainTypeBox.addItem(Bundle.getMessage("MOW"));
688        // NOTE: The above must correspond in order and name to definitions in ActiveTrain.java.
689    }
690
691    private void initializeTrainDetectionBox() {
692        trainDetectionComboBox.addItem(new TrainDetectionItem(Bundle.getMessage("TrainDetectionWholeTrain"),TrainDetection.TRAINDETECTION_WHOLETRAIN));
693        trainDetectionComboBox.addItem(new TrainDetectionItem(Bundle.getMessage("TrainDetectionHeadAndTail"),TrainDetection.TRAINDETECTION_HEADANDTAIL));
694        trainDetectionComboBox.addItem(new TrainDetectionItem(Bundle.getMessage("TrainDetectionHeadOnly"),TrainDetection.TRAINDETECTION_HEADONLY));
695    }
696
697    private void initializeScaleLengthBox() {
698        trainLengthUnitsComboBox.addItem(new TrainLengthUnitsItem(Bundle.getMessage("TrainLengthInScaleFeet"), TrainLengthUnits.TRAINLENGTH_SCALEFEET));
699        trainLengthUnitsComboBox.addItem(new TrainLengthUnitsItem(Bundle.getMessage("TrainLengthInScaleMeters"), TrainLengthUnits.TRAINLENGTH_SCALEMETERS));
700        trainLengthUnitsComboBox.addItem(new TrainLengthUnitsItem(Bundle.getMessage("TrainLengthInActualInchs"), TrainLengthUnits.TRAINLENGTH_ACTUALINCHS));
701        trainLengthUnitsComboBox.addItem(new TrainLengthUnitsItem(Bundle.getMessage("TrainLengthInActualcm"), TrainLengthUnits.TRAINLENGTH_ACTUALCM));
702    }
703
704    private void handleTransitSelectionChanged(ActionEvent e) {
705        int index = transitSelectBox.getSelectedIndex();
706        if (index < 0) {
707            return;
708        }
709        Transit t = transitSelectBox.getSelectedItem();
710        if ((t != null) && (t != selectedTransit)) {
711            selectedTransit = t;
712            initializeStartingBlockCombo();
713            initializeDestinationBlockCombo();
714            initiateFrame.pack();
715        }
716    }
717
718    private void handleInTransitClick() {
719        if (!inTransitBox.isSelected() && selectedTransit.getEntryBlocksList().isEmpty()) {
720            JmriJOptionPane.showMessageDialog(initiateFrame, Bundle
721                    .getMessage("NoEntryBlocks"), Bundle.getMessage("MessageTitle"),
722                    JmriJOptionPane.INFORMATION_MESSAGE);
723            inTransitBox.setSelected(true);
724        }
725        initializeStartingBlockCombo();
726        initializeDestinationBlockCombo();
727        initiateFrame.pack();
728    }
729
730      private void handleTrainSelectionChanged() {
731        if (!trainsFromButtonGroup.getSelection().getActionCommand().equals("TRAINSFROMOPS")) {
732            return;
733        }
734        int ix = trainSelectBox.getSelectedIndex();
735        if (ix < 1) { // no train selected
736            dccAddressSpinner.setEnabled(false);
737            return;
738        }
739        dccAddressSpinner.setEnabled(true);
740        int dccAddress;
741        try {
742            dccAddress = Integer.parseInt((((Train) trainSelectBox.getSelectedItem()).getLeadEngineDccAddress()));
743        } catch (NumberFormatException ex) {
744            JmriJOptionPane.showMessageDialog(initiateFrame, Bundle.getMessage("Error43"),
745                    Bundle.getMessage("ErrorTitle"), JmriJOptionPane.ERROR_MESSAGE);
746            return;
747        }
748        dccAddressSpinner.setValue (dccAddress);
749        trainNameField.setText(((Train) trainSelectBox.getSelectedItem()).getName());
750    }
751
752    private void handleRosterSelectionChanged(ActionEvent e) {
753        if (!trainsFromButtonGroup.getSelection().getActionCommand().equals("TRAINSFROMROSTER")) {
754            return;
755        }
756        int ix = rosterComboBox.getSelectedIndex();
757        if (ix > 0) { // first item is "Select Loco" string
758            RosterEntry r = (RosterEntry) rosterComboBox.getItemAt(ix);
759            // check to see if speed profile exists and is not empty
760            if (r.getSpeedProfile() == null || r.getSpeedProfile().getProfileSize() < 1) {
761                // disable profile boxes etc.
762                setSpeedProfileOptions(trainInfo,false);
763            } else {
764                // enable profile boxes
765                setSpeedProfileOptions(trainInfo,true);
766            }
767            maxSpeedSpinner.setValue(r.getMaxSpeedPCT()/100.0f);
768            trainNameField.setText(r.titleString());
769            if (r.getAttribute("DispatcherTrainType") != null && !r.getAttribute("DispatcherTrainType").equals("")) {
770                trainTypeBox.setSelectedItem(r.getAttribute("DispatcherTrainType"));
771            }
772        } else {
773            setSpeedProfileOptions(trainInfo,false);
774        }
775    }
776
777    private void handleDelayStartClick(ActionEvent e) {
778        departureHrSpinner.setVisible(false);
779        departureMinSpinner.setVisible(false);
780        departureTimeLabel.setVisible(false);
781        departureSepLabel.setVisible(false);
782        delaySensor.setVisible(false);
783        resetStartSensorBox.setVisible(false);
784        if (delayedStartBox.getSelectedItem().equals(Bundle.getMessage("DelayedStartTimed"))) {
785            departureHrSpinner.setVisible(true);
786            departureMinSpinner.setVisible(true);
787            departureTimeLabel.setVisible(true);
788            departureSepLabel.setVisible(true);
789        } else if (delayedStartBox.getSelectedItem().equals(Bundle.getMessage("DelayedStartSensor"))) {
790            delaySensor.setVisible(true);
791            resetStartSensorBox.setVisible(true);
792        }
793        initiateFrame.pack(); // to fit extra hh:mm in window
794    }
795
796    private void handleResetWhenDoneClick() {
797        delayMinSpinner.setVisible(false);
798        delayMinLabel.setVisible(false);
799        delayedReStartLabel.setVisible(false);
800        delayedReStartBox.setVisible(false);
801        delayReStartSensorLabel.setVisible(false);
802        delayReStartSensor.setVisible(false);
803        resetRestartSensorBox.setVisible(false);
804        if (resetWhenDoneBox.isSelected()) {
805            delayedReStartLabel.setVisible(true);
806            delayedReStartBox.setVisible(true);
807            terminateWhenDoneBox.setSelected(false);
808            if (delayedReStartBox.getSelectedItem().equals(Bundle.getMessage("DelayedStartTimed"))) {
809                delayMinSpinner.setVisible(true);
810                delayMinLabel.setVisible(true);
811            } else if (delayedReStartBox.getSelectedItem().equals(Bundle.getMessage("DelayedStartSensor"))) {
812                delayReStartSensor.setVisible(true);
813                delayReStartSensorLabel.setVisible(true);
814                resetRestartSensorBox.setVisible(true);
815            }
816        } else {
817            terminateWhenDoneBox.setEnabled(true);
818        }
819        initiateFrame.pack();
820    }
821
822    private void handleTerminateWhenDoneBoxClick() {
823        if (terminateWhenDoneBox.isSelected()) {
824            refreshNextTrainCombo();
825            resetWhenDoneBox.setSelected(false);
826            terminateWhenDoneDetails.setVisible(true);
827        } else {
828            terminateWhenDoneDetails.setVisible(false);
829        }
830    }
831
832    private void handleReverseAtEndBoxClick() {
833        delayReverseMinSpinner.setVisible(false);
834        delayReverseMinLabel.setVisible(false);
835        delayReverseReStartLabel.setVisible(false);
836        reverseDelayedRestartType.setVisible(false);
837        delayReverseReStartSensorLabel.setVisible(false);
838        delayReverseReStartSensor.setVisible(false);
839        delayReverseResetSensorBox.setVisible(false);
840        if (reverseAtEndBox.isSelected()) {
841            delayReverseReStartLabel.setVisible(true);
842            reverseDelayedRestartType.setVisible(true);
843            if (reverseDelayedRestartType.getSelectedItem().equals(Bundle.getMessage("DelayedStartTimed"))) {
844                delayReverseMinSpinner.setVisible(true);
845                delayReverseMinLabel.setVisible(true);
846            } else if (reverseDelayedRestartType.getSelectedItem().equals(Bundle.getMessage("DelayedStartSensor"))) {
847                delayReverseReStartSensor.setVisible(true);
848                delayReStartSensorLabel.setVisible(true);
849                delayReverseResetSensorBox.setVisible(true);
850            }
851        }
852        initiateFrame.pack();
853
854        if (resetWhenDoneBox.isSelected()) {
855            terminateWhenDoneBox.setSelected(false);
856            terminateWhenDoneBox.setEnabled(false);
857        } else {
858            terminateWhenDoneBox.setEnabled(true);
859        }
860    }
861
862    private void handleAutoRunClick() {
863        if (autoRunBox.isSelected()) {
864            showAutoRunItems();
865        } else {
866            hideAutoRunItems();
867        }
868        initiateFrame.pack();
869    }
870
871    private void handleStartingBlockSelectionChanged() {
872        if (radioTransitsAdHoc.isSelected() ) {
873            initializeViaBlockDynamicCombo();
874            initializeDestinationBlockDynamicCombo();
875        } else {
876            initializeDestinationBlockCombo();
877        }
878        initiateFrame.pack();
879    }
880
881    private void handleViaBlockSelectionChanged() {
882        if (radioTransitsAdHoc.isSelected() ) {
883            initializeDestinationBlockDynamicCombo();
884        } else {
885            initializeDestinationBlockCombo();
886        }
887        initiateFrame.pack();
888    }
889
890    private void handleAllocateAllTheWayButtonChanged() {
891        allocateCustomSpinner.setVisible(false);
892    }
893
894    private void handleAllocateBySafeButtonChanged() {
895        allocateCustomSpinner.setVisible(false);
896    }
897
898    private void handleAllocateNumberOfBlocksButtonChanged() {
899        allocateCustomSpinner.setVisible(true);
900    }
901
902    private void cancelInitiateTrain() {
903        _dispatcher.newTrainDone(null);
904    }
905
906    /*
907     * Handles press of "Add New Train" button.
908     * Move data to TrainInfo validating basic information
909     * Call dispatcher to start the train from traininfo which
910     * completes validation.
911     */
912    private void addNewTrain() {
913        try {
914            validateDialog();
915            trainInfo = new TrainInfo();
916            dialogToTrainInfo(trainInfo);
917            if (radioTransitsAdHoc.isSelected()) {
918                int ixStart, ixEnd, ixVia;
919                ixStart = startingBlockBox.getSelectedIndex();
920                ixEnd = destinationBlockBox.getSelectedIndex();
921                ixVia = viaBlockBox.getSelectedIndex();
922                // search for a transit if ones available.
923                Transit tmpTransit = null;
924                int routeCount = 9999;
925                int startBlockSeq = 0;
926                int endBlockSeq = 0;
927                log.debug("Start[{}]Via[{}]Dest[{}}]",
928                        startingBlockBoxList.get(ixStart).getDisplayName(),
929                        viaBlockBoxList.get(ixVia).getDisplayName(),
930                        destinationBlockBoxList.get(ixEnd).getDisplayName());
931                for (Transit tr : InstanceManager.getDefault(jmri.TransitManager.class)
932                        .getListUsingBlock(startingBlockBoxList.get(ixStart))) {
933                    if (tr.getState() == Transit.IDLE
934                            && tr.containsBlock(startingBlockBoxList.get(ixStart))
935                            && tr.containsBlock(viaBlockBoxList.get(ixVia)) &&
936                            tr.containsBlock(destinationBlockBoxList.get(ixEnd))) {
937                        log.debug("[{}]  contains all blocks", tr.getDisplayName());
938                        int ixCountStart = -1, ixCountVia = -1, ixCountDest = -1, ixCount = 0;
939                        List<Block> transitBlocks = tr.getInternalBlocksList();
940                        List<Integer> transitBlockSeq = tr.getBlockSeqList();
941                        for (Block blk : transitBlocks) {
942                            log.debug("Checking Block[{}] t[{}] BlockSequ[{}]",
943                                    blk.getDisplayName(),
944                                    ixCount,
945                                    transitBlockSeq.get(ixCount));
946                            if (ixCountStart == -1 && blk == startingBlockBoxList.get(ixStart)) {
947                                log.trace("ixOne[{}]block[{}]",ixCount,blk.getDisplayName());
948                                ixCountStart = ixCount;
949                            } else if (ixCountStart != -1 && ixCountVia == -1 && blk == viaBlockBoxList.get(ixVia)) {
950                                log.trace("ixTwo[{}]block[{}]",ixCount,blk.getDisplayName());
951                                if (ixCount != ixCountStart + 1) {
952                                    log.debug("AdHoc {}:via and start not ajacent",tr.getDisplayName());
953                                    break;
954                                }
955                                ixCountVia = ixCount;
956                            } else if (ixCountStart != -1 && ixCountVia != -1 && ixCountDest == -1 && blk == destinationBlockBoxList.get(ixEnd)) {
957                                ixCountDest = ixCount;
958                                log.trace("ixThree[{}]block[{}]",ixCountDest,blk.getDisplayName());
959                                break;
960                            }
961                            ixCount++;
962                        }
963                        if (ixCountVia == (ixCountStart + 1) && ixCountDest > ixCountStart) {
964                            log.debug("Canuse [{}", tr.getDisplayName());
965                            Integer routeBlockLength =
966                                    transitBlockSeq.get(ixCountDest) - transitBlockSeq.get(ixCountStart);
967                            if (routeBlockLength < routeCount) {
968                                routeCount = ixCountDest - ixCountStart;
969                                tmpTransit = tr;
970                                startBlockSeq = transitBlockSeq.get(ixCountStart).intValue();
971                                endBlockSeq = transitBlockSeq.get(ixCountDest).intValue();
972                            }
973                        }
974                    }
975                }
976                if (tmpTransit != null &&
977                        (JmriJOptionPane.showConfirmDialog(this, Bundle.getMessage("Question6",tmpTransit.getDisplayName()),
978                                "Question",
979                                JmriJOptionPane.YES_NO_OPTION,
980                                JmriJOptionPane.QUESTION_MESSAGE) == JmriJOptionPane.YES_OPTION)) {
981                    // use transit found
982                    trainInfo.setDynamicTransit(false);
983                    trainInfo.setTransitName(tmpTransit.getDisplayName());
984                    trainInfo.setTransitId(tmpTransit.getDisplayName());
985                    trainInfo.setStartBlockSeq(startBlockSeq);
986                    trainInfo.setStartBlockName(getBlockName(startingBlockBoxList.get(ixStart)) + "-" + startBlockSeq);
987                    trainInfo.setDestinationBlockSeq(endBlockSeq);
988                    trainInfo.setDestinationBlockName(getBlockName(destinationBlockBoxList.get(ixEnd)) + "-" + endBlockSeq);
989                    trainInfoToDialog(trainInfo);
990                } else {
991                    // use a true ad-hoc
992                    List<LayoutBlock> blockList = _dispatcher.getAdHocRoute(startingBlockBoxList.get(ixStart),
993                            destinationBlockBoxList.get(ixEnd),
994                            viaBlockBoxList.get(ixVia));
995                    if (blockList == null) {
996                        JmriJOptionPane.showMessageDialog(initiateFrame, Bundle.getMessage("Error51"),
997                                Bundle.getMessage("ErrorTitle"), JmriJOptionPane.ERROR_MESSAGE);
998                        return;
999                    }
1000                }
1001            }
1002            _dispatcher.loadTrainFromTrainInfoThrowsException(trainInfo,"NONE","");
1003        } catch (IllegalArgumentException ex) {
1004            JmriJOptionPane.showMessageDialog(initiateFrame, ex.getMessage(),
1005                    Bundle.getMessage("ErrorTitle"), JmriJOptionPane.ERROR_MESSAGE);
1006        }
1007    }
1008
1009    private void initializeFreeTransitsCombo(List<Transit> transitList) {
1010        Set<Transit> excludeTransits = new HashSet<>();
1011        for (Transit t : _TransitManager.getNamedBeanSet()) {
1012            if (t.getState() != Transit.IDLE) {
1013                excludeTransits.add(t);
1014            }
1015        }
1016        transitSelectBox.setExcludedItems(excludeTransits);
1017        JComboBoxUtil.setupComboBoxMaxRows(transitSelectBox);
1018
1019        if (transitSelectBox.getItemCount() > 0) {
1020            transitSelectBox.setSelectedIndex(0);
1021            selectedTransit = transitSelectBox.getItemAt(0);
1022        } else {
1023            selectedTransit = null;
1024        }
1025    }
1026
1027    private void initializeFreeRosterEntriesCombo() {
1028        rosterComboBox.update();
1029        // remove used entries
1030        for (int ix = rosterComboBox.getItemCount() - 1; ix > 1; ix--) {  // remove from back first item is the "select loco" message
1031            if ( !_dispatcher.isAddressFree( ((RosterEntry)rosterComboBox.getItemAt(ix)).getDccLocoAddress().getNumber() ) ) {
1032                rosterComboBox.removeItemAt(ix);
1033            }
1034        }
1035    }
1036
1037    private void initializeFreeTrainsCombo() {
1038        Train prevValue = null;
1039        if (trainSelectBox.getSelectedIndex() > 0) {
1040            // item zero is a string
1041            prevValue = (Train)trainSelectBox.getSelectedItem();
1042        }
1043        ActionListener[] als = trainSelectBox.getActionListeners();
1044        for ( ActionListener al: als) {
1045            trainSelectBox.removeActionListener(al);
1046        }
1047        trainSelectBox.removeAllItems();
1048        trainSelectBox.addItem("Select Train");
1049        // initialize free trains from operations
1050        List<Train> trains = jmri.InstanceManager.getDefault(TrainManager.class).getTrainsByNameList();
1051        if (trains.size() > 0) {
1052            for (int i = 0; i < trains.size(); i++) {
1053                Train t = trains.get(i);
1054                if (t != null) {
1055                    String tName = t.getName();
1056                    if (_dispatcher.isTrainFree(tName)) {
1057                        trainSelectBox.addItem(t);
1058                    }
1059                }
1060            }
1061        }
1062        if (prevValue != null) {
1063            trainSelectBox.setSelectedItem(prevValue);
1064        }
1065        for ( ActionListener al: als) {
1066            trainSelectBox.addActionListener(al);
1067        }
1068    }
1069
1070    /**
1071     * Sets the labels and inputs for speed profile running
1072     * @param b True if the roster entry has valid speed profile else false
1073     */
1074    private void setSpeedProfileOptions(TrainInfo info,boolean b) {
1075        useSpeedProfileLabel.setEnabled(b);
1076        useSpeedProfileCheckBox.setEnabled(b);
1077        stopBySpeedProfileLabel.setEnabled(b);
1078        stopBySpeedProfileCheckBox.setEnabled(b);
1079        stopBySpeedProfileAdjustLabel.setEnabled(b);
1080        stopBySpeedProfileAdjustSpinner.setEnabled(b);
1081        if (!b) {
1082            useSpeedProfileCheckBox.setSelected(false);
1083            stopBySpeedProfileCheckBox.setSelected(false);
1084
1085        }
1086    }
1087
1088    private void initializeStartingBlockCombo() {
1089        String prevValue = (String)startingBlockBox.getSelectedItem();
1090        startingBlockBox.removeAllItems();
1091        startingBlockBoxList.clear();
1092        if (!inTransitBox.isSelected() && selectedTransit.getEntryBlocksList().isEmpty()) {
1093            inTransitBox.setSelected(true);
1094        }
1095        if (inTransitBox.isSelected()) {
1096            startingBlockBoxList = selectedTransit.getInternalBlocksList();
1097        } else {
1098            startingBlockBoxList = selectedTransit.getEntryBlocksList();
1099        }
1100        startingBlockSeqList = selectedTransit.getBlockSeqList();
1101        boolean found = false;
1102        for (int i = 0; i < startingBlockBoxList.size(); i++) {
1103            Block b = startingBlockBoxList.get(i);
1104            int seq = startingBlockSeqList.get(i).intValue();
1105            startingBlockBox.addItem(getBlockName(b) + "-" + seq);
1106            if (!found && b.getState() == Block.OCCUPIED) {
1107                startingBlockBox.setSelectedItem(getBlockName(b) + "-" + seq);
1108                found = true;
1109            }
1110        }
1111        if (prevValue != null) {
1112            startingBlockBox.setSelectedItem(prevValue);
1113        }
1114        JComboBoxUtil.setupComboBoxMaxRows(startingBlockBox);
1115    }
1116
1117    private void initializeDestinationBlockCombo() {
1118        String prevValue = (String)destinationBlockBox.getSelectedItem();
1119        destinationBlockBox.removeAllItems();
1120        destinationBlockBoxList.clear();
1121        int index = startingBlockBox.getSelectedIndex();
1122        if (index < 0) {
1123            return;
1124        }
1125        Block startBlock = startingBlockBoxList.get(index);
1126        destinationBlockBoxList = selectedTransit.getDestinationBlocksList(
1127                startBlock, inTransitBox.isSelected());
1128        destinationBlockSeqList = selectedTransit.getDestBlocksSeqList();
1129        for (int i = 0; i < destinationBlockBoxList.size(); i++) {
1130            Block b = destinationBlockBoxList.get(i);
1131            String bName = getBlockName(b);
1132            if (selectedTransit.getBlockCount(b) > 1) {
1133                int seq = destinationBlockSeqList.get(i).intValue();
1134                bName = bName + "-" + seq;
1135            }
1136            destinationBlockBox.addItem(bName);
1137        }
1138        if (prevValue != null) {
1139            destinationBlockBox.setSelectedItem(prevValue);
1140        }
1141        JComboBoxUtil.setupComboBoxMaxRows(destinationBlockBox);
1142    }
1143
1144    private String getBlockName(Block b) {
1145        if (b != null) {
1146            return b.getDisplayName();
1147        }
1148        return " ";
1149    }
1150
1151    protected void showActivateFrame() {
1152        if (initiateFrame != null) {
1153            initializeFreeTransitsCombo(new ArrayList<>());
1154            initiateFrame.setVisible(true);
1155        } else {
1156            _dispatcher.newTrainDone(null);
1157        }
1158    }
1159
1160    public void showActivateFrame(RosterEntry re) {
1161        showActivateFrame();
1162    }
1163
1164    protected void loadTrainInfo(ActionEvent e) {
1165        List<TrainInfoFileSummary> names = _tiFile.getTrainInfoFileSummaries();
1166        if (!names.isEmpty()) {
1167            JTable table = new JTable(){
1168                @Override
1169                public Dimension getPreferredScrollableViewportSize() {
1170                  return new Dimension(super.getPreferredSize().width,
1171                      super.getPreferredScrollableViewportSize().height);
1172                }
1173              };
1174            DefaultTableModel tm = new DefaultTableModel(
1175                    new Object[]{
1176                            Bundle.getMessage("FileNameColumnTitle"),
1177                            Bundle.getMessage("TrainColumnTitle"),
1178                            Bundle.getMessage("TransitColumnTitle"),
1179                            Bundle.getMessage("StartBlockColumnTitle"),
1180                            Bundle.getMessage("EndBlockColumnTitle"),
1181                            Bundle.getMessage("DccColumnTitleColumnTitle")
1182                    }, 0) {
1183                @Override
1184                public boolean isCellEditable(int row, int column) {
1185                    //all cells false
1186                    return false;
1187                }
1188            };
1189
1190            table.setModel(tm);
1191            for (TrainInfoFileSummary fs: names) {
1192                tm.addRow(new Object[] {fs.getFileName(),fs.getTrainName(),
1193                        fs.getTransitName(),fs.getStartBlockName()
1194                        ,fs.getEndBlockName(),fs.getDccAddress()});
1195            }
1196            JPanel jp = new JPanel(new BorderLayout());
1197            TableColumnModel columnModel = table.getColumnModel();
1198            table.setAutoResizeMode( JTable.AUTO_RESIZE_OFF );
1199            for (int column = 0; column < table.getColumnCount(); column++) {
1200                int width = 30; // Min width
1201                for (int row = 0; row < table.getRowCount(); row++) {
1202                    TableCellRenderer renderer = table.getCellRenderer(row, column);
1203                    Component comp = table.prepareRenderer(renderer, row, column);
1204                    width = Math.max(comp.getPreferredSize().width +1 , width);
1205                }
1206                if(width > 300)
1207                    width=300;
1208                columnModel.getColumn(column).setPreferredWidth(width);
1209            }
1210            //jp.setPreferredSize(table.getPreferredSize());
1211            jp.add(table);
1212            JScrollPane sp = new JScrollPane(table,
1213                            ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED,
1214                            ScrollPaneConstants.HORIZONTAL_SCROLLBAR_AS_NEEDED);
1215            int optionSelected = JmriJOptionPane.showOptionDialog(initiateFrame,
1216                    sp, Bundle.getMessage("LoadTrainTitle"), JmriJOptionPane.OK_CANCEL_OPTION, JmriJOptionPane.PLAIN_MESSAGE,
1217                    null,null,null);
1218            if (optionSelected != JmriJOptionPane.OK_OPTION) {
1219                //Canceled
1220                return;
1221            }
1222            if (table.getSelectedRow() < 0) {
1223                return;
1224            }
1225            String selName = (String)table.getModel().getValueAt(table.getSelectedRow(),0);
1226            if ((selName == null) || (selName.isEmpty())) {
1227                return;
1228            }
1229            //read xml data from selected filename and move it into the new train dialog box
1230            _trainInfoName = selName;
1231            try {
1232                trainInfo = _tiFile.readTrainInfo( selName);
1233                if (trainInfo != null) {
1234                    // process the information just read
1235                    trainInfoToDialog(trainInfo);
1236                }
1237            } catch (java.io.IOException ioe) {
1238                log.error("IO Exception when reading train info file", ioe);
1239            } catch (org.jdom2.JDOMException jde) {
1240                log.error("JDOM Exception when reading train info file", jde);
1241            }
1242            handleDelayStartClick(null);
1243            handleReverseAtEndBoxClick();
1244        }
1245    }
1246
1247    private void saveTrainInfo() {
1248        saveTrainInfo(false);
1249        refreshNextTrainCombo();
1250    }
1251
1252    private void saveTrainInfoAsTemplate() {
1253        saveTrainInfo(true);
1254    }
1255
1256    private void saveTrainInfo(boolean asTemplate) {
1257        try {
1258            dialogToTrainInfo(trainInfo);
1259        } catch (IllegalArgumentException ide) {
1260            JmriJOptionPane.showMessageDialog(initiateFrame, ide.getMessage(),
1261                    Bundle.getMessage("ErrorTitle"), JmriJOptionPane.ERROR_MESSAGE);
1262            return;
1263        }
1264        // get file name
1265        String fileName;
1266        if (asTemplate) {
1267            fileName = normalizeXmlFileName(nameOfTemplateFile);
1268        } else {
1269            String eName = JmriJOptionPane.showInputDialog(initiateFrame,
1270                    Bundle.getMessage("EnterFileName") + " :", _trainInfoName);
1271            if (eName == null) {  //Cancel pressed
1272                return;
1273            }
1274            if (eName.length() < 1) {
1275                JmriJOptionPane.showMessageDialog(initiateFrame, Bundle.getMessage("Error25"),
1276                        Bundle.getMessage("ErrorTitle"), JmriJOptionPane.ERROR_MESSAGE);
1277                return;
1278            }
1279            fileName = normalizeXmlFileName(eName);
1280            _trainInfoName = fileName;
1281        }
1282        // check if train info file name is in use
1283        String[] names = _tiFile.getTrainInfoFileNames();
1284        if (names.length > 0) {
1285            boolean found = false;
1286            for (int i = 0; i < names.length; i++) {
1287                if (fileName.equals(names[i])) {
1288                    found = true;
1289                }
1290            }
1291            if (found) {
1292                // file by that name is already present
1293                int selectedValue = JmriJOptionPane.showOptionDialog(initiateFrame,
1294                        Bundle.getMessage("Question3", fileName),
1295                        Bundle.getMessage("WarningTitle"), JmriJOptionPane.DEFAULT_OPTION,
1296                        JmriJOptionPane.QUESTION_MESSAGE, null,
1297                        new Object[]{Bundle.getMessage("ButtonReplace"),Bundle.getMessage("ButtonNo")},
1298                        Bundle.getMessage("ButtonNo"));
1299                if (selectedValue != 0 ) { // array position 0 , replace not selected
1300                    return;   // return without writing if "No" response
1301                }
1302            }
1303        }
1304        // write the Train Info file
1305        try {
1306            _tiFile.writeTrainInfo(trainInfo, fileName);
1307        } //catch (org.jdom2.JDOMException jde) {
1308        // log.error("JDOM exception writing Train Info: "+jde);
1309        //}
1310        catch (java.io.IOException ioe) {
1311            log.error("IO exception writing Train Info", ioe);
1312        }
1313    }
1314
1315    private void deleteTrainInfo() {
1316        String[] names = _tiFile.getTrainInfoFileNames();
1317        if (names.length > 0) {
1318            Object selName = JmriJOptionPane.showInputDialog(initiateFrame,
1319                    Bundle.getMessage("DeleteTrainChoice"), Bundle.getMessage("DeleteTrainTitle"),
1320                    JmriJOptionPane.QUESTION_MESSAGE, null, names, names[0]);
1321            if ((selName == null) || (((String) selName).isEmpty())) {
1322                return;
1323            }
1324            _tiFile.deleteTrainInfoFile((String) selName);
1325        }
1326    }
1327
1328    private void trainInfoToDialog(TrainInfo info) {
1329        if (!info.getDynamicTransit()) {
1330            radioTransitsPredefined.setSelected(true);
1331            if (!info.getTransitName().isEmpty()) {
1332                try {
1333                    transitSelectBox.setSelectedItemByName(info.getTransitName());
1334                } catch (Exception ex) {
1335                    log.warn("Transit {} from file not in Transit menu", info.getTransitName());
1336                    JmriJOptionPane.showMessageDialog(initiateFrame,
1337                            Bundle.getMessage("TransitWarn", info.getTransitName()),
1338                            null, JmriJOptionPane.WARNING_MESSAGE);
1339                }
1340            }
1341        } else {
1342            radioTransitsAdHoc.setSelected(true);
1343        }
1344        switch (info.getTrainsFrom()) {
1345            case TRAINSFROMROSTER:
1346                radioTrainsFromRoster.setSelected(true);
1347                if (!info.getRosterId().isEmpty()) {
1348                    if (!setRosterComboBox(rosterComboBox, info.getRosterId())) {
1349                        log.warn("Roster {} from file not in Roster Combo", info.getRosterId());
1350                        JmriJOptionPane.showMessageDialog(initiateFrame,
1351                                Bundle.getMessage("TrainWarn", info.getRosterId()),
1352                                null, JmriJOptionPane.WARNING_MESSAGE);
1353                    }
1354                }
1355                break;
1356            case TRAINSFROMOPS:
1357                radioTrainsFromOps.setSelected(true);
1358                if (!info.getTrainName().isEmpty()) {
1359                    if (!setTrainComboBox(trainSelectBox, info.getTrainName())) {
1360                        log.warn("Train {} from file not in Train Combo", info.getTrainName());
1361                        JmriJOptionPane.showMessageDialog(initiateFrame,
1362                                Bundle.getMessage("TrainWarn", info.getTrainName()),
1363                                null, JmriJOptionPane.WARNING_MESSAGE);
1364                    }
1365                }
1366                break;
1367            case TRAINSFROMUSER:
1368                radioTrainsFromUser.setSelected(true);
1369                dccAddressSpinner.setValue(Integer.valueOf(info.getDccAddress()));
1370                break;
1371            case TRAINSFROMSETLATER:
1372            default:
1373                radioTrainsFromSetLater.setSelected(true);
1374        }
1375        trainNameField.setText(info.getTrainUserName());
1376        trainDetectionComboBox.setSelectedItemByValue(info.getTrainDetection());
1377        inTransitBox.setSelected(info.getTrainInTransit());
1378        if (radioTransitsAdHoc.isSelected()) {
1379            initializeStartingBlockComboDynamic();
1380        } else {
1381            initializeStartingBlockCombo();
1382        }
1383        setComboBox(startingBlockBox, info.getStartBlockName());
1384        if (radioTransitsAdHoc.isSelected()) {
1385            initializeViaBlockDynamicCombo();
1386            setComboBox(viaBlockBox, info.getViaBlockName());
1387        }
1388        if (radioTransitsAdHoc.isSelected()) {
1389            initializeDestinationBlockDynamicCombo();
1390        } else {
1391            initializeDestinationBlockCombo();
1392        }
1393        setComboBox(destinationBlockBox, info.getDestinationBlockName());
1394
1395        setAllocateMethodButtons(info.getAllocationMethod());
1396        prioritySpinner.setValue(info.getPriority());
1397        resetWhenDoneBox.setSelected(info.getResetWhenDone());
1398        reverseAtEndBox.setSelected(info.getReverseAtEnd());
1399        setDelayModeBox(info.getDelayedStart(), delayedStartBox);
1400        //delayedStartBox.setSelected(info.getDelayedStart());
1401        departureHrSpinner.setValue(info.getDepartureTimeHr());
1402        departureMinSpinner.setValue(info.getDepartureTimeMin());
1403        delaySensor.setSelectedItem(info.getDelaySensor());
1404        resetStartSensorBox.setSelected(info.getResetStartSensor());
1405        setDelayModeBox(info.getDelayedRestart(), delayedReStartBox);
1406        delayMinSpinner.setValue(info.getRestartDelayMin());
1407        delayReStartSensor.setSelectedItem(info.getRestartSensor());
1408        resetRestartSensorBox.setSelected(info.getResetRestartSensor());
1409
1410        resetStartSensorBox.setSelected(info.getResetStartSensor());
1411        setDelayModeBox(info.getReverseDelayedRestart(), reverseDelayedRestartType);
1412        delayReverseMinSpinner.setValue(info.getReverseRestartDelayMin());
1413        delayReverseReStartSensor.setSelectedItem(info.getReverseRestartSensor());
1414        delayReverseResetSensorBox.setSelected(info.getReverseResetRestartSensor());
1415
1416        terminateWhenDoneBox.setSelected(info.getTerminateWhenDone());
1417        nextTrain.setSelectedIndex(-1);
1418        try {
1419            nextTrain.setSelectedItem(info.getNextTrain());
1420        } catch (Exception ex){
1421            nextTrain.setSelectedIndex(-1);
1422        }
1423        handleTerminateWhenDoneBoxClick();
1424        setComboBox(trainTypeBox, info.getTrainType());
1425        autoRunBox.setSelected(info.getAutoRun());
1426        loadAtStartupBox.setSelected(info.getLoadAtStartup());
1427        setAllocateMethodButtons(info.getAllocationMethod());
1428        autoTrainInfoToDialog(info);
1429    }
1430
1431    private boolean validateDialog() throws IllegalArgumentException {
1432        int index = transitSelectBox.getSelectedIndex();
1433        if (index < 0) {
1434            throw new IllegalArgumentException(Bundle.getMessage("Error44"));
1435        }
1436        switch (trainsFromButtonGroup.getSelection().getActionCommand()) {
1437            case "TRAINSFROMROSTER":
1438                if (rosterComboBox.getSelectedIndex() < 1 ) {
1439                    throw new IllegalArgumentException(Bundle.getMessage("Error41"));
1440                }
1441                break;
1442            case "TRAINSFROMOPS":
1443                if (trainSelectBox.getSelectedIndex() < 1) {
1444                    throw new IllegalArgumentException(Bundle.getMessage("Error42"));
1445                }
1446                break;
1447            case "TRAINSFROMUSER":
1448                if (trainNameField.getText().isEmpty()) {
1449                    throw new IllegalArgumentException(Bundle.getMessage("Error22"));
1450                }
1451                break;
1452            case "TRAINSFROMSETLATER":
1453            default:
1454        }
1455        index = startingBlockBox.getSelectedIndex();
1456        if (index < 0) {
1457            throw new IllegalArgumentException(Bundle.getMessage("Error13"));
1458        }
1459        index = destinationBlockBox.getSelectedIndex();
1460        if (index < 0) {
1461            throw new IllegalArgumentException(Bundle.getMessage("Error8"));
1462        }
1463        if (radioTransitsAdHoc.isSelected()) {
1464            index = viaBlockBox.getSelectedIndex();
1465            if (index < 0) {
1466                throw new IllegalArgumentException(Bundle.getMessage("Error8"));
1467            }
1468        }
1469        if ((!reverseAtEndBox.isSelected()) && resetWhenDoneBox.isSelected()
1470                && (!selectedTransit.canBeResetWhenDone())) {
1471            resetWhenDoneBox.setSelected(false);
1472            throw new IllegalArgumentException(Bundle.getMessage("NoResetMessage"));
1473        }
1474        int max = Math.round((float) maxSpeedSpinner.getValue()*100.0f);
1475        int min = Math.round((float) minReliableOperatingSpeedSpinner.getValue()*100.0f);
1476        if ((max-min) < 10) {
1477            throw new IllegalArgumentException(Bundle.getMessage("Error49",
1478                    maxSpeedSpinner.getValue(), minReliableOperatingSpeedSpinner.getValue()));
1479        }
1480        return true;
1481    }
1482
1483    private boolean dialogToTrainInfo(TrainInfo info) {
1484        int index = transitSelectBox.getSelectedIndex();
1485        info.setDynamicTransit(radioTransitsAdHoc.isSelected());
1486        if (!info.getDynamicTransit() && index >= 0 ) {
1487            info.setTransitName(transitSelectBox.getSelectedItem().getDisplayName());
1488            info.setTransitId(transitSelectBox.getSelectedItem().getDisplayName());
1489        }
1490        switch (trainsFromButtonGroup.getSelection().getActionCommand()) {
1491            case "TRAINSFROMROSTER":
1492                info.setRosterId(((RosterEntry) rosterComboBox.getSelectedItem()).getId());
1493                info.setDccAddress(((RosterEntry) rosterComboBox.getSelectedItem()).getDccAddress());
1494                trainInfo.setTrainsFrom(TrainsFrom.TRAINSFROMROSTER);
1495                setTrainsFromOptions(trainInfo.getTrainsFrom());
1496                break;
1497            case "TRAINSFROMOPS":
1498                info.setTrainName(((Train) trainSelectBox.getSelectedItem()).toString());
1499                info.setDccAddress(String.valueOf(dccAddressSpinner.getValue()));
1500                trainInfo.setTrainsFrom(TrainsFrom.TRAINSFROMOPS);
1501                setTrainsFromOptions(trainInfo.getTrainsFrom());
1502                break;
1503            case "TRAINSFROMUSER":
1504                trainInfo.setTrainsFrom(TrainsFrom.TRAINSFROMUSER);
1505                info.setDccAddress(String.valueOf(dccAddressSpinner.getValue()));
1506                break;
1507            case "TRAINSFROMSETLATER":
1508            default:
1509                trainInfo.setTrainsFrom(TrainsFrom.TRAINSFROMSETLATER);
1510                info.setTrainName("");
1511                info.setDccAddress("");
1512        }
1513        info.setTrainUserName(trainNameField.getText());
1514        info.setTrainInTransit(inTransitBox.isSelected());
1515        info.setStartBlockName((String) startingBlockBox.getSelectedItem());
1516        index = startingBlockBox.getSelectedIndex();
1517        info.setStartBlockId(startingBlockBoxList.get(index).getDisplayName());
1518        if (info.getDynamicTransit()) {
1519            info.setStartBlockSeq(1);
1520        } else {
1521            info.setStartBlockSeq(startingBlockSeqList.get(index).intValue());
1522        }
1523        index = destinationBlockBox.getSelectedIndex();
1524        info.setDestinationBlockId(destinationBlockBoxList.get(index).getDisplayName());
1525        info.setDestinationBlockName(destinationBlockBoxList.get(index).getDisplayName());
1526        if (info.getDynamicTransit()) {
1527            info.setViaBlockName(viaBlockBoxList.get(viaBlockBox.getSelectedIndex()).getDisplayName());
1528        } else {
1529            info.setDestinationBlockSeq(destinationBlockSeqList.get(index).intValue());
1530        }
1531        info.setPriority((Integer) prioritySpinner.getValue());
1532        info.setTrainDetection(((TrainDetectionItem)trainDetectionComboBox.getSelectedItem()).value);
1533        info.setResetWhenDone(resetWhenDoneBox.isSelected());
1534        info.setReverseAtEnd(reverseAtEndBox.isSelected());
1535        info.setDelayedStart(delayModeFromBox(delayedStartBox));
1536        info.setDelaySensorName(delaySensor.getSelectedItemDisplayName());
1537        info.setResetStartSensor(resetStartSensorBox.isSelected());
1538        info.setDepartureTimeHr((Integer) departureHrSpinner.getValue());
1539        info.setDepartureTimeMin((Integer) departureMinSpinner.getValue());
1540        info.setTrainType((String) trainTypeBox.getSelectedItem());
1541        info.setAutoRun(autoRunBox.isSelected());
1542        info.setLoadAtStartup(loadAtStartupBox.isSelected());
1543        info.setAllocateAllTheWay(false); // force to false next field is now used.
1544        if (allocateAllTheWayRadioButton.isSelected()) {
1545            info.setAllocationMethod(ActiveTrain.ALLOCATE_AS_FAR_AS_IT_CAN);
1546        } else if (allocateBySafeRadioButton.isSelected()) {
1547            info.setAllocationMethod(ActiveTrain.ALLOCATE_BY_SAFE_SECTIONS);
1548        } else {
1549            info.setAllocationMethod((Integer) allocateCustomSpinner.getValue());
1550        }
1551        info.setDelayedRestart(delayModeFromBox(delayedReStartBox));
1552        info.setRestartSensorName(delayReStartSensor.getSelectedItemDisplayName());
1553        info.setResetRestartSensor(resetRestartSensorBox.isSelected());
1554        info.setRestartDelayMin((Integer) delayMinSpinner.getValue());
1555
1556        info.setReverseDelayedRestart(delayModeFromBox(reverseDelayedRestartType));
1557        info.setReverseRestartSensorName(delayReverseReStartSensor.getSelectedItemDisplayName());
1558        info.setReverseResetRestartSensor(delayReverseResetSensorBox.isSelected());
1559        info.setReverseRestartDelayMin((Integer) delayReverseMinSpinner.getValue());
1560
1561        info.setTerminateWhenDone(terminateWhenDoneBox.isSelected());
1562        if (nextTrain.getSelectedIndex() > 0 ) {
1563            info.setNextTrain((String)nextTrain.getSelectedItem());
1564        } else {
1565            info.setNextTrain("None");
1566        }
1567        autoRunItemsToTrainInfo(info);
1568        return true;
1569    }
1570
1571    private boolean setRosterComboBox(RosterEntryComboBox box, String txt) {
1572        boolean found = false;
1573        for (int i = 1; i < box.getItemCount(); i++) {
1574            if (txt.equals(((RosterEntry) box.getItemAt(i)).getId())) {
1575                box.setSelectedIndex(i);
1576                found = true;
1577                break;
1578            }
1579        }
1580        if (!found && box.getItemCount() > 0) {
1581            box.setSelectedIndex(0);
1582        }
1583        return found;
1584    }
1585
1586    // Normalizes a suggested xml file name.  Returns null string if a valid name cannot be assembled
1587    private String normalizeXmlFileName(String name) {
1588        if (name.length() < 1) {
1589            return "";
1590        }
1591        String newName = name;
1592        // strip off .xml or .XML if present
1593        if ((name.endsWith(".xml")) || (name.endsWith(".XML"))) {
1594            newName = name.substring(0, name.length() - 4);
1595            if (newName.length() < 1) {
1596                return "";
1597            }
1598        }
1599        // replace all non-alphanumeric characters with underscore
1600        newName = newName.replaceAll("[\\W]", "_");
1601        return (newName + ".xml");
1602    }
1603
1604    private boolean setTrainComboBox(JComboBox<Object> box, String txt) {
1605        boolean found = false;
1606        for (int i = 1; i < box.getItemCount(); i++) { //skip the select train item
1607            if (txt.equals(box.getItemAt(i).toString())) {
1608                box.setSelectedIndex(i);
1609                found = true;
1610                break;
1611            }
1612        }
1613        if (!found && box.getItemCount() > 0) {
1614            box.setSelectedIndex(0);
1615        }
1616        return found;
1617    }
1618
1619    private boolean setComboBox(JComboBox<String> box, String txt) {
1620        boolean found = false;
1621        for (int i = 0; i < box.getItemCount(); i++) {
1622            if (txt.equals(box.getItemAt(i))) {
1623                box.setSelectedIndex(i);
1624                found = true;
1625                break;
1626            }
1627        }
1628        if (!found && box.getItemCount() > 0) {
1629            box.setSelectedIndex(0);
1630        }
1631        return found;
1632    }
1633
1634    int delayModeFromBox(JComboBox<String> box) {
1635        String mode = (String) box.getSelectedItem();
1636        int result = jmri.util.StringUtil.getStateFromName(mode, delayedStartInt, delayedStartString);
1637
1638        if (result < 0) {
1639            log.warn("unexpected mode string in turnoutMode: {}", mode);
1640            throw new IllegalArgumentException();
1641        }
1642        return result;
1643    }
1644
1645    void setDelayModeBox(int mode, JComboBox<String> box) {
1646        String result = jmri.util.StringUtil.getNameFromState(mode, delayedStartInt, delayedStartString);
1647        box.setSelectedItem(result);
1648    }
1649
1650    /**
1651     * The following are for items that are only for automatic running of
1652     * ActiveTrains They are isolated here to simplify changing them in the
1653     * future.
1654     * <ul>
1655     * <li>initializeAutoRunItems - initializes the display of auto run items in
1656     * this window
1657     * <li>initializeAutoRunValues - initializes the values of auto run items
1658     * from values in a saved train info file hideAutoRunItems - hides all auto
1659     * run items in this window showAutoRunItems - shows all auto run items in
1660     * this window
1661     * <li>autoTrainInfoToDialog - gets auto run items from a train info, puts
1662     * values in items, and initializes auto run dialog items
1663     * <li>autoTrainItemsToTrainInfo - copies values of auto run items to train
1664     * info for saving to a file
1665     * <li>readAutoRunItems - reads and checks values of all auto run items.
1666     * returns true if OK, sends appropriate messages and returns false if not
1667     * OK
1668     * <li>setAutoRunItems - sets the user entered auto run items in the new
1669     * AutoActiveTrain
1670     * </ul>
1671     */
1672    // auto run items in ActivateTrainFrame
1673    private final JPanel pa1 = new JPanel();
1674    private final JLabel speedFactorLabel = new JLabel(Bundle.getMessage("SpeedFactorLabel"));
1675    private final JSpinner speedFactorSpinner = new JSpinner();
1676    private final JLabel minReliableOperatingSpeedLabel = new JLabel(Bundle.getMessage("MinReliableOperatingSpeedLabel"));
1677    private final JSpinner minReliableOperatingSpeedSpinner = new JSpinner();
1678    private final JLabel maxSpeedLabel = new JLabel(Bundle.getMessage("MaxSpeedLabel"));
1679    private final JSpinner maxSpeedSpinner = new JSpinner();
1680    private final JPanel pa2 = new JPanel();
1681    private final JLabel rampRateLabel = new JLabel(Bundle.getMessage("RampRateBoxLabel"));
1682    private final JComboBox<String> rampRateBox = new JComboBox<>();
1683    private final JPanel pa2a = new JPanel();
1684    private final JLabel useSpeedProfileLabel = new JLabel(Bundle.getMessage("UseSpeedProfileLabel"));
1685    private final JCheckBox useSpeedProfileCheckBox = new JCheckBox( );
1686    private final JLabel stopBySpeedProfileLabel = new JLabel(Bundle.getMessage("StopBySpeedProfileLabel"));
1687    private final JCheckBox stopBySpeedProfileCheckBox = new JCheckBox( );
1688    private final JLabel stopBySpeedProfileAdjustLabel = new JLabel(Bundle.getMessage("StopBySpeedProfileAdjustLabel"));
1689    private final JSpinner stopBySpeedProfileAdjustSpinner = new JSpinner();
1690    private final JPanel pa3 = new JPanel();
1691    private final JCheckBox soundDecoderBox = new JCheckBox(Bundle.getMessage("SoundDecoder"));
1692    private final JCheckBox runInReverseBox = new JCheckBox(Bundle.getMessage("RunInReverse"));
1693    private final JPanel pa4 = new JPanel();
1694
1695    protected static class TrainDetectionJCombo extends JComboBox<TrainDetectionItem> {
1696        public void setSelectedItemByValue(TrainDetection trainDetVar) {
1697            for ( int ix = 0; ix < getItemCount() ; ix ++ ) {
1698                if (getItemAt(ix).value == trainDetVar) {
1699                    this.setSelectedIndex(ix);
1700                    break;
1701                }
1702            }
1703        }
1704    }
1705
1706    private final JLabel trainDetectionLabel = new JLabel(Bundle.getMessage("TrainDetection"));
1707    public final TrainDetectionJCombo trainDetectionComboBox = new TrainDetectionJCombo();
1708
1709    protected static class TrainLengthUnitsJCombo extends JComboBox<TrainLengthUnitsItem> {
1710        public void setSelectedItemByValue(TrainLengthUnits var) {
1711            for ( int ix = 0; ix < getItemCount() ; ix ++ ) {
1712                if (getItemAt(ix).value == var) {
1713                    this.setSelectedIndex(ix);
1714                    break;
1715                }
1716            }
1717        }
1718    }
1719
1720    public final TrainLengthUnitsJCombo trainLengthUnitsComboBox = new TrainLengthUnitsJCombo();
1721    private final JLabel trainLengthLabel = new JLabel(Bundle.getMessage("MaxTrainLengthLabel"));
1722    private JLabel trainLengthAltLengthLabel; // I18N Label
1723    private final JSpinner maxTrainLengthSpinner = new JSpinner(); // initialized later
1724
1725    private void initializeAutoRunItems() {
1726        initializeRampCombo();
1727        initializeScaleLengthBox();
1728        pa1.setLayout(new FlowLayout());
1729        pa1.add(speedFactorLabel);
1730        speedFactorSpinner.setModel(new SpinnerNumberModel(1.0f, 0.1f, 2.0f, 0.01f));
1731        speedFactorSpinner.setEditor(new JSpinner.NumberEditor(speedFactorSpinner, "# %"));
1732        pa1.add(speedFactorSpinner);
1733        speedFactorSpinner.setToolTipText(Bundle.getMessage("SpeedFactorHint"));
1734        pa1.add(new JLabel("   "));
1735        pa1.add(maxSpeedLabel);
1736        maxSpeedSpinner.setModel(new SpinnerNumberModel(1.0f, 0.1f, 1.0f, 0.01f));
1737        maxSpeedSpinner.setEditor(new JSpinner.NumberEditor(maxSpeedSpinner, "# %"));
1738        pa1.add(maxSpeedSpinner);
1739        maxSpeedSpinner.setToolTipText(Bundle.getMessage("MaxSpeedHint"));
1740        pa1.add(minReliableOperatingSpeedLabel);
1741        minReliableOperatingSpeedSpinner.setModel(new SpinnerNumberModel(0.0f, 0.0f, 1.0f, 0.01f));
1742        minReliableOperatingSpeedSpinner.setEditor(new JSpinner.NumberEditor(minReliableOperatingSpeedSpinner, "# %"));
1743        pa1.add(minReliableOperatingSpeedSpinner);
1744        minReliableOperatingSpeedSpinner.setToolTipText(Bundle.getMessage("MinReliableOperatingSpeedHint"));
1745        initiatePane.add(pa1);
1746        pa2.setLayout(new FlowLayout());
1747        pa2.add(rampRateLabel);
1748        pa2.add(rampRateBox);
1749        rampRateBox.setToolTipText(Bundle.getMessage("RampRateBoxHint"));
1750        pa2.add(useSpeedProfileLabel);
1751        pa2.add(useSpeedProfileCheckBox);
1752        useSpeedProfileCheckBox.setToolTipText(Bundle.getMessage("UseSpeedProfileHint"));
1753        initiatePane.add(pa2);
1754        pa2a.setLayout(new FlowLayout());
1755        pa2a.add(stopBySpeedProfileLabel);
1756        pa2a.add(stopBySpeedProfileCheckBox);
1757        stopBySpeedProfileCheckBox.setToolTipText(Bundle.getMessage("UseSpeedProfileHint")); // reuse identical hint for Stop
1758        pa2a.add(stopBySpeedProfileAdjustLabel);
1759        stopBySpeedProfileAdjustSpinner.setModel(new SpinnerNumberModel( 1.0f, 0.1f, 5.0f, 0.01f));
1760        stopBySpeedProfileAdjustSpinner.setEditor(new JSpinner.NumberEditor(stopBySpeedProfileAdjustSpinner, "# %"));
1761        pa2a.add(stopBySpeedProfileAdjustSpinner);
1762        stopBySpeedProfileAdjustSpinner.setToolTipText(Bundle.getMessage("StopBySpeedProfileAdjustHint"));
1763        initiatePane.add(pa2a);
1764        pa3.setLayout(new FlowLayout());
1765        pa3.add(soundDecoderBox);
1766        soundDecoderBox.setToolTipText(Bundle.getMessage("SoundDecoderBoxHint"));
1767        pa3.add(new JLabel("   "));
1768        pa3.add(runInReverseBox);
1769        runInReverseBox.setToolTipText(Bundle.getMessage("RunInReverseBoxHint"));
1770        initiatePane.add(pa3);
1771        maxTrainLengthSpinner.setModel(new SpinnerNumberModel(18.0f, 0.0f, 10000.0f, 0.5f));
1772        maxTrainLengthSpinner.setEditor(new JSpinner.NumberEditor(maxTrainLengthSpinner, "###0.0"));
1773        maxTrainLengthSpinner.setToolTipText(Bundle.getMessage("MaxTrainLengthHint")); // won't be updated while Dispatcher is open
1774        maxTrainLengthSpinner.addChangeListener( e -> handlemaxTrainLengthChangeUnitsLength());
1775        trainLengthUnitsComboBox.addActionListener( e -> handlemaxTrainLengthChangeUnitsLength());
1776        trainLengthAltLengthLabel=new JLabel();
1777        pa4.setLayout(new FlowLayout());
1778        pa4.add(trainLengthLabel);
1779        pa4.add(maxTrainLengthSpinner);
1780        pa4.add(trainLengthUnitsComboBox);
1781        pa4.add(trainLengthAltLengthLabel);
1782        initiatePane.add(pa4);
1783        hideAutoRunItems();   // initialize with auto run items hidden
1784    }
1785
1786    private void handlemaxTrainLengthChangeUnitsLength() {
1787        trainLengthAltLengthLabel.setText(maxTrainLengthCalculateAltFormatted(
1788                ((TrainLengthUnitsItem) trainLengthUnitsComboBox.getSelectedItem()).getValue(),
1789                (float) maxTrainLengthSpinner.getValue()));
1790    }
1791
1792    /**
1793     * Get an I18N String of the max TrainLength.
1794     * @param fromUnits the Length Unit.
1795     * @param fromValue the length.
1796     * @return String format of the length.
1797     */
1798    private String maxTrainLengthCalculateAltFormatted(TrainLengthUnits fromUnits, float fromValue) {
1799        float value = maxTrainLengthCalculateAlt(fromUnits, fromValue);
1800        switch (fromUnits) {
1801            case TRAINLENGTH_ACTUALINCHS:
1802                return String.format(Locale.getDefault(), "%.2f %s",
1803                    value, Bundle.getMessage("TrainLengthInScaleFeet"));
1804            case TRAINLENGTH_ACTUALCM:
1805                return String.format(Locale.getDefault(), "%.1f %s",
1806                    value, Bundle.getMessage("TrainLengthInScaleMeters"));
1807            case TRAINLENGTH_SCALEFEET:
1808                return String.format(Locale.getDefault(), "%.1f %s",
1809                    value, Bundle.getMessage("TrainLengthInActualInchs"));
1810            case TRAINLENGTH_SCALEMETERS:
1811                return String.format(Locale.getDefault(), "%.0f %s",
1812                    value, Bundle.getMessage("TrainLengthInActualcm"));
1813            default:
1814                log.error("Invalid TrainLengthUnits must have been updated, fix maxTrainLengthCalculateAltFormatted");
1815        }
1816        return "";
1817    }
1818
1819    private float maxTrainLengthToScaleMeters(TrainLengthUnits fromUnits, float fromValue) {
1820        float value;
1821        // convert to meters.
1822        switch (fromUnits) {
1823            case TRAINLENGTH_ACTUALINCHS:
1824                value = fromValue / 12.0f * (float) _dispatcher.getScale().getScaleRatio();
1825                value = value / 3.28084f;
1826                break;
1827            case TRAINLENGTH_ACTUALCM:
1828                value = fromValue / 100.0f * (float) _dispatcher.getScale().getScaleRatio();
1829                break;
1830           case TRAINLENGTH_SCALEFEET:
1831               value = fromValue / 3.28084f;
1832               break;
1833           case TRAINLENGTH_SCALEMETERS:
1834               value = fromValue;
1835               break;
1836           default:
1837               value = 0;
1838               log.error("Invalid TrainLengthUnits has been updated, fix me");
1839        }
1840        return value;
1841    }
1842
1843    /*
1844     * Calculates the reciprocal unit. Actual to Scale and vice versa
1845     */
1846    private float maxTrainLengthCalculateAlt(TrainLengthUnits fromUnits, float fromValue) {
1847        switch (fromUnits) {
1848            case TRAINLENGTH_ACTUALINCHS:
1849                // calc scale feet
1850                return (float) jmri.util.MathUtil.granulize(fromValue / 12 * (float) _dispatcher.getScale().getScaleRatio(),0.1f);
1851            case TRAINLENGTH_ACTUALCM:
1852                // calc scale meter
1853                return fromValue / 100 * (float) _dispatcher.getScale().getScaleRatio();
1854            case TRAINLENGTH_SCALEFEET:
1855                // calc actual inchs
1856                return fromValue * 12 * (float) _dispatcher.getScale().getScaleFactor();
1857           case TRAINLENGTH_SCALEMETERS:
1858                // calc actual cm.
1859                return fromValue * 100 * (float) _dispatcher.getScale().getScaleFactor();
1860           default:
1861               log.error("Invalid TrainLengthUnits has been updated, fix me");
1862        }
1863        return 0;
1864    }
1865
1866    private void hideAutoRunItems() {
1867        pa1.setVisible(false);
1868        pa2.setVisible(false);
1869        pa2a.setVisible(false);
1870        pa3.setVisible(false);
1871        pa4.setVisible(false);
1872    }
1873
1874    private void showAutoRunItems() {
1875        pa1.setVisible(true);
1876        pa2.setVisible(true);
1877        pa2a.setVisible(true);
1878        pa3.setVisible(true);
1879        pa4.setVisible(true);
1880    }
1881
1882    private void autoTrainInfoToDialog(TrainInfo info) {
1883        speedFactorSpinner.setValue(info.getSpeedFactor());
1884        maxSpeedSpinner.setValue(info.getMaxSpeed());
1885        minReliableOperatingSpeedSpinner.setValue(info.getMinReliableOperatingSpeed());
1886        setComboBox(rampRateBox, info.getRampRate());
1887        trainDetectionComboBox.setSelectedItemByValue(info.getTrainDetection());
1888        runInReverseBox.setSelected(info.getRunInReverse());
1889        soundDecoderBox.setSelected(info.getSoundDecoder());
1890        trainLengthUnitsComboBox.setSelectedItemByValue(info.getTrainLengthUnits());
1891        switch (info.getTrainLengthUnits()) {
1892            case TRAINLENGTH_SCALEFEET:
1893                maxTrainLengthSpinner.setValue(info.getMaxTrainLengthScaleFeet());
1894                break;
1895            case TRAINLENGTH_SCALEMETERS:
1896                maxTrainLengthSpinner.setValue(info.getMaxTrainLengthScaleMeters());
1897                break;
1898            case TRAINLENGTH_ACTUALINCHS:
1899                maxTrainLengthSpinner.setValue(info.getMaxTrainLengthScaleFeet() * 12.0f * (float)_dispatcher.getScale().getScaleFactor());
1900                break;
1901            case TRAINLENGTH_ACTUALCM:
1902                maxTrainLengthSpinner.setValue(info.getMaxTrainLengthScaleMeters() * 100.0f * (float)_dispatcher.getScale().getScaleFactor());
1903                break;
1904            default:
1905                maxTrainLengthSpinner.setValue(0.0f);
1906        }
1907        useSpeedProfileCheckBox.setSelected(info.getUseSpeedProfile());
1908        stopBySpeedProfileCheckBox.setSelected(info.getStopBySpeedProfile());
1909        stopBySpeedProfileAdjustSpinner.setValue(info.getStopBySpeedProfileAdjust());
1910        if (autoRunBox.isSelected()) {
1911            showAutoRunItems();
1912        } else {
1913            hideAutoRunItems();
1914        }
1915        initiateFrame.pack();
1916    }
1917
1918    private void autoRunItemsToTrainInfo(TrainInfo info) {
1919        info.setSpeedFactor((float) speedFactorSpinner.getValue());
1920        info.setMaxSpeed((float) maxSpeedSpinner.getValue());
1921        info.setMinReliableOperatingSpeed((float) minReliableOperatingSpeedSpinner.getValue());
1922        info.setRampRate((String) rampRateBox.getSelectedItem());
1923        info.setRunInReverse(runInReverseBox.isSelected());
1924        info.setSoundDecoder(soundDecoderBox.isSelected());
1925        info.setTrainLengthUnits(((TrainLengthUnitsItem) trainLengthUnitsComboBox.getSelectedItem()).getValue());
1926        info.setMaxTrainLengthScaleMeters(maxTrainLengthToScaleMeters( info.getTrainLengthUnits(), (float) maxTrainLengthSpinner.getValue()));
1927
1928        // Only use speed profile values if enabled
1929        if (useSpeedProfileCheckBox.isEnabled()) {
1930            info.setUseSpeedProfile(useSpeedProfileCheckBox.isSelected());
1931            info.setStopBySpeedProfile(stopBySpeedProfileCheckBox.isSelected());
1932            info.setStopBySpeedProfileAdjust((float) stopBySpeedProfileAdjustSpinner.getValue());
1933        } else {
1934            info.setUseSpeedProfile(false);
1935            info.setStopBySpeedProfile(false);
1936            info.setStopBySpeedProfileAdjust(1.0f);
1937        }
1938    }
1939
1940   private void initializeRampCombo() {
1941        rampRateBox.removeAllItems();
1942        rampRateBox.addItem(Bundle.getMessage("RAMP_NONE"));
1943        rampRateBox.addItem(Bundle.getMessage("RAMP_FAST"));
1944        rampRateBox.addItem(Bundle.getMessage("RAMP_MEDIUM"));
1945        rampRateBox.addItem(Bundle.getMessage("RAMP_MED_SLOW"));
1946        rampRateBox.addItem(Bundle.getMessage("RAMP_SLOW"));
1947        rampRateBox.addItem(Bundle.getMessage("RAMP_SPEEDPROFILE"));
1948        // Note: the order above must correspond to the numbers in AutoActiveTrain.java
1949    }
1950
1951    /**
1952     * Sets up the RadioButtons and visability of spinner for the allocation method
1953     *
1954     * @param value 0, Allocate by Safe spots, -1, allocate as far as possible Any
1955     *            other value the number of sections to allocate
1956     */
1957    private void setAllocateMethodButtons(int value) {
1958        switch (value) {
1959            case ActiveTrain.ALLOCATE_BY_SAFE_SECTIONS:
1960                allocateBySafeRadioButton.setSelected(true);
1961                allocateCustomSpinner.setVisible(false);
1962                break;
1963            case ActiveTrain.ALLOCATE_AS_FAR_AS_IT_CAN:
1964                allocateAllTheWayRadioButton.setSelected(true);
1965                allocateCustomSpinner.setVisible(false);
1966                break;
1967            default:
1968                allocateNumberOfBlocks.setSelected(true);
1969                allocateCustomSpinner.setVisible(true);
1970                allocateCustomSpinner.setValue(value);
1971        }
1972    }
1973
1974    /*
1975     * Layout block stuff
1976     */
1977    private ArrayList<LayoutBlock> getOccupiedBlockList() {
1978        LayoutBlockManager lBM = jmri.InstanceManager.getDefault(LayoutBlockManager.class);
1979        ArrayList<LayoutBlock> lBlocks = new ArrayList<>();
1980        for (LayoutBlock lB : lBM.getNamedBeanSet()) {
1981            if (lB.getBlock().getState() == Block.OCCUPIED) {
1982                lBlocks.add(lB);
1983            }
1984        }
1985        return lBlocks;
1986    }
1987
1988    private void initializeStartingBlockComboDynamic() {
1989        startingBlockBox.removeAllItems();
1990        startingBlockBoxList.clear();
1991        for (LayoutBlock lB: getOccupiedBlockList()) {
1992            if (!startingBlockBoxList.contains(lB.getBlock())) {
1993                startingBlockBoxList.add(lB.getBlock());
1994                startingBlockBox.addItem(getBlockName(lB.getBlock()));
1995            }
1996        }
1997        JComboBoxUtil.setupComboBoxMaxRows(startingBlockBox);
1998    }
1999
2000    private void initializeViaBlockDynamicCombo() {
2001        String prevValue = (String) viaBlockBox.getSelectedItem();
2002        viaBlockBox.removeActionListener(viaBlockBoxListener);
2003        viaBlockBox.removeAllItems();
2004        viaBlockBoxList.clear();
2005        LayoutBlockManager lBM = jmri.InstanceManager.getDefault(LayoutBlockManager.class);
2006        if (startingBlockBox.getSelectedItem() != null) {
2007            LayoutBlock lBSrc;
2008            if (startingBlockBox.getSelectedIndex() >= 0) {
2009                lBSrc = lBM.getByUserName((String) startingBlockBox.getSelectedItem());
2010                if (lBSrc != null) {
2011                    int rX = lBSrc.getNumberOfNeighbours() - 1;
2012                    for (; rX > -1; rX--) {
2013                        viaBlockBox.addItem(lBSrc.getNeighbourAtIndex(rX).getDisplayName());
2014                        viaBlockBoxList.add(lBSrc.getNeighbourAtIndex(rX));
2015                    }
2016                }
2017            }
2018        }
2019        if (prevValue != null) {
2020            viaBlockBox.setSelectedItem(prevValue);
2021        }
2022        viaBlockBox.addActionListener(viaBlockBoxListener);
2023    }
2024
2025    private void initializeDestinationBlockDynamicCombo() {
2026        destinationBlockBox.removeAllItems();
2027        destinationBlockBoxList.clear();
2028        LayoutBlockManager lBM = jmri.InstanceManager.getDefault(LayoutBlockManager.class);
2029        if (startingBlockBox.getSelectedItem() != null) {
2030            LayoutBlock lBSrc;
2031            if (startingBlockBox.getSelectedIndex() >= 0
2032                    && viaBlockBox.getSelectedIndex() >= 0) {
2033                lBSrc = lBM.getByUserName((String) startingBlockBox.getSelectedItem());
2034                Block b = viaBlockBoxList.get(viaBlockBox.getSelectedIndex());
2035                if (lBSrc != null) {
2036                    int rX = lBSrc.getNumberOfRoutes() - 1;
2037                    for (; rX > -1; rX--) {
2038                        if (lBSrc.getRouteNextBlockAtIndex(rX) == b) {
2039                            destinationBlockBox.addItem(lBSrc.getRouteDestBlockAtIndex(rX).getDisplayName());
2040                            destinationBlockBoxList.add(lBSrc.getRouteDestBlockAtIndex(rX));
2041                        }
2042                    }
2043                }
2044            }
2045        }
2046    }
2047
2048    /*
2049     * Check Advanced routing
2050    */
2051    private boolean checkAdvancedRouting() {
2052        if (!InstanceManager.getDefault(LayoutBlockManager.class).isAdvancedRoutingEnabled()) {
2053            int response = JmriJOptionPane.showConfirmDialog(this, Bundle.getMessage("AdHocNeedsEnableBlockRouting"),
2054                    Bundle.getMessage("AdHocNeedsBlockRouting"), JmriJOptionPane.YES_NO_OPTION);
2055            if (response == 0) {
2056                InstanceManager.getDefault(LayoutBlockManager.class).enableAdvancedRouting(true);
2057                JmriJOptionPane.showMessageDialog(this, Bundle.getMessage("AdhocNeedsBlockRoutingEnabled"));
2058            } else {
2059                return false;
2060            }
2061        }
2062        return true;
2063    }
2064
2065    /*
2066     * ComboBox item.
2067     */
2068    protected static class TrainDetectionItem {
2069
2070        private final String key;
2071        private TrainDetection value;
2072
2073        public TrainDetectionItem(String text, TrainDetection trainDetection ) {
2074            this.key = text;
2075            this.value = trainDetection;
2076        }
2077
2078        @Override
2079        public String toString() {
2080            return key;
2081        }
2082
2083        public String getKey() {
2084            return key;
2085        }
2086
2087        public TrainDetection getValue() {
2088            return value;
2089        }
2090    }
2091
2092    /*
2093     * ComboBox item.
2094     */
2095    protected static class TrainLengthUnitsItem {
2096
2097        private final String key;
2098        private TrainLengthUnits value;
2099
2100        public TrainLengthUnitsItem(String text, TrainLengthUnits trainLength ) {
2101            this.key = text;
2102            this.value = trainLength;
2103        }
2104
2105        @Override
2106        public String toString() {
2107            return key;
2108        }
2109
2110        public String getKey() {
2111            return key;
2112        }
2113
2114        public TrainLengthUnits getValue() {
2115            return value;
2116        }
2117    }
2118
2119    private static final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(ActivateTrainFrame.class);
2120
2121}