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