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(true);
661                trainNameField.setVisible(true);
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(true);
671                trainNameField.setVisible(true);
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(true);
694                trainNameField.setVisible(true);
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            trainNameField.setText(r.titleString());
783            if (r.getAttribute("DispatcherTrainType") != null && !r.getAttribute("DispatcherTrainType").equals("")) {
784                trainTypeBox.setSelectedItem(r.getAttribute("DispatcherTrainType"));
785            }
786        } else {
787            setSpeedProfileOptions(false);
788        }
789    }
790
791    private boolean checkResetWhenDone() {
792        if ((!reverseAtEndBox.isSelected()) && resetWhenDoneBox.isSelected()
793                && (!selectedTransit.canBeResetWhenDone())) {
794            resetWhenDoneBox.setSelected(false);
795            JmriJOptionPane.showMessageDialog(initiateFrame, Bundle
796                    .getMessage("NoResetMessage"), Bundle.getMessage("MessageTitle"),
797                    JmriJOptionPane.INFORMATION_MESSAGE);
798            return false;
799        }
800        return true;
801    }
802
803    private void handleDelayStartClick(ActionEvent e) {
804        departureHrSpinner.setVisible(false);
805        departureMinSpinner.setVisible(false);
806        departureTimeLabel.setVisible(false);
807        departureSepLabel.setVisible(false);
808        delaySensor.setVisible(false);
809        resetStartSensorBox.setVisible(false);
810        if (delayedStartBox.getSelectedItem().equals(Bundle.getMessage("DelayedStartTimed"))) {
811            departureHrSpinner.setVisible(true);
812            departureMinSpinner.setVisible(true);
813            departureTimeLabel.setVisible(true);
814            departureSepLabel.setVisible(true);
815        } else if (delayedStartBox.getSelectedItem().equals(Bundle.getMessage("DelayedStartSensor"))) {
816            delaySensor.setVisible(true);
817            resetStartSensorBox.setVisible(true);
818        }
819        initiateFrame.pack(); // to fit extra hh:mm in window
820    }
821
822    private void handleResetWhenDoneClick(ActionEvent e) {
823        delayMinSpinner.setVisible(false);
824        delayMinLabel.setVisible(false);
825        delayedReStartLabel.setVisible(false);
826        delayedReStartBox.setVisible(false);
827        delayReStartSensorLabel.setVisible(false);
828        delayReStartSensor.setVisible(false);
829        resetRestartSensorBox.setVisible(false);
830        if (resetWhenDoneBox.isSelected()) {
831            delayedReStartLabel.setVisible(true);
832            delayedReStartBox.setVisible(true);
833            terminateWhenDoneBox.setSelected(false);
834            if (delayedReStartBox.getSelectedItem().equals(Bundle.getMessage("DelayedStartTimed"))) {
835                delayMinSpinner.setVisible(true);
836                delayMinLabel.setVisible(true);
837            } else if (delayedReStartBox.getSelectedItem().equals(Bundle.getMessage("DelayedStartSensor"))) {
838                delayReStartSensor.setVisible(true);
839                delayReStartSensorLabel.setVisible(true);
840                resetRestartSensorBox.setVisible(true);
841            }
842        } else {
843            terminateWhenDoneBox.setEnabled(true);
844        }
845        initiateFrame.pack();
846    }
847
848    private void handleTerminateWhenDoneBoxClick(ActionEvent e) {
849        if (terminateWhenDoneBox.isSelected()) {
850            refreshNextTrainCombo();
851            resetWhenDoneBox.setSelected(false);
852            terminateWhenDoneDetails.setVisible(true);
853        } else {
854            terminateWhenDoneDetails.setVisible(false);
855            // leave it
856            //nextTrain.setSelectedItem("");
857        }
858    }
859    private void handleReverseAtEndBoxClick(ActionEvent e) {
860        delayReverseMinSpinner.setVisible(false);
861        delayReverseMinLabel.setVisible(false);
862        delayReverseReStartLabel.setVisible(false);
863        reverseDelayedRestartType.setVisible(false);
864        delayReverseReStartSensorLabel.setVisible(false);
865        delayReverseReStartSensor.setVisible(false);
866        delayReverseResetSensorBox.setVisible(false);
867        if (reverseAtEndBox.isSelected()) {
868            delayReverseReStartLabel.setVisible(true);
869            reverseDelayedRestartType.setVisible(true);
870            if (reverseDelayedRestartType.getSelectedItem().equals(Bundle.getMessage("DelayedStartTimed"))) {
871                delayReverseMinSpinner.setVisible(true);
872                delayReverseMinLabel.setVisible(true);
873            } else if (reverseDelayedRestartType.getSelectedItem().equals(Bundle.getMessage("DelayedStartSensor"))) {
874                delayReverseReStartSensor.setVisible(true);
875                delayReStartSensorLabel.setVisible(true);
876                delayReverseResetSensorBox.setVisible(true);
877            }
878        }
879        initiateFrame.pack();
880
881        if (resetWhenDoneBox.isSelected()) {
882            terminateWhenDoneBox.setSelected(false);
883            terminateWhenDoneBox.setEnabled(false);
884        } else {
885            terminateWhenDoneBox.setEnabled(true);
886        }
887    }
888
889    private void handleAutoRunClick(ActionEvent e) {
890        if (autoRunBox.isSelected()) {
891            showAutoRunItems();
892        } else {
893            hideAutoRunItems();
894        }
895        initiateFrame.pack();
896    }
897
898    private void handleStartingBlockSelectionChanged(ActionEvent e) {
899        initializeDestinationBlockCombo();
900        initiateFrame.pack();
901    }
902
903    private void handleAllocateAllTheWayButtonChanged(ActionEvent e) {
904        allocateCustomSpinner.setVisible(false);
905    }
906
907    private void handleAllocateBySafeButtonChanged(ActionEvent e) {
908        allocateCustomSpinner.setVisible(false);
909    }
910
911    private void handleAllocateNumberOfBlocksButtonChanged(ActionEvent e) {
912        allocateCustomSpinner.setVisible(true);
913    }
914
915    private void cancelInitiateTrain(ActionEvent e) {
916        _dispatcher.newTrainDone(null);
917    }
918
919    /**
920     * Handles press of "Add New Train" button by edit-checking populated values
921     * then (if no errors) creating an ActiveTrain and (optionally) an
922     * AutoActiveTrain
923     */
924    private void addNewTrain(ActionEvent e) {
925        // get information
926        if (selectedTransit == null) {
927            // no transits available
928            JmriJOptionPane.showMessageDialog(initiateFrame, Bundle.getMessage("Error15"),
929                    Bundle.getMessage("ErrorTitle"), JmriJOptionPane.ERROR_MESSAGE);
930            cancelInitiateTrain(null);
931            return;
932        }
933        String transitName = selectedTransit.getDisplayName();
934        String trainName = "";
935        int index = startingBlockBox.getSelectedIndex();
936        if (index < 0) {
937            return;
938        }
939        String startBlockName = startingBlockBoxList.get(index).getDisplayName();
940        int startBlockSeq = startingBlockSeqList.get(index).intValue();
941        index = destinationBlockBox.getSelectedIndex();
942        if (index < 0) {
943            return;
944        }
945        String endBlockName = destinationBlockBoxList.get(index).getDisplayName();
946        int endBlockSeq = destinationBlockSeqList.get(index).intValue();
947        boolean autoRun = autoRunBox.isSelected();
948        if (!checkResetWhenDone()) {
949            return;
950        }
951        boolean resetWhenDone = resetWhenDoneBox.isSelected();
952        boolean reverseAtEnd = reverseAtEndBox.isSelected();
953        index = trainDetectionComboBox.getSelectedIndex();
954        if (index < 0) {
955            return;
956        }
957        TrainDetection trainDetection = ((TrainDetectionItem)trainDetectionComboBox.getSelectedItem()).value;
958        int allocateMethod = 3;
959        if (allocateAllTheWayRadioButton.isSelected()) {
960            allocateMethod = ActiveTrain.ALLOCATE_AS_FAR_AS_IT_CAN;
961        } else if (allocateBySafeRadioButton.isSelected()) {
962            allocateMethod = ActiveTrain.ALLOCATE_BY_SAFE_SECTIONS;
963        } else {
964            allocateMethod = (Integer) allocateCustomSpinner.getValue();
965        }
966        int delayedStart = delayModeFromBox(delayedStartBox);
967        int delayedReStart = delayModeFromBox(delayedReStartBox);
968        int delayedReverseReStart = delayModeFromBox(reverseDelayedRestartType);
969        int departureTimeHours = 8;
970        departureTimeHours = (Integer) departureHrSpinner.getValue();
971        int departureTimeMinutes = 8;
972        departureTimeMinutes = (Integer) departureMinSpinner.getValue();
973        int delayRestartMinutes = 0;
974        delayRestartMinutes = (Integer) delayMinSpinner.getValue();
975        if ((delayRestartMinutes < 0)) {
976            JmriJOptionPane.showMessageDialog(initiateFrame, delayMinSpinner.getValue(),
977                    Bundle.getMessage("ErrorTitle"), JmriJOptionPane.ERROR_MESSAGE);
978            log.warn("Range error in Delay Restart Time Minutes field");
979            return;
980        }
981        int delayReverseRestartMinutes = 0;
982        delayReverseRestartMinutes = (Integer) delayReverseMinSpinner.getValue();
983        if ((delayReverseRestartMinutes < 0)) {
984            JmriJOptionPane.showMessageDialog(initiateFrame, delayReverseMinSpinner.getValue(),
985                    Bundle.getMessage("ErrorTitle"), JmriJOptionPane.ERROR_MESSAGE);
986            log.warn("Range error in Reverse Delay Restart Time Minutes field");
987            return;
988        }
989        int tSource = 0;
990        String dccAddress = "unknown";
991        switch (_TrainsFrom) {
992            case TRAINSFROMROSTER:
993                index = rosterComboBox.getSelectedIndex();
994                if (index < 1) { // first item is the "Select Loco" message
995                    // no train selected
996                    JmriJOptionPane.showMessageDialog(initiateFrame, Bundle.getMessage("Error41"),
997                            Bundle.getMessage("ErrorTitle"), JmriJOptionPane.ERROR_MESSAGE);
998                    return;
999                }
1000                RosterEntry r = (RosterEntry) rosterComboBox.getSelectedItem();
1001                dccAddress = r.getDccAddress();
1002                if (trainNameField.getText().isEmpty()) {
1003                    JmriJOptionPane.showMessageDialog(initiateFrame, Bundle.getMessage(
1004                            "Error45", dccAddress), Bundle.getMessage("ErrorTitle"),
1005                            JmriJOptionPane.ERROR_MESSAGE);
1006                    return;
1007                }
1008                trainName=trainNameField.getText();
1009                if (!_dispatcher.isTrainFree(trainName)) {
1010                    // train name is already in use by an Active Train
1011                    JmriJOptionPane.showMessageDialog(initiateFrame, Bundle.getMessage(
1012                            "Error24", trainName), Bundle.getMessage("ErrorTitle"),
1013                            JmriJOptionPane.ERROR_MESSAGE);
1014                    return;
1015                }
1016                trainName = trainNameField.getText();
1017                if (!isAddressFree(r.getDccLocoAddress().getNumber())) {
1018                    // DCC address is already in use by an Active Train
1019                    JmriJOptionPane.showMessageDialog(initiateFrame, Bundle.getMessage(
1020                            "Error40", dccAddress), Bundle.getMessage("ErrorTitle"),
1021                            JmriJOptionPane.ERROR_MESSAGE);
1022                    return;
1023                }
1024
1025                tSource = ActiveTrain.ROSTER;
1026
1027                if (trainTypeBox.getSelectedIndex() != 0 &&
1028                        (r.getAttribute("DispatcherTrainType") == null ||
1029                                !r.getAttribute("DispatcherTrainType").equals("" + trainTypeBox.getSelectedItem()))) {
1030                    r.putAttribute("DispatcherTrainType", "" + trainTypeBox.getSelectedItem());
1031                    r.updateFile();
1032                    Roster.getDefault().writeRoster();
1033                }
1034                break;
1035            case TRAINSFROMOPS:
1036                tSource = ActiveTrain.OPERATIONS;
1037                index = trainSelectBox.getSelectedIndex();
1038                if (index < 1) { // first item is Select Train
1039                    // Train not selected
1040                    JmriJOptionPane.showMessageDialog(initiateFrame, Bundle.getMessage("Error42"),
1041                            Bundle.getMessage("ErrorTitle"), JmriJOptionPane.ERROR_MESSAGE);
1042                    return;
1043                }
1044                if (trainNameField.getText().isEmpty()) {
1045                    JmriJOptionPane.showMessageDialog(initiateFrame, Bundle.getMessage(
1046                            "Error45", dccAddress), Bundle.getMessage("ErrorTitle"),
1047                            JmriJOptionPane.ERROR_MESSAGE);
1048                    return;
1049                }
1050                if (!_dispatcher.isTrainFree(trainName)) {
1051                    // train name is already in use by an Active Train
1052                    JmriJOptionPane.showMessageDialog(initiateFrame, Bundle.getMessage(
1053                            "Error24", trainName), Bundle.getMessage("ErrorTitle"),
1054                            JmriJOptionPane.ERROR_MESSAGE);
1055                    return;
1056                }
1057                trainName = trainSelectBox.getSelectedItem().toString();
1058                dccAddress = getDCCAddressFromSpinner();
1059                if (dccAddress == null) {
1060                    return;
1061                }
1062                break;
1063            case TRAINSFROMUSER:
1064                trainName = trainNameField.getText();
1065                if ((trainName == null) || trainName.equals("")) {
1066                    // no train name entered
1067                    JmriJOptionPane.showMessageDialog(initiateFrame, Bundle.getMessage("Error14"),
1068                            Bundle.getMessage("ErrorTitle"), JmriJOptionPane.ERROR_MESSAGE);
1069                    return;
1070                }
1071                if (trainNameField.getText().isEmpty()) {
1072                    JmriJOptionPane.showMessageDialog(initiateFrame, Bundle.getMessage(
1073                            "Error45", dccAddress), Bundle.getMessage("ErrorTitle"),
1074                            JmriJOptionPane.ERROR_MESSAGE);
1075                    return;
1076                }
1077                if (!_dispatcher.isTrainFree(trainName)) {
1078                    // train name is already in use by an Active Train
1079                    JmriJOptionPane.showMessageDialog(initiateFrame, Bundle.getMessage(
1080                            "Error24", trainName), Bundle.getMessage("ErrorTitle"),
1081                            JmriJOptionPane.ERROR_MESSAGE);
1082                    return;
1083                }
1084                dccAddress = getDCCAddressFromSpinner();
1085                if (dccAddress == null) {
1086                    return;
1087                }
1088                tSource = ActiveTrain.USER;
1089                break;
1090            case TRAINSFROMSETLATER:
1091            default:
1092                trainName = "";
1093        }
1094        int priority = 5;
1095        priority = (Integer) prioritySpinner.getValue();
1096        int trainType = trainTypeBox.getSelectedIndex();
1097        if (autoRunBox.isSelected()) {
1098            if (!readAutoRunItems()) {
1099                return;
1100            }
1101        }
1102
1103        // create a new Active Train
1104        ActiveTrain at = _dispatcher.createActiveTrain(transitName, trainName, tSource, startBlockName,
1105                startBlockSeq, endBlockName, endBlockSeq, autoRun, dccAddress, priority,
1106                resetWhenDone, reverseAtEnd,  true, initiateFrame, allocateMethod);
1107        if (at == null) {
1108            return;  // error message sent by createActiveTrain
1109        }
1110        if (tSource == ActiveTrain.ROSTER) {
1111            at.setRosterEntry((RosterEntry)rosterComboBox.getSelectedItem());
1112        }
1113        at.setTrainDetection(trainDetection);
1114        at.setAllocateMethod(allocateMethod);
1115        at.setDelayedStart(delayedStart);
1116        at.setDelayedRestart(delayedReStart);
1117        at.setDepartureTimeHr(departureTimeHours);
1118        at.setDepartureTimeMin(departureTimeMinutes);
1119        at.setRestartDelay(delayRestartMinutes);
1120        at.setDelaySensor(delaySensor.getSelectedItem());
1121        at.setReverseDelayRestart(delayedReverseReStart);
1122        at.setReverseRestartDelay(delayReverseRestartMinutes);
1123        at.setReverseDelaySensor(delayReverseReStartSensor.getSelectedItem());
1124        at.setReverseResetRestartSensor(delayReverseResetSensorBox.isSelected());
1125        if ((_dispatcher.isFastClockTimeGE(departureTimeHours, departureTimeMinutes) && delayedStart != ActiveTrain.SENSORDELAY)
1126                || delayedStart == ActiveTrain.NODELAY) {
1127            at.setStarted();
1128        }
1129        at.setRestartSensor(delayReStartSensor.getSelectedItem());
1130        at.setResetRestartSensor(resetRestartSensorBox.isSelected());
1131        at.setTrainType(trainType);
1132        at.setTerminateWhenDone(terminateWhenDoneBox.isSelected());
1133        at.setNextTrain(_nextTrain);
1134        if (autoRunBox.isSelected()) {
1135            AutoActiveTrain aat = new AutoActiveTrain(at);
1136            setAutoRunItems(aat);
1137            _dispatcher.getAutoTrainsFrame().addAutoActiveTrain(aat);
1138            if (!aat.initialize()) {
1139                JmriJOptionPane.showMessageDialog(initiateFrame, Bundle.getMessage(
1140                        "Error27", at.getTrainName()), Bundle.getMessage("MessageTitle"),
1141                        JmriJOptionPane.INFORMATION_MESSAGE);
1142            }
1143        }
1144        _dispatcher.allocateNewActiveTrain(at);
1145        _dispatcher.newTrainDone(at);
1146    }
1147
1148    private String getDCCAddressFromSpinner() {
1149        int address = (Integer) dccAddressSpinner.getValue(); // SpinnerNumberModel
1150                                                          // limits
1151                                                          // address to
1152                                                          // 1 - 9999
1153                                                          // inclusive
1154        if (!isAddressFree(address)) {
1155            // DCC address is already in use by an Active Train
1156            JmriJOptionPane.showMessageDialog(initiateFrame, Bundle.getMessage(
1157                    "Error40", address), Bundle.getMessage("ErrorTitle"),
1158                    JmriJOptionPane.ERROR_MESSAGE);
1159            return null;
1160        }
1161        return String.valueOf(address);
1162    }
1163
1164    private void initializeFreeTransitsCombo(List<Transit> transitList) {
1165        Set<Transit> excludeTransits = new HashSet<>();
1166        for (Transit t : _TransitManager.getNamedBeanSet()) {
1167            if (t.getState() != Transit.IDLE) {
1168                excludeTransits.add(t);
1169            }
1170        }
1171        transitSelectBox.setExcludedItems(excludeTransits);
1172        JComboBoxUtil.setupComboBoxMaxRows(transitSelectBox);
1173
1174        if (transitSelectBox.getItemCount() > 0) {
1175            transitSelectBox.setSelectedIndex(0);
1176            selectedTransit = transitSelectBox.getItemAt(0);
1177        } else {
1178            selectedTransit = null;
1179        }
1180    }
1181
1182    private void initializeFreeRosterEntriesCombo() {
1183        rosterComboBox.update();
1184        // remove used entries
1185        for (int ix = rosterComboBox.getItemCount() - 1; ix > 1; ix--) {  // remove from back first item is the "select loco" message
1186            if ( !isAddressFree( ((RosterEntry)rosterComboBox.getItemAt(ix)).getDccLocoAddress().getNumber() ) ) {
1187                rosterComboBox.removeItemAt(ix);
1188            }
1189        }
1190    }
1191
1192    private void initializeFreeTrainsCombo() {
1193        ActionListener[] als = trainSelectBox.getActionListeners();
1194        for ( ActionListener al: als) {
1195            trainSelectBox.removeActionListener(al);
1196        }
1197        trainSelectBox.removeAllItems();
1198        trainSelectBox.addItem("Select Train");
1199        // initialize free trains from operations
1200        List<Train> trains = jmri.InstanceManager.getDefault(TrainManager.class).getTrainsByNameList();
1201        if (trains.size() > 0) {
1202            for (int i = 0; i < trains.size(); i++) {
1203                Train t = trains.get(i);
1204                if (t != null) {
1205                    String tName = t.getName();
1206                    if (_dispatcher.isTrainFree(tName)) {
1207                        trainSelectBox.addItem(t);
1208                    }
1209                }
1210            }
1211        }
1212        for ( ActionListener al: als) {
1213            trainSelectBox.addActionListener(al);
1214        }
1215    }
1216
1217    /**
1218     * Sets the labels and inputs for speed profile running
1219     * @param b True if the roster entry has valid speed profile else false
1220     */
1221    private void setSpeedProfileOptions(boolean b) {
1222        useSpeedProfileLabel.setEnabled(b);
1223        useSpeedProfileCheckBox.setEnabled(b);
1224        stopBySpeedProfileLabel.setEnabled(b);
1225        stopBySpeedProfileCheckBox.setEnabled(b);
1226        stopBySpeedProfileAdjustLabel.setEnabled(b);
1227        stopBySpeedProfileAdjustSpinner.setEnabled(b);
1228        if (!b) {
1229            useSpeedProfileCheckBox.setSelected(false);
1230            stopBySpeedProfileCheckBox.setSelected(false);
1231            _useSpeedProfile = false;
1232            _stopBySpeedProfile = false;
1233        }
1234    }
1235
1236
1237    private boolean isAddressFree(int addr) {
1238        for (int j = 0; j < _ActiveTrainsList.size(); j++) {
1239            ActiveTrain at = _ActiveTrainsList.get(j);
1240            if (addr == Integer.parseInt(at.getDccAddress())) {
1241                return false;
1242            }
1243        }
1244        return true;
1245    }
1246
1247    private void initializeStartingBlockCombo() {
1248        startingBlockBox.removeAllItems();
1249        startingBlockBoxList.clear();
1250        if (!inTransitBox.isSelected() && selectedTransit.getEntryBlocksList().isEmpty()) {
1251            inTransitBox.setSelected(true);
1252        }
1253        if (inTransitBox.isSelected()) {
1254            startingBlockBoxList = selectedTransit.getInternalBlocksList();
1255        } else {
1256            startingBlockBoxList = selectedTransit.getEntryBlocksList();
1257        }
1258        startingBlockSeqList = selectedTransit.getBlockSeqList();
1259        boolean found = false;
1260        for (int i = 0; i < startingBlockBoxList.size(); i++) {
1261            Block b = startingBlockBoxList.get(i);
1262            int seq = startingBlockSeqList.get(i).intValue();
1263            startingBlockBox.addItem(getBlockName(b) + "-" + seq);
1264            if (!found && b.getState() == Block.OCCUPIED) {
1265                startingBlockBox.setSelectedItem(getBlockName(b) + "-" + seq);
1266                found = true;
1267            }
1268        }
1269        JComboBoxUtil.setupComboBoxMaxRows(startingBlockBox);
1270    }
1271
1272    private void initializeDestinationBlockCombo() {
1273        destinationBlockBox.removeAllItems();
1274        destinationBlockBoxList.clear();
1275        int index = startingBlockBox.getSelectedIndex();
1276        if (index < 0) {
1277            return;
1278        }
1279        Block startBlock = startingBlockBoxList.get(index);
1280        destinationBlockBoxList = selectedTransit.getDestinationBlocksList(
1281                startBlock, inTransitBox.isSelected());
1282        destinationBlockSeqList = selectedTransit.getDestBlocksSeqList();
1283        for (int i = 0; i < destinationBlockBoxList.size(); i++) {
1284            Block b = destinationBlockBoxList.get(i);
1285            String bName = getBlockName(b);
1286            if (selectedTransit.getBlockCount(b) > 1) {
1287                int seq = destinationBlockSeqList.get(i).intValue();
1288                bName = bName + "-" + seq;
1289            }
1290            destinationBlockBox.addItem(bName);
1291        }
1292        JComboBoxUtil.setupComboBoxMaxRows(destinationBlockBox);
1293    }
1294
1295    private String getBlockName(Block b) {
1296        if (b != null) {
1297            return b.getDisplayName();
1298        }
1299        return " ";
1300    }
1301
1302    protected void showActivateFrame() {
1303        if (initiateFrame != null) {
1304            initializeFreeTransitsCombo(new ArrayList<Transit>());
1305            initiateFrame.setVisible(true);
1306        } else {
1307            _dispatcher.newTrainDone(null);
1308        }
1309    }
1310
1311    public void showActivateFrame(RosterEntry re) {
1312        showActivateFrame();
1313    }
1314
1315    private void loadTrainInfo(ActionEvent e) {
1316        String[] names = _tiFile.getTrainInfoFileNames();
1317        TrainInfo info = null;
1318        if (names.length > 0) {
1319            //prompt user to select a single train info filename from directory list
1320            Object selName = JmriJOptionPane.showInputDialog(initiateFrame,
1321                    Bundle.getMessage("LoadTrainChoice"), Bundle.getMessage("LoadTrainTitle"),
1322                    JmriJOptionPane.QUESTION_MESSAGE, null, names, names[0]);
1323            if ((selName == null) || (((String) selName).equals(""))) {
1324                return;
1325            }
1326            //read xml data from selected filename and move it into the new train dialog box
1327            _trainInfoName = (String) selName;
1328            try {
1329                info = _tiFile.readTrainInfo((String) selName);
1330                if (info != null) {
1331                    // process the information just read
1332                    trainInfoToDialog(info);
1333                }
1334            } catch (java.io.IOException ioe) {
1335                log.error("IO Exception when reading train info file", ioe);
1336            } catch (org.jdom2.JDOMException jde) {
1337                log.error("JDOM Exception when reading train info file", jde);
1338            }
1339        }
1340        handleDelayStartClick(null);
1341        handleReverseAtEndBoxClick(null);
1342    }
1343
1344    private void saveTrainInfo(ActionEvent e, boolean locoOptional) {
1345        TrainInfo info = null;
1346        try {
1347            info = dialogToTrainInfo(locoOptional);
1348        } catch (IllegalArgumentException ide) {
1349            JmriJOptionPane.showMessageDialog(initiateFrame, ide.getMessage(),
1350                    Bundle.getMessage("ErrorTitle"), JmriJOptionPane.ERROR_MESSAGE);
1351            return;
1352        }
1353        // get file name
1354        String eName = "";
1355        eName = JmriJOptionPane.showInputDialog(initiateFrame,
1356                Bundle.getMessage("EnterFileName") + " :", _trainInfoName);
1357        if (eName == null) {  //Cancel pressed
1358            return;
1359        }
1360        if (eName.length() < 1) {
1361            JmriJOptionPane.showMessageDialog(initiateFrame, Bundle.getMessage("Error25"),
1362                    Bundle.getMessage("ErrorTitle"), JmriJOptionPane.ERROR_MESSAGE);
1363            return;
1364        }
1365        String fileName = normalizeXmlFileName(eName);
1366        _trainInfoName = fileName;
1367        // check if train info file name is in use
1368        String[] names = _tiFile.getTrainInfoFileNames();
1369        if (names.length > 0) {
1370            boolean found = false;
1371            for (int i = 0; i < names.length; i++) {
1372                if (fileName.equals(names[i])) {
1373                    found = true;
1374                }
1375            }
1376            if (found) {
1377                // file by that name is already present
1378                int selectedValue = JmriJOptionPane.showOptionDialog(initiateFrame,
1379                        Bundle.getMessage("Question3", fileName),
1380                        Bundle.getMessage("WarningTitle"), JmriJOptionPane.DEFAULT_OPTION,
1381                        JmriJOptionPane.QUESTION_MESSAGE, null,
1382                        new Object[]{Bundle.getMessage("ButtonReplace"),Bundle.getMessage("ButtonNo")},
1383                        Bundle.getMessage("ButtonNo"));
1384                if (selectedValue != 0 ) { // array position 0 , replace not selected
1385                    return;   // return without writing if "No" response
1386                }
1387            }
1388        }
1389        // write the Train Info file
1390        try {
1391            _tiFile.writeTrainInfo(info, fileName);
1392        } //catch (org.jdom2.JDOMException jde) {
1393        // log.error("JDOM exception writing Train Info: "+jde);
1394        //}
1395        catch (java.io.IOException ioe) {
1396            log.error("IO exception writing Train Info", ioe);
1397        }
1398    }
1399
1400    private void deleteTrainInfo(ActionEvent e) {
1401        String[] names = _tiFile.getTrainInfoFileNames();
1402        if (names.length > 0) {
1403            Object selName = JmriJOptionPane.showInputDialog(initiateFrame,
1404                    Bundle.getMessage("DeleteTrainChoice"), Bundle.getMessage("DeleteTrainTitle"),
1405                    JmriJOptionPane.QUESTION_MESSAGE, null, names, names[0]);
1406            if ((selName == null) || (((String) selName).equals(""))) {
1407                return;
1408            }
1409            _tiFile.deleteTrainInfoFile((String) selName);
1410        }
1411    }
1412
1413    private void trainInfoToDialog(TrainInfo info) {
1414        try {
1415            transitSelectBox.setSelectedItemByName(info.getTransitName());
1416        } catch (Exception ex) {
1417            log.warn("Transit {} from file not in Transit menu", info.getTransitName());
1418            JmriJOptionPane.showMessageDialog(initiateFrame,
1419                    Bundle.getMessage("TransitWarn", info.getTransitName()),
1420                    null, JmriJOptionPane.WARNING_MESSAGE);
1421        }
1422        _TrainsFrom = info.getTrainsFrom();
1423        switch (_TrainsFrom) {
1424            case TRAINSFROMROSTER:
1425                radioTrainsFromRoster.setSelected(true);
1426                if (!setRosterComboBox(rosterComboBox, info.getRosterId())) {
1427                    log.warn("Roster {} from file not in Roster Combo", info.getRosterId());
1428                    JmriJOptionPane.showMessageDialog(initiateFrame,
1429                            Bundle.getMessage("TrainWarn", info.getRosterId()),
1430                            null, JmriJOptionPane.WARNING_MESSAGE);
1431                }
1432                break;
1433            case TRAINSFROMOPS:
1434                radioTrainsFromOps.setSelected(true);
1435                if (!setTrainComboBox(trainSelectBox, info.getTrainName())) {
1436                    log.warn("Train {} from file not in Train Combo", info.getTrainName());
1437                    JmriJOptionPane.showMessageDialog(initiateFrame,
1438                            Bundle.getMessage("TrainWarn", info.getTrainName()),
1439                            null, JmriJOptionPane.WARNING_MESSAGE);
1440                }
1441                break;
1442            case TRAINSFROMUSER:
1443                radioTrainsFromUser.setSelected(true);
1444                dccAddressSpinner.setValue(Integer.parseInt(info.getDccAddress()));
1445                break;
1446            case TRAINSFROMSETLATER:
1447            default:
1448                radioTrainsFromSetLater.setSelected(true);
1449        }
1450        trainNameField.setText(info.getTrainUserName());
1451        trainDetectionComboBox.setSelectedItemByValue(info.getTrainDetection());
1452        inTransitBox.setSelected(info.getTrainInTransit());
1453        initializeStartingBlockCombo();
1454        initializeDestinationBlockCombo();
1455        setComboBox(startingBlockBox, info.getStartBlockName());
1456        setComboBox(destinationBlockBox, info.getDestinationBlockName());
1457        prioritySpinner.setValue(info.getPriority());
1458        resetWhenDoneBox.setSelected(info.getResetWhenDone());
1459        reverseAtEndBox.setSelected(info.getReverseAtEnd());
1460        setDelayModeBox(info.getDelayedStart(), delayedStartBox);
1461        //delayedStartBox.setSelected(info.getDelayedStart());
1462        departureHrSpinner.setValue(info.getDepartureTimeHr());
1463        departureMinSpinner.setValue(info.getDepartureTimeMin());
1464        delaySensor.setSelectedItem(info.getDelaySensor());
1465        resetStartSensorBox.setSelected(info.getResetStartSensor());
1466        setDelayModeBox(info.getDelayedRestart(), delayedReStartBox);
1467        delayMinSpinner.setValue(info.getRestartDelayMin());
1468        delayReStartSensor.setSelectedItem(info.getRestartSensor());
1469        resetRestartSensorBox.setSelected(info.getResetRestartSensor());
1470
1471        resetStartSensorBox.setSelected(info.getResetStartSensor());
1472        setDelayModeBox(info.getReverseDelayedRestart(), reverseDelayedRestartType);
1473        delayReverseMinSpinner.setValue(info.getReverseRestartDelayMin());
1474        delayReverseReStartSensor.setSelectedItem(info.getReverseRestartSensor());
1475        delayReverseResetSensorBox.setSelected(info.getReverseResetRestartSensor());
1476
1477        terminateWhenDoneBox.setSelected(info.getTerminateWhenDone());
1478        nextTrain.setSelectedIndex(-1);
1479
1480        try {
1481            nextTrain.setSelectedItem(info.getNextTrain());
1482        } catch (Exception ex){
1483            nextTrain.setSelectedIndex(-1);
1484        }
1485        handleTerminateWhenDoneBoxClick(null);
1486        setComboBox(trainTypeBox, info.getTrainType());
1487        autoRunBox.setSelected(info.getAutoRun());
1488        loadAtStartupBox.setSelected(info.getLoadAtStartup());
1489        setAllocateMethodButtons(info.getAllocationMethod());
1490        autoTrainInfoToDialog(info);
1491    }
1492
1493    private TrainInfo dialogToTrainInfo(boolean locoOptional) throws IllegalArgumentException {
1494        TrainInfo info = new TrainInfo();
1495        int index = transitSelectBox.getSelectedIndex();
1496        if (index < 0) {
1497            throw new IllegalArgumentException(Bundle.getMessage("Error44"));
1498        } else {
1499            info.setTransitName(transitSelectBox.getSelectedItem().getDisplayName());
1500            info.setTransitId(transitSelectBox.getSelectedItem().getDisplayName());
1501        }
1502        switch (_TrainsFrom) {
1503            case TRAINSFROMROSTER:
1504                if (rosterComboBox.getSelectedIndex() < 1 ) {
1505                    throw new IllegalArgumentException(Bundle.getMessage("Error41"));
1506                }
1507                info.setRosterId(((RosterEntry) rosterComboBox.getSelectedItem()).getId());
1508                info.setDccAddress(((RosterEntry) rosterComboBox.getSelectedItem()).getDccAddress());
1509                break;
1510            case TRAINSFROMOPS:
1511                if (trainSelectBox.getSelectedIndex() < 1) {
1512                    throw new IllegalArgumentException(Bundle.getMessage("Error42"));
1513                }
1514                info.setTrainName(((Train) trainSelectBox.getSelectedItem()).getId());
1515                info.setDccAddress(String.valueOf(dccAddressSpinner.getValue()));
1516                break;
1517            case TRAINSFROMUSER:
1518                if (trainNameField.getText().isEmpty()) {
1519                    throw new IllegalArgumentException(Bundle.getMessage("Error22"));
1520                }
1521                info.setDccAddress(String.valueOf(dccAddressSpinner.getValue()));
1522                break;
1523            case TRAINSFROMSETLATER:
1524            default:
1525                info.setTrainName("");
1526                info.setDccAddress("");
1527        }
1528        info.setTrainUserName(trainNameField.getText());
1529        info.setTrainInTransit(inTransitBox.isSelected());
1530        info.setStartBlockName((String) startingBlockBox.getSelectedItem());
1531        index = startingBlockBox.getSelectedIndex();
1532        if (index < 0) {
1533            throw new IllegalArgumentException(Bundle.getMessage("Error13"));
1534        } else {
1535            info.setStartBlockId(startingBlockBoxList.get(index).getDisplayName());
1536            info.setStartBlockSeq(startingBlockSeqList.get(index).intValue());
1537        }
1538        info.setDestinationBlockName((String) destinationBlockBox.getSelectedItem());
1539        index = destinationBlockBox.getSelectedIndex();
1540        if (index < 0) {
1541            throw new IllegalArgumentException(Bundle.getMessage("Error8"));
1542        } else {
1543            info.setDestinationBlockId(destinationBlockBoxList.get(index).getDisplayName());
1544            info.setDestinationBlockSeq(destinationBlockSeqList.get(index).intValue());
1545        }
1546        info.setTrainsFrom(_TrainsFrom);
1547        info.setPriority((Integer) prioritySpinner.getValue());
1548        info.setTrainDetection(((TrainDetectionItem)trainDetectionComboBox.getSelectedItem()).value);
1549        info.setResetWhenDone(resetWhenDoneBox.isSelected());
1550        info.setReverseAtEnd(reverseAtEndBox.isSelected());
1551        info.setDelayedStart(delayModeFromBox(delayedStartBox));
1552        info.setDelaySensorName(delaySensor.getSelectedItemDisplayName());
1553        info.setResetStartSensor(resetStartSensorBox.isSelected());
1554        info.setDepartureTimeHr((Integer) departureHrSpinner.getValue());
1555        info.setDepartureTimeMin((Integer) departureMinSpinner.getValue());
1556        info.setTrainType((String) trainTypeBox.getSelectedItem());
1557        info.setAutoRun(autoRunBox.isSelected());
1558        info.setLoadAtStartup(loadAtStartupBox.isSelected());
1559        info.setAllocateAllTheWay(false); // force to false next field is now used.
1560        if (allocateAllTheWayRadioButton.isSelected()) {
1561            info.setAllocationMethod(ActiveTrain.ALLOCATE_AS_FAR_AS_IT_CAN);
1562        } else if (allocateBySafeRadioButton.isSelected()) {
1563            info.setAllocationMethod(ActiveTrain.ALLOCATE_BY_SAFE_SECTIONS);
1564        } else {
1565            info.setAllocationMethod((Integer) allocateCustomSpinner.getValue());
1566        }
1567        info.setDelayedRestart(delayModeFromBox(delayedReStartBox));
1568        info.setRestartSensorName(delayReStartSensor.getSelectedItemDisplayName());
1569        info.setResetRestartSensor(resetRestartSensorBox.isSelected());
1570        info.setRestartDelayMin((Integer) delayMinSpinner.getValue());
1571
1572        info.setReverseDelayedRestart(delayModeFromBox(reverseDelayedRestartType));
1573        info.setReverseRestartSensorName(delayReverseReStartSensor.getSelectedItemDisplayName());
1574        info.setReverseResetRestartSensor(delayReverseResetSensorBox.isSelected());
1575        info.setReverseRestartDelayMin((Integer) delayReverseMinSpinner.getValue());
1576
1577        info.setTerminateWhenDone(terminateWhenDoneBox.isSelected());
1578        if (nextTrain.getSelectedIndex() > 0 ) {
1579            info.setNextTrain((String)nextTrain.getSelectedItem());
1580        } else {
1581            info.setNextTrain("None");
1582        }
1583        autoRunItemsToTrainInfo(info);
1584        return info;
1585    }
1586
1587    private boolean setRosterComboBox(RosterEntryComboBox box, String txt) {
1588        boolean found = false;
1589        for (int i = 1; i < box.getItemCount(); i++) {
1590            if (txt.equals(((RosterEntry) box.getItemAt(i)).getId())) {
1591                box.setSelectedIndex(i);
1592                found = true;
1593                break;
1594            }
1595        }
1596        if (!found && box.getItemCount() > 0) {
1597            box.setSelectedIndex(0);
1598        }
1599        return found;
1600    }
1601
1602    // Normalizes a suggested xml file name.  Returns null string if a valid name cannot be assembled
1603    private String normalizeXmlFileName(String name) {
1604        if (name.length() < 1) {
1605            return "";
1606        }
1607        String newName = name;
1608        // strip off .xml or .XML if present
1609        if ((name.endsWith(".xml")) || (name.endsWith(".XML"))) {
1610            newName = name.substring(0, name.length() - 4);
1611            if (newName.length() < 1) {
1612                return "";
1613            }
1614        }
1615        // replace all non-alphanumeric characters with underscore
1616        newName = newName.replaceAll("[\\W]", "_");
1617        return (newName + ".xml");
1618    }
1619
1620    private boolean setTrainComboBox(JComboBox<Object> box, String txt) {
1621        boolean found = false;
1622        for (int i = 1; i < box.getItemCount(); i++) { //skip the select train item
1623            if (txt.equals(box.getItemAt(i).toString())) {
1624                box.setSelectedIndex(i);
1625                found = true;
1626                break;
1627            }
1628        }
1629        if (!found && box.getItemCount() > 0) {
1630            box.setSelectedIndex(0);
1631        }
1632        return found;
1633    }
1634
1635    private boolean setComboBox(JComboBox<String> box, String txt) {
1636        boolean found = false;
1637        for (int i = 0; i < box.getItemCount(); i++) {
1638            if (txt.equals(box.getItemAt(i))) {
1639                box.setSelectedIndex(i);
1640                found = true;
1641                break;
1642            }
1643        }
1644        if (!found && box.getItemCount() > 0) {
1645            box.setSelectedIndex(0);
1646        }
1647        return found;
1648    }
1649
1650    int delayModeFromBox(JComboBox<String> box) {
1651        String mode = (String) box.getSelectedItem();
1652        int result = jmri.util.StringUtil.getStateFromName(mode, delayedStartInt, delayedStartString);
1653
1654        if (result < 0) {
1655            log.warn("unexpected mode string in turnoutMode: {}", mode);
1656            throw new IllegalArgumentException();
1657        }
1658        return result;
1659    }
1660
1661    void setDelayModeBox(int mode, JComboBox<String> box) {
1662        String result = jmri.util.StringUtil.getNameFromState(mode, delayedStartInt, delayedStartString);
1663        box.setSelectedItem(result);
1664    }
1665
1666    /**
1667     * The following are for items that are only for automatic running of
1668     * ActiveTrains They are isolated here to simplify changing them in the
1669     * future.
1670     * <ul>
1671     * <li>initializeAutoRunItems - initializes the display of auto run items in
1672     * this window
1673     * <li>initializeAutoRunValues - initializes the values of auto run items
1674     * from values in a saved train info file hideAutoRunItems - hides all auto
1675     * run items in this window showAutoRunItems - shows all auto run items in
1676     * this window
1677     * <li>autoTrainInfoToDialog - gets auto run items from a train info, puts
1678     * values in items, and initializes auto run dialog items
1679     * <li>autoTrainItemsToTrainInfo - copies values of auto run items to train
1680     * info for saving to a file
1681     * <li>readAutoRunItems - reads and checks values of all auto run items.
1682     * returns true if OK, sends appropriate messages and returns false if not
1683     * OK
1684     * <li>setAutoRunItems - sets the user entered auto run items in the new
1685     * AutoActiveTrain
1686     * </ul>
1687     */
1688    // auto run items in ActivateTrainFrame
1689    private final JPanel pa1 = new JPanel();
1690    private final JLabel speedFactorLabel = new JLabel(Bundle.getMessage("SpeedFactorLabel"));
1691    private final JSpinner speedFactorSpinner = new JSpinner();
1692    private final JLabel maxSpeedLabel = new JLabel(Bundle.getMessage("MaxSpeedLabel"));
1693    private final JSpinner maxSpeedSpinner = new JSpinner();
1694    private final JPanel pa2 = new JPanel();
1695    private final JLabel rampRateLabel = new JLabel(Bundle.getMessage("RampRateBoxLabel"));
1696    private final JComboBox<String> rampRateBox = new JComboBox<>();
1697    private final JPanel pa2a = new JPanel();
1698    private final JLabel useSpeedProfileLabel = new JLabel(Bundle.getMessage("UseSpeedProfileLabel"));
1699    private final JCheckBox useSpeedProfileCheckBox = new JCheckBox( );
1700    private final JLabel stopBySpeedProfileLabel = new JLabel(Bundle.getMessage("StopBySpeedProfileLabel"));
1701    private final JCheckBox stopBySpeedProfileCheckBox = new JCheckBox( );
1702    private final JLabel stopBySpeedProfileAdjustLabel = new JLabel(Bundle.getMessage("StopBySpeedProfileAdjustLabel"));
1703    private final JSpinner stopBySpeedProfileAdjustSpinner = new JSpinner();
1704    private final JPanel pa3 = new JPanel();
1705    private final JCheckBox soundDecoderBox = new JCheckBox(Bundle.getMessage("SoundDecoder"));
1706    private final JCheckBox runInReverseBox = new JCheckBox(Bundle.getMessage("RunInReverse"));
1707    private final JPanel pa4 = new JPanel();
1708    protected static class TrainDetectionJCombo extends JComboBox<TrainDetectionItem> {
1709        public void setSelectedItemByValue(TrainDetection var) {
1710            for ( int ix = 0; ix < getItemCount() ; ix ++ ) {
1711                if (getItemAt(ix).value == var) {
1712                    this.setSelectedIndex(ix);
1713                    break;
1714                }
1715            }
1716        }
1717    }
1718    public final TrainDetectionJCombo trainDetectionComboBox
1719                = new TrainDetectionJCombo();
1720    private final JLabel trainDetectionLabel = new JLabel(Bundle.getMessage("TrainDetection"));
1721    private final JLabel trainLengthLabel = new JLabel(Bundle.getMessage("MaxTrainLengthLabel"));
1722    private final JSpinner maxTrainLengthSpinner = new JSpinner(); // initialized later
1723    // auto run variables
1724    float _speedFactor = 1.0f;
1725    float _maxSpeed = 0.6f;
1726    int _rampRate = AutoActiveTrain.RAMP_NONE;
1727    TrainDetection _trainDetection = TrainDetection.TRAINDETECTION_HEADONLY;
1728    boolean _runInReverse = false;
1729    boolean _soundDecoder = false;
1730    float _maxTrainLength = 200.0f;
1731    boolean _stopBySpeedProfile = false;
1732    float _stopBySpeedProfileAdjust = 1.0f;
1733    boolean _useSpeedProfile = true;
1734    String _nextTrain = "";
1735
1736    private void setAutoRunDefaults() {
1737        _speedFactor = 1.0f;
1738        _maxSpeed = 0.6f;
1739        _rampRate = AutoActiveTrain.RAMP_NONE;
1740        _runInReverse = false;
1741        _soundDecoder = false;
1742        _maxTrainLength = 100.0f;
1743        _stopBySpeedProfile = false;
1744        _stopBySpeedProfileAdjust = 1.0f;
1745        _useSpeedProfile = true;
1746        _nextTrain = "";
1747
1748    }
1749
1750    private void initializeAutoRunItems() {
1751        initializeRampCombo();
1752        pa1.setLayout(new FlowLayout());
1753        pa1.add(speedFactorLabel);
1754        speedFactorSpinner.setModel(new SpinnerNumberModel(Float.valueOf(1.0f), Float.valueOf(0.1f), Float.valueOf(2.0f), Float.valueOf(0.01f)));
1755        speedFactorSpinner.setEditor(new JSpinner.NumberEditor(speedFactorSpinner, "# %"));
1756        pa1.add(speedFactorSpinner);
1757        speedFactorSpinner.setToolTipText(Bundle.getMessage("SpeedFactorHint"));
1758        pa1.add(new JLabel("   "));
1759        pa1.add(maxSpeedLabel);
1760        maxSpeedSpinner.setModel(new SpinnerNumberModel(Float.valueOf(1.0f), Float.valueOf(0.1f), Float.valueOf(2.0f), Float.valueOf(0.01f)));
1761        maxSpeedSpinner.setEditor(new JSpinner.NumberEditor(maxSpeedSpinner, "# %"));
1762        pa1.add(maxSpeedSpinner);
1763        maxSpeedSpinner.setToolTipText(Bundle.getMessage("MaxSpeedHint"));
1764        initiatePane.add(pa1);
1765        pa2.setLayout(new FlowLayout());
1766        pa2.add(rampRateLabel);
1767        pa2.add(rampRateBox);
1768        rampRateBox.setToolTipText(Bundle.getMessage("RampRateBoxHint"));
1769        pa2.add(useSpeedProfileLabel);
1770        pa2.add(useSpeedProfileCheckBox);
1771        useSpeedProfileCheckBox.setToolTipText(Bundle.getMessage("UseSpeedProfileHint"));
1772        initiatePane.add(pa2);
1773        pa2a.setLayout(new FlowLayout());
1774        pa2a.add(stopBySpeedProfileLabel);
1775        pa2a.add(stopBySpeedProfileCheckBox);
1776        stopBySpeedProfileCheckBox.setToolTipText(Bundle.getMessage("UseSpeedProfileHint")); // reuse identical hint for Stop
1777        pa2a.add(stopBySpeedProfileAdjustLabel);
1778        stopBySpeedProfileAdjustSpinner.setModel(new SpinnerNumberModel( Float.valueOf(1.0f), Float.valueOf(0.1f), Float.valueOf(5.0f), Float.valueOf(0.01f)));
1779        stopBySpeedProfileAdjustSpinner.setEditor(new JSpinner.NumberEditor(stopBySpeedProfileAdjustSpinner, "# %"));
1780        pa2a.add(stopBySpeedProfileAdjustSpinner);
1781        stopBySpeedProfileAdjustSpinner.setToolTipText(Bundle.getMessage("StopBySpeedProfileAdjustHint"));
1782        initiatePane.add(pa2a);
1783        pa3.setLayout(new FlowLayout());
1784        pa3.add(soundDecoderBox);
1785        soundDecoderBox.setToolTipText(Bundle.getMessage("SoundDecoderBoxHint"));
1786        pa3.add(new JLabel("   "));
1787        pa3.add(runInReverseBox);
1788        runInReverseBox.setToolTipText(Bundle.getMessage("RunInReverseBoxHint"));
1789        initiatePane.add(pa3);
1790        pa4.setLayout(new FlowLayout());
1791        pa4.add(trainLengthLabel);
1792        maxTrainLengthSpinner.setModel(new SpinnerNumberModel(Float.valueOf(18.0f), Float.valueOf(0.0f), Float.valueOf(10000.0f), Float.valueOf(0.5f)));
1793        maxTrainLengthSpinner.setEditor(new JSpinner.NumberEditor(maxTrainLengthSpinner, "###0.0"));
1794        pa4.add(maxTrainLengthSpinner);
1795        boolean unitIsMeter = InstanceManager.getDefault(DispatcherFrame.class).getUseScaleMeters(); // read from user setting
1796        maxTrainLengthSpinner.setToolTipText(Bundle.getMessage("MaxTrainLengthHint",
1797                (unitIsMeter ? Bundle.getMessage("ScaleMeters") : Bundle.getMessage("ScaleFeet")))); // won't be updated while Dispatcher is open
1798        initiatePane.add(pa4);
1799        hideAutoRunItems();   // initialize with auto run items hidden
1800        initializeAutoRunValues();
1801    }
1802
1803    private void initializeAutoRunValues() {
1804        speedFactorSpinner.setValue(_speedFactor);
1805        maxSpeedSpinner.setValue(_maxSpeed);
1806        rampRateBox.setSelectedIndex(_rampRate);
1807        soundDecoderBox.setSelected(_soundDecoder);
1808        runInReverseBox.setSelected(_runInReverse);
1809        useSpeedProfileCheckBox.setSelected(_useSpeedProfile);
1810        stopBySpeedProfileAdjustSpinner.setValue(_stopBySpeedProfileAdjust);
1811        stopBySpeedProfileCheckBox.setSelected(_stopBySpeedProfile);
1812        maxTrainLengthSpinner.setValue(Math.round(_maxTrainLength * 2) * 0.5f); // set in spinner as 0.5 increments
1813
1814    }
1815
1816    private void hideAutoRunItems() {
1817        pa1.setVisible(false);
1818        pa2.setVisible(false);
1819        pa2a.setVisible(false);
1820        pa3.setVisible(false);
1821        pa4.setVisible(false);
1822    }
1823
1824    private void showAutoRunItems() {
1825        pa1.setVisible(true);
1826        pa2.setVisible(true);
1827        pa2a.setVisible(true);
1828        pa3.setVisible(true);
1829        pa4.setVisible(true);
1830    }
1831
1832    private void autoTrainInfoToDialog(TrainInfo info) {
1833        speedFactorSpinner.setValue(info.getSpeedFactor());
1834        maxSpeedSpinner.setValue(info.getMaxSpeed());
1835        setComboBox(rampRateBox, info.getRampRate());
1836        trainDetectionComboBox.setSelectedItemByValue(info.getTrainDetection());
1837        runInReverseBox.setSelected(info.getRunInReverse());
1838        soundDecoderBox.setSelected(info.getSoundDecoder());
1839        maxTrainLengthSpinner.setValue(info.getMaxTrainLength());
1840        useSpeedProfileCheckBox.setSelected(info.getUseSpeedProfile());
1841        stopBySpeedProfileCheckBox.setSelected(info.getStopBySpeedProfile());
1842        stopBySpeedProfileAdjustSpinner.setValue(info.getStopBySpeedProfileAdjust());
1843        if (autoRunBox.isSelected()) {
1844            showAutoRunItems();
1845        } else {
1846            hideAutoRunItems();
1847        }
1848        initiateFrame.pack();
1849    }
1850
1851    private void autoRunItemsToTrainInfo(TrainInfo info) {
1852        info.setSpeedFactor((float) speedFactorSpinner.getValue());
1853        info.setMaxSpeed((float) maxSpeedSpinner.getValue());
1854        info.setRampRate((String) rampRateBox.getSelectedItem());
1855        info.setRunInReverse(runInReverseBox.isSelected());
1856        info.setSoundDecoder(soundDecoderBox.isSelected());
1857        info.setMaxTrainLength((float) maxTrainLengthSpinner.getValue());
1858        // Only use speed profile values if enabled
1859        if (useSpeedProfileCheckBox.isEnabled()) {
1860            info.setUseSpeedProfile(useSpeedProfileCheckBox.isSelected());
1861            info.setStopBySpeedProfile(stopBySpeedProfileCheckBox.isSelected());
1862            info.setStopBySpeedProfileAdjust((float) stopBySpeedProfileAdjustSpinner.getValue());
1863        } else {
1864            info.setUseSpeedProfile(false);
1865            info.setStopBySpeedProfile(false);
1866            info.setStopBySpeedProfileAdjust(1.0f);
1867        }
1868    }
1869
1870    private boolean readAutoRunItems() {
1871        boolean success = true;
1872        _speedFactor = (float) speedFactorSpinner.getValue();
1873        _maxSpeed = (float) maxSpeedSpinner.getValue();
1874        _rampRate = rampRateBox.getSelectedIndex();
1875        _trainDetection = ((TrainDetectionItem)trainDetectionComboBox.getSelectedItem()).value;
1876        _runInReverse = runInReverseBox.isSelected();
1877        _soundDecoder = soundDecoderBox.isSelected();
1878        _maxTrainLength = (float) maxTrainLengthSpinner.getValue();
1879        _useSpeedProfile = useSpeedProfileCheckBox.isSelected();
1880        _stopBySpeedProfile = stopBySpeedProfileCheckBox.isSelected();
1881        if (_stopBySpeedProfile) {
1882            _stopBySpeedProfileAdjust = (Float) stopBySpeedProfileAdjustSpinner.getValue();
1883        }
1884        if (nextTrain.getSelectedIndex() < 0) {
1885            _nextTrain="";
1886        } else {
1887            _nextTrain = (String)nextTrain.getSelectedItem();
1888        }
1889        return success;
1890    }
1891
1892    private void setAutoRunItems(AutoActiveTrain aaf) {
1893        aaf.setSpeedFactor(_speedFactor);
1894        aaf.setMaxSpeed(_maxSpeed);
1895        aaf.setRampRate(_rampRate);
1896        aaf.setRunInReverse(_runInReverse);
1897        aaf.setSoundDecoder(_soundDecoder);
1898        aaf.setMaxTrainLength(_maxTrainLength);
1899        aaf.setStopBySpeedProfile(_stopBySpeedProfile);
1900        aaf.setStopBySpeedProfileAdjust(_stopBySpeedProfileAdjust);
1901        aaf.setUseSpeedProfile(_useSpeedProfile);
1902    }
1903
1904    private void initializeRampCombo() {
1905        rampRateBox.removeAllItems();
1906        rampRateBox.addItem(Bundle.getMessage("RAMP_NONE"));
1907        rampRateBox.addItem(Bundle.getMessage("RAMP_FAST"));
1908        rampRateBox.addItem(Bundle.getMessage("RAMP_MEDIUM"));
1909        rampRateBox.addItem(Bundle.getMessage("RAMP_MED_SLOW"));
1910        rampRateBox.addItem(Bundle.getMessage("RAMP_SLOW"));
1911        rampRateBox.addItem(Bundle.getMessage("RAMP_SPEEDPROFILE"));
1912        // Note: the order above must correspond to the numbers in AutoActiveTrain.java
1913    }
1914
1915    /**
1916     * Sets up the RadioButtons and visability of spinner for the allocation method
1917     *
1918     * @param value 0, Allocate by Safe spots, -1, allocate as far as possible Any
1919     *            other value the number of sections to allocate
1920     */
1921    private void setAllocateMethodButtons(int value) {
1922        switch (value) {
1923            case ActiveTrain.ALLOCATE_BY_SAFE_SECTIONS:
1924                allocateBySafeRadioButton.setSelected(true);
1925                allocateCustomSpinner.setVisible(false);
1926                break;
1927            case ActiveTrain.ALLOCATE_AS_FAR_AS_IT_CAN:
1928                allocateAllTheWayRadioButton.setSelected(true);
1929                allocateCustomSpinner.setVisible(false);
1930                break;
1931            default:
1932                allocateNumberOfBlocks.setSelected(true);
1933                allocateCustomSpinner.setVisible(true);
1934                allocateCustomSpinner.setValue(value);
1935        }
1936    }
1937
1938    /*
1939     * ComboBox item.
1940     */
1941    protected static class TrainDetectionItem {
1942        private String key;
1943        private TrainDetection value;
1944        public TrainDetectionItem(String text, TrainDetection trainDetection ) {
1945            this.key = text;
1946            this.value = trainDetection;
1947        }
1948        @Override
1949        public String toString()
1950        {
1951            return key;
1952        }
1953        public String getKey()
1954        {
1955            return key;
1956        }
1957        public TrainDetection getValue()
1958        {
1959            return value;
1960        }
1961    }
1962
1963    private static final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(ActivateTrainFrame.class);
1964
1965}