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