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