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