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                        checkAdvancedRouting();
420                        transitSelectBox.setEnabled(false);
421                        //adHocCloseLoop.setEnabled(true);
422                        inTransitBox.setEnabled(false);
423                        inTransitBox.setSelected(true);
424                        initializeStartingBlockComboDynamic();
425                        viaBlockBox.setVisible(true);
426                        viaBlockBoxLabel.setVisible(true);
427                    }
428                }
429            });
430
431            //p3.add(adHocCloseLoop);
432            //adHocCloseLoop.setToolTipText(Bundle.getMessage("TransitCloseLoopHint"));
433
434            p3.add(new JLabel(Bundle.getMessage("TransitBoxLabel") + " :"));
435            p3.add(transitSelectBox);
436            transitSelectBox.addActionListener(new ActionListener() {
437                @Override
438                public void actionPerformed(ActionEvent e) {
439                    handleTransitSelectionChanged(e);
440                }
441            });
442            transitSelectBox.setToolTipText(Bundle.getMessage("TransitBoxHint"));
443            initiatePane.add(p3);
444
445            // Train in transit
446            JPanel p4 = new JPanel();
447            p4.add(inTransitBox);
448            inTransitBox.addActionListener(new ActionListener() {
449                @Override
450                public void actionPerformed(ActionEvent e) {
451                    handleInTransitClick();
452                }
453            });
454            inTransitBox.setToolTipText(Bundle.getMessage("InTransitBoxHint"));
455            initiatePane.add(p4);
456
457            // Starting block, add Via for adhoc transits
458            JPanel p5 = new JPanel();
459            p5.add(new JLabel(Bundle.getMessage("StartingBlockBoxLabel") + " :"));
460            p5.add(startingBlockBox);
461            startingBlockBox.setToolTipText(Bundle.getMessage("StartingBlockBoxHint"));
462            startingBlockBox.addActionListener(new ActionListener() {
463                @Override
464                public void actionPerformed(ActionEvent e) {
465                    handleStartingBlockSelectionChanged(e);
466                }
467            });
468            p5.add(viaBlockBoxLabel);
469            p5.add(viaBlockBox);
470            viaBlockBox.setToolTipText(Bundle.getMessage("ViaBlockBoxHint"));
471            viaBlockBox.addActionListener(viaBlockBoxListener);
472            initiatePane.add(p5);
473
474            // Destination block
475            JPanel p6 = new JPanel();
476            p6.add(new JLabel(Bundle.getMessage("DestinationBlockBoxLabel") + ":"));
477            p6.add(destinationBlockBox);
478            destinationBlockBox.setToolTipText(Bundle.getMessage("DestinationBlockBoxHint"));
479            initiatePane.add(p6);
480
481            // Train detection scope
482            JPanel p7 = new JPanel();
483            p7.add(trainDetectionLabel);
484            initializeTrainDetectionBox();
485            p7.add(trainDetectionComboBox);
486            trainDetectionComboBox.setToolTipText(Bundle.getMessage("TrainDetectionBoxHint"));
487            initiatePane.add(p7);
488
489            // Allocation method
490            JPanel p8 = new JPanel();
491            p8.setBorder(BorderFactory.createTitledBorder(Bundle.getMessage("AllocateMethodLabel")));
492            allocateMethodButtonGroup.add(allocateAllTheWayRadioButton);
493            allocateMethodButtonGroup.add(allocateBySafeRadioButton);
494            allocateMethodButtonGroup.add(allocateNumberOfBlocks);
495            p8.add(allocateAllTheWayRadioButton);
496            allocateAllTheWayRadioButton.setToolTipText(Bundle.getMessage("AllocateAllTheWayHint"));
497            p8.add(allocateBySafeRadioButton);
498            allocateBySafeRadioButton.setToolTipText(Bundle.getMessage("AllocateSafeHint"));
499            p8.add(allocateNumberOfBlocks);
500            allocateNumberOfBlocks.setToolTipText(Bundle.getMessage("AllocateMethodHint"));
501            allocateAllTheWayRadioButton.addActionListener(new ActionListener() {
502                @Override
503                public void actionPerformed(ActionEvent e) {
504                    handleAllocateAllTheWayButtonChanged(e);
505                }
506            });
507            allocateBySafeRadioButton.addActionListener(new ActionListener() {
508                @Override
509                public void actionPerformed(ActionEvent e) {
510                    handleAllocateBySafeButtonChanged(e);
511                }
512            });
513            allocateNumberOfBlocks.addActionListener(new ActionListener() {
514                @Override
515                public void actionPerformed(ActionEvent e) {
516                    handleAllocateNumberOfBlocksButtonChanged(e);
517                }
518            });
519            p8.add(allocateCustomSpinner);
520            allocateCustomSpinner.setToolTipText(Bundle.getMessage("AllocateMethodHint"));
521            initiatePane.add(p8);
522
523            // Restart at end
524            JPanel p9 = new JPanel();
525            p9.add(resetWhenDoneBox);
526            resetWhenDoneBox.addActionListener(new ActionListener() {
527                @Override
528                public void actionPerformed(ActionEvent e) {
529                    handleResetWhenDoneClick(e);
530                }
531            });
532            resetWhenDoneBox.setToolTipText(Bundle.getMessage("ResetWhenDoneBoxHint"));
533            initiatePane.add(p9);
534
535            // Restart using sensor
536            JPanel p9a = new JPanel();
537            ((FlowLayout) p9a.getLayout()).setVgap(1);
538            p9a.add(delayedReStartLabel);
539            p9a.add(delayedReStartBox);
540            p9a.add(resetRestartSensorBox);
541            resetRestartSensorBox.setToolTipText(Bundle.getMessage("ResetRestartSensorHint"));
542            resetRestartSensorBox.setSelected(true);
543            delayedReStartBox.addActionListener(new ActionListener() {
544                @Override
545                public void actionPerformed(ActionEvent e) {
546                    handleResetWhenDoneClick(e);
547                }
548            });
549            delayedReStartBox.setToolTipText(Bundle.getMessage("DelayedReStartHint"));
550            initiatePane.add(p9a);
551
552            // Restart using timer
553            JPanel p9b = new JPanel();
554            ((FlowLayout) p9b.getLayout()).setVgap(1);
555            p9b.add(delayMinLabel);
556            p9b.add(delayMinSpinner); // already set to 0
557            delayMinSpinner.setToolTipText(Bundle.getMessage("RestartTimedHint"));
558            p9b.add(delayReStartSensorLabel);
559            p9b.add(delayReStartSensor);
560            delayReStartSensor.setAllowNull(true);
561            handleResetWhenDoneClick(null);
562            initiatePane.add(p9b);
563
564            initiatePane.add(new JSeparator());
565
566            // Reverse at end
567            JPanel p10 = new JPanel();
568            p10.add(reverseAtEndBox);
569            reverseAtEndBox.setToolTipText(Bundle.getMessage("ReverseAtEndBoxHint"));
570            initiatePane.add(p10);
571            reverseAtEndBox.addActionListener(new ActionListener() {
572                @Override
573                public void actionPerformed(ActionEvent e) {
574                    handleReverseAtEndBoxClick(e);
575                }
576            });
577
578            // Reverse using sensor
579            JPanel pDelayReverseRestartDetails = new JPanel();
580            ((FlowLayout) pDelayReverseRestartDetails.getLayout()).setVgap(1);
581            pDelayReverseRestartDetails.add(delayReverseReStartLabel);
582            pDelayReverseRestartDetails.add(reverseDelayedRestartType);
583            pDelayReverseRestartDetails.add(delayReverseResetSensorBox);
584            delayReverseResetSensorBox.setToolTipText(Bundle.getMessage("ReverseResetRestartSensorHint"));
585            delayReverseResetSensorBox.setSelected(true);
586            reverseDelayedRestartType.addActionListener(new ActionListener() {
587                @Override
588                public void actionPerformed(ActionEvent e) {
589                    handleReverseAtEndBoxClick(e);
590                }
591            });
592            reverseDelayedRestartType.setToolTipText(Bundle.getMessage("ReverseDelayedReStartHint"));
593            initiatePane.add(pDelayReverseRestartDetails);
594
595            // Reverse using timer
596            JPanel pDelayReverseRestartDetails2 = new JPanel();
597            ((FlowLayout) pDelayReverseRestartDetails2.getLayout()).setVgap(1);
598            pDelayReverseRestartDetails2.add(delayReverseMinLabel);
599            pDelayReverseRestartDetails2.add(delayReverseMinSpinner); // already set to 0
600            delayReverseMinSpinner.setToolTipText(Bundle.getMessage("ReverseRestartTimedHint"));
601            pDelayReverseRestartDetails2.add(delayReverseReStartSensorLabel);
602            pDelayReverseRestartDetails2.add(delayReverseReStartSensor);
603            delayReverseReStartSensor.setAllowNull(true);
604            handleReverseAtEndBoxClick(null);
605            initiatePane.add(pDelayReverseRestartDetails2);
606
607            initiatePane.add(new JSeparator());
608
609            // Terminate when done option
610            JPanel p11 = new JPanel();
611            p11.setLayout(new FlowLayout());
612            p11.add(terminateWhenDoneBox);
613            terminateWhenDoneBox.addActionListener(new ActionListener() {
614                @Override
615                public void actionPerformed(ActionEvent e) {
616                    handleTerminateWhenDoneBoxClick(e);
617                }
618            });
619            initiatePane.add(p11);
620
621            // Optional next train, tied to terminate when done.
622            terminateWhenDoneDetails.setLayout(new FlowLayout());
623            terminateWhenDoneDetails.add(nextTrainLabel);
624            terminateWhenDoneDetails.add(nextTrain);
625            nextTrain.setToolTipText(Bundle.getMessage("TerminateWhenDoneNextTrainHint"));
626            initiatePane.add(terminateWhenDoneDetails);
627            handleTerminateWhenDoneBoxClick(null);
628
629            initiatePane.add(new JSeparator());
630
631            // Priority and train type.
632            JPanel p12 = new JPanel();
633            p12.setLayout(new FlowLayout());
634            p12.add(new JLabel(Bundle.getMessage("PriorityLabel") + ":"));
635            p12.add(prioritySpinner); // already set to 5
636            prioritySpinner.setToolTipText(Bundle.getMessage("PriorityHint"));
637            p12.add(new JLabel("     "));
638            p12.add(new JLabel(Bundle.getMessage("TrainTypeBoxLabel")));
639            initializeTrainTypeBox();
640            p12.add(trainTypeBox);
641            trainTypeBox.setSelectedIndex(1);
642            trainTypeBox.setToolTipText(Bundle.getMessage("TrainTypeBoxHint"));
643            initiatePane.add(p12);
644
645            // Delayed start option
646            JPanel p13 = new JPanel();
647            p13.add(new JLabel(Bundle.getMessage("DelayedStart")));
648            p13.add(delayedStartBox);
649            delayedStartBox.setToolTipText(Bundle.getMessage("DelayedStartHint"));
650            delayedStartBox.addActionListener(new ActionListener() {
651                @Override
652                public void actionPerformed(ActionEvent e) {
653                    handleDelayStartClick(e);
654                }
655            });
656            p13.add(departureTimeLabel);
657            departureHrSpinner.setEditor(new JSpinner.NumberEditor(departureHrSpinner, "00"));
658            p13.add(departureHrSpinner);
659            departureHrSpinner.setValue(8);
660            departureHrSpinner.setToolTipText(Bundle.getMessage("DepartureTimeHrHint"));
661            p13.add(departureSepLabel);
662            departureMinSpinner.setEditor(new JSpinner.NumberEditor(departureMinSpinner, "00"));
663            p13.add(departureMinSpinner);
664            departureMinSpinner.setValue(0);
665            departureMinSpinner.setToolTipText(Bundle.getMessage("DepartureTimeMinHint"));
666            p13.add(delaySensor);
667            delaySensor.setAllowNull(true);
668            p13.add(resetStartSensorBox);
669            resetStartSensorBox.setToolTipText(Bundle.getMessage("ResetStartSensorHint"));
670            resetStartSensorBox.setSelected(true);
671            handleDelayStartClick(null);
672            initiatePane.add(p13);
673
674            // Load at startup option
675            JPanel p14 = new JPanel();
676            p14.setLayout(new FlowLayout());
677            p14.add(loadAtStartupBox);
678            loadAtStartupBox.setToolTipText(Bundle.getMessage("LoadAtStartupBoxHint"));
679            loadAtStartupBox.setSelected(false);
680            initiatePane.add(p14);
681
682            // Auto run option
683            initiatePane.add(new JSeparator());
684            JPanel p15 = new JPanel();
685            p15.add(autoRunBox);
686            autoRunBox.addActionListener(new ActionListener() {
687                @Override
688                public void actionPerformed(ActionEvent e) {
689                    handleAutoRunClick(e);
690                }
691            });
692            autoRunBox.setToolTipText(Bundle.getMessage("AutoRunBoxHint"));
693            autoRunBox.setSelected(false);
694            initiatePane.add(p15);
695            initializeAutoRunItems();
696
697            // Footer buttons
698            JPanel ftr = new JPanel();
699            JButton cancelButton = null;
700            ftr.add(cancelButton = new JButton(Bundle.getMessage("ButtonCancel")));
701            cancelButton.addActionListener(new ActionListener() {
702                @Override
703                public void actionPerformed(ActionEvent e) {
704                    cancelInitiateTrain(e);
705                }
706            });
707            cancelButton.setToolTipText(Bundle.getMessage("CancelButtonHint"));
708            ftr.add(addNewTrainButton = new JButton(Bundle.getMessage("ButtonCreate")));
709            addNewTrainButton.addActionListener(new ActionListener() {
710                @Override
711                public void actionPerformed(ActionEvent e) {
712                    addNewTrain(e);
713                }
714            });
715            addNewTrainButton.setToolTipText(Bundle.getMessage("AddNewTrainButtonHint"));
716
717            JPanel mainPane = new JPanel(new BorderLayout());
718            JScrollPane scrPane = new JScrollPane(initiatePane);
719            mainPane.add(hdr, BorderLayout.NORTH);
720            mainPane.add(scrPane, BorderLayout.CENTER);
721            mainPane.add(ftr, BorderLayout.SOUTH);
722            initiateFrame.setContentPane(mainPane);
723            switch (trainInfo.getTrainsFrom()) {
724                case TRAINSFROMROSTER:
725                    radioTrainsFromRoster.setSelected(true);
726                    break;
727                case TRAINSFROMOPS:
728                    radioTrainsFromOps.setSelected(true);
729                    break;
730                case TRAINSFROMUSER:
731                    radioTrainsFromUser.setSelected(true);
732                    break;
733                case TRAINSFROMSETLATER:
734                default:
735                    radioTrainsFromSetLater.setSelected(true);
736            }
737
738        }
739        autoRunBox.setSelected(false);
740        loadAtStartupBox.setSelected(false);
741        initializeFreeTransitsCombo(new ArrayList<Transit>());
742        refreshNextTrainCombo();
743        setTrainsFromOptions(trainInfo.getTrainsFrom());
744        initiateFrame.pack();
745        initiateFrame.setVisible(true);
746
747        trainInfoToDialog(trainInfo);
748    }
749
750    private void refreshNextTrainCombo() {
751        Object saveEntry = null;
752        if (nextTrain.getSelectedIndex() > 0) {
753            saveEntry=nextTrain.getSelectedItem();
754        }
755        nextTrain.removeAllItems();
756        nextTrain.addItem(" ");
757        for (String file: _tiFile.getTrainInfoFileNames()) {
758            nextTrain.addItem(file);
759        }
760        if (saveEntry != null) {
761            nextTrain.setSelectedItem(saveEntry);
762        }
763    }
764    private void setTrainsFromOptions(TrainsFrom transFrom) {
765        switch (transFrom) {
766            case TRAINSFROMROSTER:
767                initializeFreeRosterEntriesCombo();
768                rosterComboBox.setVisible(true);
769                trainSelectBox.setVisible(false);
770                trainFieldLabel.setVisible(true);
771                trainNameField.setVisible(true);
772                dccAddressFieldLabel.setVisible(false);
773                dccAddressSpinner.setVisible(false);
774                break;
775            case TRAINSFROMOPS:
776                initializeFreeTrainsCombo();
777                trainSelectBox.setVisible(true);
778                rosterComboBox.setVisible(false);
779                trainFieldLabel.setVisible(true);
780                trainNameField.setVisible(true);
781                dccAddressFieldLabel.setVisible(true);
782                dccAddressSpinner.setVisible(true);
783                setSpeedProfileOptions(trainInfo,false);
784                break;
785            case TRAINSFROMUSER:
786                trainNameField.setText("");
787                trainSelectBox.setVisible(false);
788                rosterComboBox.setVisible(false);
789                trainFieldLabel.setVisible(true);
790                trainNameField.setVisible(true);
791                dccAddressFieldLabel.setVisible(true);
792                dccAddressSpinner.setVisible(true);
793                dccAddressSpinner.setEnabled(true);
794                setSpeedProfileOptions(trainInfo,false);
795                break;
796            case TRAINSFROMSETLATER:
797            default:
798                rosterComboBox.setVisible(false);
799                trainSelectBox.setVisible(false);
800                trainFieldLabel.setVisible(true);
801                trainNameField.setVisible(true);
802                dccAddressFieldLabel.setVisible(false);
803                dccAddressSpinner.setVisible(false);
804        }
805    }
806
807    private void initializeTrainTypeBox() {
808        trainTypeBox.removeAllItems();
809        trainTypeBox.addItem("<" + Bundle.getMessage("None").toLowerCase() + ">"); // <none>
810        trainTypeBox.addItem(Bundle.getMessage("LOCAL_PASSENGER"));
811        trainTypeBox.addItem(Bundle.getMessage("LOCAL_FREIGHT"));
812        trainTypeBox.addItem(Bundle.getMessage("THROUGH_PASSENGER"));
813        trainTypeBox.addItem(Bundle.getMessage("THROUGH_FREIGHT"));
814        trainTypeBox.addItem(Bundle.getMessage("EXPRESS_PASSENGER"));
815        trainTypeBox.addItem(Bundle.getMessage("EXPRESS_FREIGHT"));
816        trainTypeBox.addItem(Bundle.getMessage("MOW"));
817        // NOTE: The above must correspond in order and name to definitions in ActiveTrain.java.
818    }
819
820    private void initializeTrainDetectionBox() {
821        trainDetectionComboBox.addItem(new TrainDetectionItem(Bundle.getMessage("TrainDetectionWholeTrain"),TrainDetection.TRAINDETECTION_WHOLETRAIN));
822        trainDetectionComboBox.addItem(new TrainDetectionItem(Bundle.getMessage("TrainDetectionHeadAndTail"),TrainDetection.TRAINDETECTION_HEADANDTAIL));
823        trainDetectionComboBox.addItem(new TrainDetectionItem(Bundle.getMessage("TrainDetectionHeadOnly"),TrainDetection.TRAINDETECTION_HEADONLY));
824    }
825
826    private void initializeScaleLengthBox() {
827        trainLengthUnitsComboBox.addItem(new TrainLengthUnitsItem(Bundle.getMessage("TrainLengthInScaleFeet"), TrainLengthUnits.TRAINLENGTH_SCALEFEET));
828        trainLengthUnitsComboBox.addItem(new TrainLengthUnitsItem(Bundle.getMessage("TrainLengthInScaleMeters"), TrainLengthUnits.TRAINLENGTH_SCALEMETERS));
829        trainLengthUnitsComboBox.addItem(new TrainLengthUnitsItem(Bundle.getMessage("TrainLengthInActualInchs"), TrainLengthUnits.TRAINLENGTH_ACTUALINCHS));
830        trainLengthUnitsComboBox.addItem(new TrainLengthUnitsItem(Bundle.getMessage("TrainLengthInActualcm"), TrainLengthUnits.TRAINLENGTH_ACTUALCM));
831    }
832
833    private void handleTransitSelectionChanged(ActionEvent e) {
834        int index = transitSelectBox.getSelectedIndex();
835        if (index < 0) {
836            return;
837        }
838        Transit t = transitSelectBox.getSelectedItem();
839        if ((t != null) && (t != selectedTransit)) {
840            selectedTransit = t;
841            initializeStartingBlockCombo();
842            initializeDestinationBlockCombo();
843            initiateFrame.pack();
844        }
845    }
846
847    private void handleInTransitClick() {
848        if (!inTransitBox.isSelected() && selectedTransit.getEntryBlocksList().isEmpty()) {
849            JmriJOptionPane.showMessageDialog(initiateFrame, Bundle
850                    .getMessage("NoEntryBlocks"), Bundle.getMessage("MessageTitle"),
851                    JmriJOptionPane.INFORMATION_MESSAGE);
852            inTransitBox.setSelected(true);
853        }
854        initializeStartingBlockCombo();
855        initializeDestinationBlockCombo();
856        initiateFrame.pack();
857    }
858
859      private void handleTrainSelectionChanged() {
860        if (!trainsFromButtonGroup.getSelection().getActionCommand().equals("TRAINSFROMOPS")) {
861            return;
862        }
863        int ix = trainSelectBox.getSelectedIndex();
864        if (ix < 1) { // no train selected
865            dccAddressSpinner.setEnabled(false);
866            return;
867        }
868        dccAddressSpinner.setEnabled(true);
869        int dccAddress;
870        try {
871            dccAddress = Integer.parseInt((((Train) trainSelectBox.getSelectedItem()).getLeadEngineDccAddress()));
872        } catch (NumberFormatException Ex) {
873            JmriJOptionPane.showMessageDialog(initiateFrame, Bundle.getMessage("Error43"),
874                    Bundle.getMessage("ErrorTitle"), JmriJOptionPane.ERROR_MESSAGE);
875            return;
876        }
877        dccAddressSpinner.setValue (dccAddress);
878        trainNameField.setText(((Train) trainSelectBox.getSelectedItem()).getName());
879    }
880
881    private void handleRosterSelectionChanged(ActionEvent e) {
882        if (!trainsFromButtonGroup.getSelection().getActionCommand().equals("TRAINSFROMROSTER")) {
883            return;
884        }
885        int ix = rosterComboBox.getSelectedIndex();
886        if (ix > 0) { // first item is "Select Loco" string
887            RosterEntry r = (RosterEntry) rosterComboBox.getItemAt(ix);
888            // check to see if speed profile exists and is not empty
889            if (r.getSpeedProfile() == null || r.getSpeedProfile().getProfileSize() < 1) {
890                // disable profile boxes etc.
891                setSpeedProfileOptions(trainInfo,false);
892            } else {
893                // enable profile boxes
894                setSpeedProfileOptions(trainInfo,true);
895            }
896            maxSpeedSpinner.setValue(r.getMaxSpeedPCT()/100.0f);
897            trainNameField.setText(r.titleString());
898            if (r.getAttribute("DispatcherTrainType") != null && !r.getAttribute("DispatcherTrainType").equals("")) {
899                trainTypeBox.setSelectedItem(r.getAttribute("DispatcherTrainType"));
900            }
901        } else {
902            setSpeedProfileOptions(trainInfo,false);
903        }
904    }
905
906    private void handleDelayStartClick(ActionEvent e) {
907        departureHrSpinner.setVisible(false);
908        departureMinSpinner.setVisible(false);
909        departureTimeLabel.setVisible(false);
910        departureSepLabel.setVisible(false);
911        delaySensor.setVisible(false);
912        resetStartSensorBox.setVisible(false);
913        if (delayedStartBox.getSelectedItem().equals(Bundle.getMessage("DelayedStartTimed"))) {
914            departureHrSpinner.setVisible(true);
915            departureMinSpinner.setVisible(true);
916            departureTimeLabel.setVisible(true);
917            departureSepLabel.setVisible(true);
918        } else if (delayedStartBox.getSelectedItem().equals(Bundle.getMessage("DelayedStartSensor"))) {
919            delaySensor.setVisible(true);
920            resetStartSensorBox.setVisible(true);
921        }
922        initiateFrame.pack(); // to fit extra hh:mm in window
923    }
924
925    private void handleResetWhenDoneClick(ActionEvent e) {
926        delayMinSpinner.setVisible(false);
927        delayMinLabel.setVisible(false);
928        delayedReStartLabel.setVisible(false);
929        delayedReStartBox.setVisible(false);
930        delayReStartSensorLabel.setVisible(false);
931        delayReStartSensor.setVisible(false);
932        resetRestartSensorBox.setVisible(false);
933        if (resetWhenDoneBox.isSelected()) {
934            delayedReStartLabel.setVisible(true);
935            delayedReStartBox.setVisible(true);
936            terminateWhenDoneBox.setSelected(false);
937            if (delayedReStartBox.getSelectedItem().equals(Bundle.getMessage("DelayedStartTimed"))) {
938                delayMinSpinner.setVisible(true);
939                delayMinLabel.setVisible(true);
940            } else if (delayedReStartBox.getSelectedItem().equals(Bundle.getMessage("DelayedStartSensor"))) {
941                delayReStartSensor.setVisible(true);
942                delayReStartSensorLabel.setVisible(true);
943                resetRestartSensorBox.setVisible(true);
944            }
945        } else {
946            terminateWhenDoneBox.setEnabled(true);
947        }
948        initiateFrame.pack();
949    }
950
951    private void handleTerminateWhenDoneBoxClick(ActionEvent e) {
952        if (terminateWhenDoneBox.isSelected()) {
953            refreshNextTrainCombo();
954            resetWhenDoneBox.setSelected(false);
955            terminateWhenDoneDetails.setVisible(true);
956        } else {
957            terminateWhenDoneDetails.setVisible(false);
958        }
959    }
960
961    private void handleReverseAtEndBoxClick(ActionEvent e) {
962        delayReverseMinSpinner.setVisible(false);
963        delayReverseMinLabel.setVisible(false);
964        delayReverseReStartLabel.setVisible(false);
965        reverseDelayedRestartType.setVisible(false);
966        delayReverseReStartSensorLabel.setVisible(false);
967        delayReverseReStartSensor.setVisible(false);
968        delayReverseResetSensorBox.setVisible(false);
969        if (reverseAtEndBox.isSelected()) {
970            delayReverseReStartLabel.setVisible(true);
971            reverseDelayedRestartType.setVisible(true);
972            if (reverseDelayedRestartType.getSelectedItem().equals(Bundle.getMessage("DelayedStartTimed"))) {
973                delayReverseMinSpinner.setVisible(true);
974                delayReverseMinLabel.setVisible(true);
975            } else if (reverseDelayedRestartType.getSelectedItem().equals(Bundle.getMessage("DelayedStartSensor"))) {
976                delayReverseReStartSensor.setVisible(true);
977                delayReStartSensorLabel.setVisible(true);
978                delayReverseResetSensorBox.setVisible(true);
979            }
980        }
981        initiateFrame.pack();
982
983        if (resetWhenDoneBox.isSelected()) {
984            terminateWhenDoneBox.setSelected(false);
985            terminateWhenDoneBox.setEnabled(false);
986        } else {
987            terminateWhenDoneBox.setEnabled(true);
988        }
989    }
990
991    private void handleAutoRunClick(ActionEvent e) {
992        if (autoRunBox.isSelected()) {
993            showAutoRunItems();
994        } else {
995            hideAutoRunItems();
996        }
997        initiateFrame.pack();
998    }
999
1000    private void handleStartingBlockSelectionChanged(ActionEvent e) {
1001        if (radioTransitsAdHoc.isSelected() ) {
1002            initializeViaBlockDynamicCombo();
1003            initializeDestinationBlockDynamicCombo();
1004        } else {
1005            initializeDestinationBlockCombo();
1006        }
1007        initiateFrame.pack();
1008    }
1009
1010    private void handleViaBlockSelectionChanged(ActionEvent e) {
1011        if (radioTransitsAdHoc.isSelected() ) {
1012            initializeDestinationBlockDynamicCombo();
1013        } else {
1014            initializeDestinationBlockCombo();
1015        }
1016        initiateFrame.pack();
1017    }
1018
1019    private void handleAllocateAllTheWayButtonChanged(ActionEvent e) {
1020        allocateCustomSpinner.setVisible(false);
1021    }
1022
1023    private void handleAllocateBySafeButtonChanged(ActionEvent e) {
1024        allocateCustomSpinner.setVisible(false);
1025    }
1026
1027    private void handleAllocateNumberOfBlocksButtonChanged(ActionEvent e) {
1028        allocateCustomSpinner.setVisible(true);
1029    }
1030
1031    private void cancelInitiateTrain(ActionEvent e) {
1032        _dispatcher.newTrainDone(null);
1033    }
1034
1035    /*
1036     * Handles press of "Add New Train" button.
1037     * Move data to TrainInfo validating basic information
1038     * Call dispatcher to start the train from traininfo which
1039     * completes validation.
1040     */
1041    private void addNewTrain(ActionEvent e) {
1042        try {
1043            validateDialog();
1044            trainInfo = new TrainInfo();
1045            dialogToTrainInfo(trainInfo);
1046            if (radioTransitsAdHoc.isSelected()) {
1047                int ixStart, ixEnd, ixVia;
1048                ixStart = startingBlockBox.getSelectedIndex();
1049                ixEnd = destinationBlockBox.getSelectedIndex();
1050                ixVia = viaBlockBox.getSelectedIndex();
1051                // search for a transit if ones available.
1052                Transit tmpTransit = null;
1053                int routeCount = 9999;
1054                int startBlockSeq = 0;
1055                int endBlockSeq = 0;
1056                log.debug("Start[{}]Via[{}]Dest[{}}]",
1057                        startingBlockBoxList.get(ixStart).getDisplayName(),
1058                        viaBlockBoxList.get(ixVia).getDisplayName(),
1059                        destinationBlockBoxList.get(ixEnd).getDisplayName());
1060                for (Transit tr : InstanceManager.getDefault(jmri.TransitManager.class)
1061                        .getListUsingBlock(startingBlockBoxList.get(ixStart))) {
1062                    if (tr.getState() == Transit.IDLE
1063                            && tr.containsBlock(startingBlockBoxList.get(ixStart))
1064                            && tr.containsBlock(viaBlockBoxList.get(ixVia)) &&
1065                            tr.containsBlock(destinationBlockBoxList.get(ixEnd))) {
1066                        log.debug("[{}]  contains all blocks", tr.getDisplayName());
1067                        int ixCountStart = -1, ixCountVia = -1, ixCountDest = -1, ixCount = 0;
1068                        List<Block> transitBlocks = tr.getInternalBlocksList();
1069                        List<Integer> transitBlockSeq = tr.getBlockSeqList();
1070                        for (Block blk : transitBlocks) {
1071                            log.debug("Checking Block[{}] t[{}] BlockSequ[{}]",
1072                                    blk.getDisplayName(),
1073                                    ixCount,
1074                                    transitBlockSeq.get(ixCount));
1075                            if (ixCountStart == -1 && blk == startingBlockBoxList.get(ixStart)) {
1076                                log.trace("ixOne[{}]block[{}]",ixCount,blk.getDisplayName());
1077                                ixCountStart = ixCount;
1078                            } else if (ixCountStart != -1 && ixCountVia == -1 && blk == viaBlockBoxList.get(ixVia)) {
1079                                log.trace("ixTwo[{}]block[{}]",ixCount,blk.getDisplayName());
1080                                if (ixCount != ixCountStart + 1) {
1081                                    log.debug("AdHoc {}:via and start not ajacent",tr.getDisplayName());
1082                                    break;
1083                                }
1084                                ixCountVia = ixCount;
1085                            } else if (ixCountStart != -1 && ixCountVia != -1 && ixCountDest == -1 && blk == destinationBlockBoxList.get(ixEnd)) {
1086                                ixCountDest = ixCount;
1087                                log.trace("ixThree[{}]block[{}]",ixCountDest,blk.getDisplayName());
1088                                break;
1089                            }
1090                            ixCount++;
1091                        }
1092                        if (ixCountVia == (ixCountStart + 1) && ixCountDest > ixCountStart) {
1093                            log.debug("Canuse [{}", tr.getDisplayName());
1094                            Integer routeBlockLength =
1095                                    transitBlockSeq.get(ixCountDest) - transitBlockSeq.get(ixCountStart);
1096                            if (routeBlockLength < routeCount) {
1097                                routeCount = ixCountDest - ixCountStart;
1098                                tmpTransit = tr;
1099                                startBlockSeq = transitBlockSeq.get(ixCountStart).intValue();
1100                                endBlockSeq = transitBlockSeq.get(ixCountDest).intValue();
1101                            }
1102                        }
1103                    }
1104                }
1105                if (tmpTransit != null &&
1106                        (JmriJOptionPane.showConfirmDialog(this, Bundle.getMessage("Question6",tmpTransit.getDisplayName()),
1107                                "Question",
1108                                JmriJOptionPane.YES_NO_OPTION,
1109                                JmriJOptionPane.QUESTION_MESSAGE) == JmriJOptionPane.YES_OPTION)) {
1110                    // use transit found
1111                    trainInfo.setDynamicTransit(false);
1112                    trainInfo.setTransitName(tmpTransit.getDisplayName());
1113                    trainInfo.setTransitId(tmpTransit.getDisplayName());
1114                    trainInfo.setStartBlockSeq(startBlockSeq);
1115                    trainInfo.setStartBlockName(getBlockName(startingBlockBoxList.get(ixStart)) + "-" + startBlockSeq);
1116                    trainInfo.setDestinationBlockSeq(endBlockSeq);
1117                    trainInfo.setDestinationBlockName(getBlockName(destinationBlockBoxList.get(ixEnd)) + "-" + endBlockSeq);
1118                    trainInfoToDialog(trainInfo);
1119                } else {
1120                    // use a true ad-hoc
1121                    List<LayoutBlock> blockList = _dispatcher.getAdHocRoute(startingBlockBoxList.get(ixStart),
1122                            destinationBlockBoxList.get(ixEnd),
1123                            viaBlockBoxList.get(ixVia));
1124                    if (blockList == null) {
1125                        JmriJOptionPane.showMessageDialog(initiateFrame, Bundle.getMessage("Error51"),
1126                                Bundle.getMessage("ErrorTitle"), JmriJOptionPane.ERROR_MESSAGE);
1127                        return;
1128                    }
1129                }
1130            }
1131            _dispatcher.loadTrainFromTrainInfoThrowsException(trainInfo,"NONE","");
1132        } catch (IllegalArgumentException ex) {
1133            JmriJOptionPane.showMessageDialog(initiateFrame, ex.getMessage(),
1134                    Bundle.getMessage("ErrorTitle"), JmriJOptionPane.ERROR_MESSAGE);
1135        }
1136    }
1137
1138    private void initializeFreeTransitsCombo(List<Transit> transitList) {
1139        Set<Transit> excludeTransits = new HashSet<>();
1140        for (Transit t : _TransitManager.getNamedBeanSet()) {
1141            if (t.getState() != Transit.IDLE) {
1142                excludeTransits.add(t);
1143            }
1144        }
1145        transitSelectBox.setExcludedItems(excludeTransits);
1146        JComboBoxUtil.setupComboBoxMaxRows(transitSelectBox);
1147
1148        if (transitSelectBox.getItemCount() > 0) {
1149            transitSelectBox.setSelectedIndex(0);
1150            selectedTransit = transitSelectBox.getItemAt(0);
1151        } else {
1152            selectedTransit = null;
1153        }
1154    }
1155
1156    private void initializeFreeRosterEntriesCombo() {
1157        rosterComboBox.update();
1158        // remove used entries
1159        for (int ix = rosterComboBox.getItemCount() - 1; ix > 1; ix--) {  // remove from back first item is the "select loco" message
1160            if ( !_dispatcher.isAddressFree( ((RosterEntry)rosterComboBox.getItemAt(ix)).getDccLocoAddress().getNumber() ) ) {
1161                rosterComboBox.removeItemAt(ix);
1162            }
1163        }
1164    }
1165
1166    private void initializeFreeTrainsCombo() {
1167        Train prevValue = null;
1168        if (trainSelectBox.getSelectedIndex() > 0) {
1169            // item zero is a string
1170            prevValue = (Train)trainSelectBox.getSelectedItem();
1171        }
1172        ActionListener[] als = trainSelectBox.getActionListeners();
1173        for ( ActionListener al: als) {
1174            trainSelectBox.removeActionListener(al);
1175        }
1176        trainSelectBox.removeAllItems();
1177        trainSelectBox.addItem("Select Train");
1178        // initialize free trains from operations
1179        List<Train> trains = jmri.InstanceManager.getDefault(TrainManager.class).getTrainsByNameList();
1180        if (trains.size() > 0) {
1181            for (int i = 0; i < trains.size(); i++) {
1182                Train t = trains.get(i);
1183                if (t != null) {
1184                    String tName = t.getName();
1185                    if (_dispatcher.isTrainFree(tName)) {
1186                        trainSelectBox.addItem(t);
1187                    }
1188                }
1189            }
1190        }
1191        if (prevValue != null) {
1192            trainSelectBox.setSelectedItem(prevValue);
1193        }
1194        for ( ActionListener al: als) {
1195            trainSelectBox.addActionListener(al);
1196        }
1197    }
1198
1199    /**
1200     * Sets the labels and inputs for speed profile running
1201     * @param b True if the roster entry has valid speed profile else false
1202     */
1203    private void setSpeedProfileOptions(TrainInfo info,boolean b) {
1204        useSpeedProfileLabel.setEnabled(b);
1205        useSpeedProfileCheckBox.setEnabled(b);
1206        stopBySpeedProfileLabel.setEnabled(b);
1207        stopBySpeedProfileCheckBox.setEnabled(b);
1208        stopBySpeedProfileAdjustLabel.setEnabled(b);
1209        stopBySpeedProfileAdjustSpinner.setEnabled(b);
1210        if (!b) {
1211            useSpeedProfileCheckBox.setSelected(false);
1212            stopBySpeedProfileCheckBox.setSelected(false);
1213
1214        }
1215    }
1216
1217    private void initializeStartingBlockCombo() {
1218        String prevValue = (String)startingBlockBox.getSelectedItem();
1219        startingBlockBox.removeAllItems();
1220        startingBlockBoxList.clear();
1221        if (!inTransitBox.isSelected() && selectedTransit.getEntryBlocksList().isEmpty()) {
1222            inTransitBox.setSelected(true);
1223        }
1224        if (inTransitBox.isSelected()) {
1225            startingBlockBoxList = selectedTransit.getInternalBlocksList();
1226        } else {
1227            startingBlockBoxList = selectedTransit.getEntryBlocksList();
1228        }
1229        startingBlockSeqList = selectedTransit.getBlockSeqList();
1230        boolean found = false;
1231        for (int i = 0; i < startingBlockBoxList.size(); i++) {
1232            Block b = startingBlockBoxList.get(i);
1233            int seq = startingBlockSeqList.get(i).intValue();
1234            startingBlockBox.addItem(getBlockName(b) + "-" + seq);
1235            if (!found && b.getState() == Block.OCCUPIED) {
1236                startingBlockBox.setSelectedItem(getBlockName(b) + "-" + seq);
1237                found = true;
1238            }
1239        }
1240        if (prevValue != null) {
1241            startingBlockBox.setSelectedItem(prevValue);
1242        }
1243        JComboBoxUtil.setupComboBoxMaxRows(startingBlockBox);
1244    }
1245
1246    private void initializeDestinationBlockCombo() {
1247        String prevValue = (String)destinationBlockBox.getSelectedItem();
1248        destinationBlockBox.removeAllItems();
1249        destinationBlockBoxList.clear();
1250        int index = startingBlockBox.getSelectedIndex();
1251        if (index < 0) {
1252            return;
1253        }
1254        Block startBlock = startingBlockBoxList.get(index);
1255        destinationBlockBoxList = selectedTransit.getDestinationBlocksList(
1256                startBlock, inTransitBox.isSelected());
1257        destinationBlockSeqList = selectedTransit.getDestBlocksSeqList();
1258        for (int i = 0; i < destinationBlockBoxList.size(); i++) {
1259            Block b = destinationBlockBoxList.get(i);
1260            String bName = getBlockName(b);
1261            if (selectedTransit.getBlockCount(b) > 1) {
1262                int seq = destinationBlockSeqList.get(i).intValue();
1263                bName = bName + "-" + seq;
1264            }
1265            destinationBlockBox.addItem(bName);
1266        }
1267        if (prevValue != null) {
1268            destinationBlockBox.setSelectedItem(prevValue);
1269        }
1270        JComboBoxUtil.setupComboBoxMaxRows(destinationBlockBox);
1271    }
1272
1273    private String getBlockName(Block b) {
1274        if (b != null) {
1275            return b.getDisplayName();
1276        }
1277        return " ";
1278    }
1279
1280    protected void showActivateFrame() {
1281        if (initiateFrame != null) {
1282            initializeFreeTransitsCombo(new ArrayList<Transit>());
1283            initiateFrame.setVisible(true);
1284        } else {
1285            _dispatcher.newTrainDone(null);
1286        }
1287    }
1288
1289    public void showActivateFrame(RosterEntry re) {
1290        showActivateFrame();
1291    }
1292
1293    protected void loadTrainInfo(ActionEvent e) {
1294        List<TrainInfoFileSummary> names = _tiFile.getTrainInfoFileSummaries();
1295        if (names.size() > 0) {
1296            JTable table = new JTable(){
1297                @Override
1298                public Dimension getPreferredScrollableViewportSize() {
1299                  return new Dimension(super.getPreferredSize().width,
1300                      super.getPreferredScrollableViewportSize().height);
1301                }
1302              };
1303            DefaultTableModel tm = new DefaultTableModel(
1304                    new Object[]{
1305                            Bundle.getMessage("FileNameColumnTitle"),
1306                            Bundle.getMessage("TrainColumnTitle"),
1307                            Bundle.getMessage("TransitColumnTitle"),
1308                            Bundle.getMessage("StartBlockColumnTitle"),
1309                            Bundle.getMessage("EndBlockColumnTitle"),
1310                            Bundle.getMessage("DccColumnTitleColumnTitle")
1311                    }, 0) {
1312                @Override
1313                public boolean isCellEditable(int row, int column) {
1314                    //all cells false
1315                    return false;
1316                }
1317            };
1318
1319            table.setModel(tm);
1320            for (TrainInfoFileSummary fs: names) {
1321                tm.addRow(new Object[] {fs.getFileName(),fs.getTrainName(),
1322                        fs.getTransitName(),fs.getStartBlockName()
1323                        ,fs.getEndBlockName(),fs.getDccAddress()});
1324            }
1325            JPanel jp = new JPanel(new BorderLayout());
1326            TableColumnModel columnModel = table.getColumnModel();
1327            table.setAutoResizeMode( JTable.AUTO_RESIZE_OFF );
1328            for (int column = 0; column < table.getColumnCount(); column++) {
1329                int width = 30; // Min width
1330                for (int row = 0; row < table.getRowCount(); row++) {
1331                    TableCellRenderer renderer = table.getCellRenderer(row, column);
1332                    Component comp = table.prepareRenderer(renderer, row, column);
1333                    width = Math.max(comp.getPreferredSize().width +1 , width);
1334                }
1335                if(width > 300)
1336                    width=300;
1337                columnModel.getColumn(column).setPreferredWidth(width);
1338            }
1339            //jp.setPreferredSize(table.getPreferredSize());
1340            jp.add(table);
1341            JScrollPane sp = new JScrollPane(table,
1342                            ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED,
1343                            ScrollPaneConstants.HORIZONTAL_SCROLLBAR_AS_NEEDED);
1344            int optionSelected = JmriJOptionPane.showOptionDialog(initiateFrame,
1345                    sp, Bundle.getMessage("LoadTrainTitle"), JmriJOptionPane.OK_CANCEL_OPTION, JmriJOptionPane.PLAIN_MESSAGE,
1346                    null,null,null);
1347            if (optionSelected != JmriJOptionPane.OK_OPTION) {
1348                //Canceled
1349                return;
1350            }
1351            if (table.getSelectedRow() < 0) {
1352                return;
1353            }
1354            String selName = (String)table.getModel().getValueAt(table.getSelectedRow(),0);
1355            if ((selName == null) || (selName.isEmpty())) {
1356                return;
1357            }
1358            //read xml data from selected filename and move it into the new train dialog box
1359            _trainInfoName = selName;
1360            try {
1361                trainInfo = _tiFile.readTrainInfo( selName);
1362                if (trainInfo != null) {
1363                    // process the information just read
1364                    trainInfoToDialog(trainInfo);
1365                }
1366            } catch (java.io.IOException ioe) {
1367                log.error("IO Exception when reading train info file", ioe);
1368            } catch (org.jdom2.JDOMException jde) {
1369                log.error("JDOM Exception when reading train info file", jde);
1370            }
1371            handleDelayStartClick(null);
1372            handleReverseAtEndBoxClick(null);
1373        }
1374    }
1375
1376    private void saveTrainInfo(ActionEvent e) {
1377        saveTrainInfo(false);
1378        refreshNextTrainCombo();
1379    }
1380
1381    private void saveTrainInfoAsTemplate(ActionEvent e) {
1382        saveTrainInfo(true);
1383    }
1384
1385    private void saveTrainInfo(boolean asTemplate) {
1386        try {
1387            dialogToTrainInfo(trainInfo);
1388        } catch (IllegalArgumentException ide) {
1389            JmriJOptionPane.showMessageDialog(initiateFrame, ide.getMessage(),
1390                    Bundle.getMessage("ErrorTitle"), JmriJOptionPane.ERROR_MESSAGE);
1391            return;
1392        }
1393        // get file name
1394        String fileName;
1395        if (asTemplate) {
1396            fileName = normalizeXmlFileName(nameOfTemplateFile);
1397        } else {
1398            String eName = "";
1399            eName = JmriJOptionPane.showInputDialog(initiateFrame,
1400                    Bundle.getMessage("EnterFileName") + " :", _trainInfoName);
1401            if (eName == null) {  //Cancel pressed
1402                return;
1403            }
1404            if (eName.length() < 1) {
1405                JmriJOptionPane.showMessageDialog(initiateFrame, Bundle.getMessage("Error25"),
1406                        Bundle.getMessage("ErrorTitle"), JmriJOptionPane.ERROR_MESSAGE);
1407                return;
1408            }
1409            fileName = normalizeXmlFileName(eName);
1410            _trainInfoName = fileName;
1411        }
1412        // check if train info file name is in use
1413        String[] names = _tiFile.getTrainInfoFileNames();
1414        if (names.length > 0) {
1415            boolean found = false;
1416            for (int i = 0; i < names.length; i++) {
1417                if (fileName.equals(names[i])) {
1418                    found = true;
1419                }
1420            }
1421            if (found) {
1422                // file by that name is already present
1423                int selectedValue = JmriJOptionPane.showOptionDialog(initiateFrame,
1424                        Bundle.getMessage("Question3", fileName),
1425                        Bundle.getMessage("WarningTitle"), JmriJOptionPane.DEFAULT_OPTION,
1426                        JmriJOptionPane.QUESTION_MESSAGE, null,
1427                        new Object[]{Bundle.getMessage("ButtonReplace"),Bundle.getMessage("ButtonNo")},
1428                        Bundle.getMessage("ButtonNo"));
1429                if (selectedValue != 0 ) { // array position 0 , replace not selected
1430                    return;   // return without writing if "No" response
1431                }
1432            }
1433        }
1434        // write the Train Info file
1435        try {
1436            _tiFile.writeTrainInfo(trainInfo, fileName);
1437        } //catch (org.jdom2.JDOMException jde) {
1438        // log.error("JDOM exception writing Train Info: "+jde);
1439        //}
1440        catch (java.io.IOException ioe) {
1441            log.error("IO exception writing Train Info", ioe);
1442        }
1443    }
1444
1445    private void deleteTrainInfo(ActionEvent e) {
1446        String[] names = _tiFile.getTrainInfoFileNames();
1447        if (names.length > 0) {
1448            Object selName = JmriJOptionPane.showInputDialog(initiateFrame,
1449                    Bundle.getMessage("DeleteTrainChoice"), Bundle.getMessage("DeleteTrainTitle"),
1450                    JmriJOptionPane.QUESTION_MESSAGE, null, names, names[0]);
1451            if ((selName == null) || (((String) selName).equals(""))) {
1452                return;
1453            }
1454            _tiFile.deleteTrainInfoFile((String) selName);
1455        }
1456    }
1457
1458    private void trainInfoToDialog(TrainInfo info) {
1459        if (!info.getDynamicTransit()) {
1460            radioTransitsPredefined.setSelected(true);
1461            if (!info.getTransitName().isEmpty()) {
1462                try {
1463                    transitSelectBox.setSelectedItemByName(info.getTransitName());
1464                } catch (Exception ex) {
1465                    log.warn("Transit {} from file not in Transit menu", info.getTransitName());
1466                    JmriJOptionPane.showMessageDialog(initiateFrame,
1467                            Bundle.getMessage("TransitWarn", info.getTransitName()),
1468                            null, JmriJOptionPane.WARNING_MESSAGE);
1469                }
1470            }
1471        } else {
1472            radioTransitsAdHoc.setSelected(true);
1473        }
1474        switch (info.getTrainsFrom()) {
1475            case TRAINSFROMROSTER:
1476                radioTrainsFromRoster.setSelected(true);
1477                if (!info.getRosterId().isEmpty()) {
1478                    if (!setRosterComboBox(rosterComboBox, info.getRosterId())) {
1479                        log.warn("Roster {} from file not in Roster Combo", info.getRosterId());
1480                        JmriJOptionPane.showMessageDialog(initiateFrame,
1481                                Bundle.getMessage("TrainWarn", info.getRosterId()),
1482                                null, JmriJOptionPane.WARNING_MESSAGE);
1483                    }
1484                }
1485                break;
1486            case TRAINSFROMOPS:
1487                radioTrainsFromOps.setSelected(true);
1488                if (!info.getTrainName().isEmpty()) {
1489                    if (!setTrainComboBox(trainSelectBox, info.getTrainName())) {
1490                        log.warn("Train {} from file not in Train Combo", info.getTrainName());
1491                        JmriJOptionPane.showMessageDialog(initiateFrame,
1492                                Bundle.getMessage("TrainWarn", info.getTrainName()),
1493                                null, JmriJOptionPane.WARNING_MESSAGE);
1494                    }
1495                }
1496                break;
1497            case TRAINSFROMUSER:
1498                radioTrainsFromUser.setSelected(true);
1499                dccAddressSpinner.setValue(Integer.parseInt(info.getDccAddress()));
1500                break;
1501            case TRAINSFROMSETLATER:
1502            default:
1503                radioTrainsFromSetLater.setSelected(true);
1504        }
1505        trainNameField.setText(info.getTrainUserName());
1506        trainDetectionComboBox.setSelectedItemByValue(info.getTrainDetection());
1507        inTransitBox.setSelected(info.getTrainInTransit());
1508        if (radioTransitsAdHoc.isSelected()) {
1509            initializeStartingBlockComboDynamic();
1510        } else {
1511            initializeStartingBlockCombo();
1512        }
1513        setComboBox(startingBlockBox, info.getStartBlockName());
1514        if (radioTransitsAdHoc.isSelected()) {
1515            initializeViaBlockDynamicCombo();
1516            setComboBox(viaBlockBox, info.getViaBlockName());
1517        }
1518        if (radioTransitsAdHoc.isSelected()) {
1519            initializeDestinationBlockDynamicCombo();
1520        } else {
1521            initializeDestinationBlockCombo();
1522        }
1523        setComboBox(destinationBlockBox, info.getDestinationBlockName());
1524
1525        setAllocateMethodButtons(info.getAllocationMethod());
1526        prioritySpinner.setValue(info.getPriority());
1527        resetWhenDoneBox.setSelected(info.getResetWhenDone());
1528        reverseAtEndBox.setSelected(info.getReverseAtEnd());
1529        setDelayModeBox(info.getDelayedStart(), delayedStartBox);
1530        //delayedStartBox.setSelected(info.getDelayedStart());
1531        departureHrSpinner.setValue(info.getDepartureTimeHr());
1532        departureMinSpinner.setValue(info.getDepartureTimeMin());
1533        delaySensor.setSelectedItem(info.getDelaySensor());
1534        resetStartSensorBox.setSelected(info.getResetStartSensor());
1535        setDelayModeBox(info.getDelayedRestart(), delayedReStartBox);
1536        delayMinSpinner.setValue(info.getRestartDelayMin());
1537        delayReStartSensor.setSelectedItem(info.getRestartSensor());
1538        resetRestartSensorBox.setSelected(info.getResetRestartSensor());
1539
1540        resetStartSensorBox.setSelected(info.getResetStartSensor());
1541        setDelayModeBox(info.getReverseDelayedRestart(), reverseDelayedRestartType);
1542        delayReverseMinSpinner.setValue(info.getReverseRestartDelayMin());
1543        delayReverseReStartSensor.setSelectedItem(info.getReverseRestartSensor());
1544        delayReverseResetSensorBox.setSelected(info.getReverseResetRestartSensor());
1545
1546        terminateWhenDoneBox.setSelected(info.getTerminateWhenDone());
1547        nextTrain.setSelectedIndex(-1);
1548        try {
1549            nextTrain.setSelectedItem(info.getNextTrain());
1550        } catch (Exception ex){
1551            nextTrain.setSelectedIndex(-1);
1552        }
1553        handleTerminateWhenDoneBoxClick(null);
1554        setComboBox(trainTypeBox, info.getTrainType());
1555        autoRunBox.setSelected(info.getAutoRun());
1556        loadAtStartupBox.setSelected(info.getLoadAtStartup());
1557        setAllocateMethodButtons(info.getAllocationMethod());
1558        autoTrainInfoToDialog(info);
1559    }
1560
1561    private boolean validateDialog() throws IllegalArgumentException {
1562        int index = transitSelectBox.getSelectedIndex();
1563        if (index < 0) {
1564            throw new IllegalArgumentException(Bundle.getMessage("Error44"));
1565        }
1566        switch (trainsFromButtonGroup.getSelection().getActionCommand()) {
1567            case "TRAINSFROMROSTER":
1568                if (rosterComboBox.getSelectedIndex() < 1 ) {
1569                    throw new IllegalArgumentException(Bundle.getMessage("Error41"));
1570                }
1571                break;
1572            case "TRAINSFROMOPS":
1573                if (trainSelectBox.getSelectedIndex() < 1) {
1574                    throw new IllegalArgumentException(Bundle.getMessage("Error42"));
1575                }
1576                break;
1577            case "TRAINSFROMUSER":
1578                if (trainNameField.getText().isEmpty()) {
1579                    throw new IllegalArgumentException(Bundle.getMessage("Error22"));
1580                }
1581                break;
1582            case "TRAINSFROMSETLATER":
1583            default:
1584        }
1585        index = startingBlockBox.getSelectedIndex();
1586        if (index < 0) {
1587            throw new IllegalArgumentException(Bundle.getMessage("Error13"));
1588        }
1589        index = destinationBlockBox.getSelectedIndex();
1590        if (index < 0) {
1591            throw new IllegalArgumentException(Bundle.getMessage("Error8"));
1592        }
1593        if (radioTransitsAdHoc.isSelected()) {
1594            index = viaBlockBox.getSelectedIndex();
1595            if (index < 0) {
1596                throw new IllegalArgumentException(Bundle.getMessage("Error8"));
1597            }
1598        }
1599        if ((!reverseAtEndBox.isSelected()) && resetWhenDoneBox.isSelected()
1600                && (!selectedTransit.canBeResetWhenDone())) {
1601            resetWhenDoneBox.setSelected(false);
1602            throw new IllegalArgumentException(Bundle.getMessage("NoResetMessage"));
1603        }
1604        int max = Math.round((float) maxSpeedSpinner.getValue()*100.0f);
1605        int min = Math.round((float) minReliableOperatingSpeedSpinner.getValue()*100.0f);
1606        if ((max-min) < 10) {
1607            throw new IllegalArgumentException(Bundle.getMessage("Error49",
1608                    maxSpeedSpinner.getValue(), minReliableOperatingSpeedSpinner.getValue()));
1609        }
1610        return true;
1611    }
1612
1613    private boolean dialogToTrainInfo(TrainInfo info) {
1614        int index = transitSelectBox.getSelectedIndex();
1615        info.setDynamicTransit(radioTransitsAdHoc.isSelected());
1616        if (!info.getDynamicTransit() && index >= 0 ) {
1617            info.setTransitName(transitSelectBox.getSelectedItem().getDisplayName());
1618            info.setTransitId(transitSelectBox.getSelectedItem().getDisplayName());
1619        }
1620        switch (trainsFromButtonGroup.getSelection().getActionCommand()) {
1621            case "TRAINSFROMROSTER":
1622                info.setRosterId(((RosterEntry) rosterComboBox.getSelectedItem()).getId());
1623                info.setDccAddress(((RosterEntry) rosterComboBox.getSelectedItem()).getDccAddress());
1624                trainInfo.setTrainsFrom(TrainsFrom.TRAINSFROMROSTER);
1625                setTrainsFromOptions(trainInfo.getTrainsFrom());
1626                break;
1627            case "TRAINSFROMOPS":
1628                info.setTrainName(((Train) trainSelectBox.getSelectedItem()).toString());
1629                info.setDccAddress(String.valueOf(dccAddressSpinner.getValue()));
1630                trainInfo.setTrainsFrom(TrainsFrom.TRAINSFROMOPS);
1631                setTrainsFromOptions(trainInfo.getTrainsFrom());
1632                break;
1633            case "TRAINSFROMUSER":
1634                trainInfo.setTrainsFrom(TrainsFrom.TRAINSFROMUSER);
1635                info.setDccAddress(String.valueOf(dccAddressSpinner.getValue()));
1636                break;
1637            case "TRAINSFROMSETLATER":
1638            default:
1639                trainInfo.setTrainsFrom(TrainsFrom.TRAINSFROMSETLATER);
1640                info.setTrainName("");
1641                info.setDccAddress("");
1642        }
1643        info.setTrainUserName(trainNameField.getText());
1644        info.setTrainInTransit(inTransitBox.isSelected());
1645        info.setStartBlockName((String) startingBlockBox.getSelectedItem());
1646        index = startingBlockBox.getSelectedIndex();
1647        info.setStartBlockId(startingBlockBoxList.get(index).getDisplayName());
1648        if (info.getDynamicTransit()) {
1649            info.setStartBlockSeq(1);
1650        } else {
1651            info.setStartBlockSeq(startingBlockSeqList.get(index).intValue());
1652        }
1653        index = destinationBlockBox.getSelectedIndex();
1654        info.setDestinationBlockId(destinationBlockBoxList.get(index).getDisplayName());
1655        info.setDestinationBlockName(destinationBlockBoxList.get(index).getDisplayName());
1656        if (info.getDynamicTransit()) {
1657            info.setViaBlockName(viaBlockBoxList.get(viaBlockBox.getSelectedIndex()).getDisplayName());
1658        } else {
1659            info.setDestinationBlockSeq(destinationBlockSeqList.get(index).intValue());
1660        }
1661        info.setPriority((Integer) prioritySpinner.getValue());
1662        info.setTrainDetection(((TrainDetectionItem)trainDetectionComboBox.getSelectedItem()).value);
1663        info.setResetWhenDone(resetWhenDoneBox.isSelected());
1664        info.setReverseAtEnd(reverseAtEndBox.isSelected());
1665        info.setDelayedStart(delayModeFromBox(delayedStartBox));
1666        info.setDelaySensorName(delaySensor.getSelectedItemDisplayName());
1667        info.setResetStartSensor(resetStartSensorBox.isSelected());
1668        info.setDepartureTimeHr((Integer) departureHrSpinner.getValue());
1669        info.setDepartureTimeMin((Integer) departureMinSpinner.getValue());
1670        info.setTrainType((String) trainTypeBox.getSelectedItem());
1671        info.setAutoRun(autoRunBox.isSelected());
1672        info.setLoadAtStartup(loadAtStartupBox.isSelected());
1673        info.setAllocateAllTheWay(false); // force to false next field is now used.
1674        if (allocateAllTheWayRadioButton.isSelected()) {
1675            info.setAllocationMethod(ActiveTrain.ALLOCATE_AS_FAR_AS_IT_CAN);
1676        } else if (allocateBySafeRadioButton.isSelected()) {
1677            info.setAllocationMethod(ActiveTrain.ALLOCATE_BY_SAFE_SECTIONS);
1678        } else {
1679            info.setAllocationMethod((Integer) allocateCustomSpinner.getValue());
1680        }
1681        info.setDelayedRestart(delayModeFromBox(delayedReStartBox));
1682        info.setRestartSensorName(delayReStartSensor.getSelectedItemDisplayName());
1683        info.setResetRestartSensor(resetRestartSensorBox.isSelected());
1684        info.setRestartDelayMin((Integer) delayMinSpinner.getValue());
1685
1686        info.setReverseDelayedRestart(delayModeFromBox(reverseDelayedRestartType));
1687        info.setReverseRestartSensorName(delayReverseReStartSensor.getSelectedItemDisplayName());
1688        info.setReverseResetRestartSensor(delayReverseResetSensorBox.isSelected());
1689        info.setReverseRestartDelayMin((Integer) delayReverseMinSpinner.getValue());
1690
1691        info.setTerminateWhenDone(terminateWhenDoneBox.isSelected());
1692        if (nextTrain.getSelectedIndex() > 0 ) {
1693            info.setNextTrain((String)nextTrain.getSelectedItem());
1694        } else {
1695            info.setNextTrain("None");
1696        }
1697        autoRunItemsToTrainInfo(info);
1698        return true;
1699    }
1700
1701    private boolean setRosterComboBox(RosterEntryComboBox box, String txt) {
1702        boolean found = false;
1703        for (int i = 1; i < box.getItemCount(); i++) {
1704            if (txt.equals(((RosterEntry) box.getItemAt(i)).getId())) {
1705                box.setSelectedIndex(i);
1706                found = true;
1707                break;
1708            }
1709        }
1710        if (!found && box.getItemCount() > 0) {
1711            box.setSelectedIndex(0);
1712        }
1713        return found;
1714    }
1715
1716    // Normalizes a suggested xml file name.  Returns null string if a valid name cannot be assembled
1717    private String normalizeXmlFileName(String name) {
1718        if (name.length() < 1) {
1719            return "";
1720        }
1721        String newName = name;
1722        // strip off .xml or .XML if present
1723        if ((name.endsWith(".xml")) || (name.endsWith(".XML"))) {
1724            newName = name.substring(0, name.length() - 4);
1725            if (newName.length() < 1) {
1726                return "";
1727            }
1728        }
1729        // replace all non-alphanumeric characters with underscore
1730        newName = newName.replaceAll("[\\W]", "_");
1731        return (newName + ".xml");
1732    }
1733
1734    private boolean setTrainComboBox(JComboBox<Object> box, String txt) {
1735        boolean found = false;
1736        for (int i = 1; i < box.getItemCount(); i++) { //skip the select train item
1737            if (txt.equals(box.getItemAt(i).toString())) {
1738                box.setSelectedIndex(i);
1739                found = true;
1740                break;
1741            }
1742        }
1743        if (!found && box.getItemCount() > 0) {
1744            box.setSelectedIndex(0);
1745        }
1746        return found;
1747    }
1748
1749    private boolean setComboBox(JComboBox<String> box, String txt) {
1750        boolean found = false;
1751        for (int i = 0; i < box.getItemCount(); i++) {
1752            if (txt.equals(box.getItemAt(i))) {
1753                box.setSelectedIndex(i);
1754                found = true;
1755                break;
1756            }
1757        }
1758        if (!found && box.getItemCount() > 0) {
1759            box.setSelectedIndex(0);
1760        }
1761        return found;
1762    }
1763
1764    int delayModeFromBox(JComboBox<String> box) {
1765        String mode = (String) box.getSelectedItem();
1766        int result = jmri.util.StringUtil.getStateFromName(mode, delayedStartInt, delayedStartString);
1767
1768        if (result < 0) {
1769            log.warn("unexpected mode string in turnoutMode: {}", mode);
1770            throw new IllegalArgumentException();
1771        }
1772        return result;
1773    }
1774
1775    void setDelayModeBox(int mode, JComboBox<String> box) {
1776        String result = jmri.util.StringUtil.getNameFromState(mode, delayedStartInt, delayedStartString);
1777        box.setSelectedItem(result);
1778    }
1779
1780    /**
1781     * The following are for items that are only for automatic running of
1782     * ActiveTrains They are isolated here to simplify changing them in the
1783     * future.
1784     * <ul>
1785     * <li>initializeAutoRunItems - initializes the display of auto run items in
1786     * this window
1787     * <li>initializeAutoRunValues - initializes the values of auto run items
1788     * from values in a saved train info file hideAutoRunItems - hides all auto
1789     * run items in this window showAutoRunItems - shows all auto run items in
1790     * this window
1791     * <li>autoTrainInfoToDialog - gets auto run items from a train info, puts
1792     * values in items, and initializes auto run dialog items
1793     * <li>autoTrainItemsToTrainInfo - copies values of auto run items to train
1794     * info for saving to a file
1795     * <li>readAutoRunItems - reads and checks values of all auto run items.
1796     * returns true if OK, sends appropriate messages and returns false if not
1797     * OK
1798     * <li>setAutoRunItems - sets the user entered auto run items in the new
1799     * AutoActiveTrain
1800     * </ul>
1801     */
1802    // auto run items in ActivateTrainFrame
1803    private final JPanel pa1 = new JPanel();
1804    private final JLabel speedFactorLabel = new JLabel(Bundle.getMessage("SpeedFactorLabel"));
1805    private final JSpinner speedFactorSpinner = new JSpinner();
1806    private final JLabel minReliableOperatingSpeedLabel = new JLabel(Bundle.getMessage("MinReliableOperatingSpeedLabel"));
1807    private final JSpinner minReliableOperatingSpeedSpinner = new JSpinner();
1808    private final JLabel maxSpeedLabel = new JLabel(Bundle.getMessage("MaxSpeedLabel"));
1809    private final JSpinner maxSpeedSpinner = new JSpinner();
1810    private final JPanel pa2 = new JPanel();
1811    private final JLabel rampRateLabel = new JLabel(Bundle.getMessage("RampRateBoxLabel"));
1812    private final JComboBox<String> rampRateBox = new JComboBox<>();
1813    private final JPanel pa2a = new JPanel();
1814    private final JLabel useSpeedProfileLabel = new JLabel(Bundle.getMessage("UseSpeedProfileLabel"));
1815    private final JCheckBox useSpeedProfileCheckBox = new JCheckBox( );
1816    private final JLabel stopBySpeedProfileLabel = new JLabel(Bundle.getMessage("StopBySpeedProfileLabel"));
1817    private final JCheckBox stopBySpeedProfileCheckBox = new JCheckBox( );
1818    private final JLabel stopBySpeedProfileAdjustLabel = new JLabel(Bundle.getMessage("StopBySpeedProfileAdjustLabel"));
1819    private final JSpinner stopBySpeedProfileAdjustSpinner = new JSpinner();
1820    private final JPanel pa3 = new JPanel();
1821    private final JCheckBox soundDecoderBox = new JCheckBox(Bundle.getMessage("SoundDecoder"));
1822    private final JCheckBox runInReverseBox = new JCheckBox(Bundle.getMessage("RunInReverse"));
1823    private final JPanel pa4 = new JPanel();
1824
1825    protected static class TrainDetectionJCombo extends JComboBox<TrainDetectionItem> {
1826        public void setSelectedItemByValue(TrainDetection var) {
1827            for ( int ix = 0; ix < getItemCount() ; ix ++ ) {
1828                if (getItemAt(ix).value == var) {
1829                    this.setSelectedIndex(ix);
1830                    break;
1831                }
1832            }
1833        }
1834    }
1835    private final JLabel trainDetectionLabel = new JLabel(Bundle.getMessage("TrainDetection"));
1836    public final TrainDetectionJCombo trainDetectionComboBox
1837    = new TrainDetectionJCombo();
1838
1839    protected static class TrainLengthUnitsJCombo extends JComboBox<TrainLengthUnitsItem> {
1840        public void setSelectedItemByValue(TrainLengthUnits var) {
1841            for ( int ix = 0; ix < getItemCount() ; ix ++ ) {
1842                if (getItemAt(ix).value == var) {
1843                    this.setSelectedIndex(ix);
1844                    break;
1845                }
1846            }
1847        }
1848    }
1849    public final TrainLengthUnitsJCombo trainLengthUnitsComboBox = new TrainLengthUnitsJCombo();
1850    private final JLabel trainLengthLabel = new JLabel(Bundle.getMessage("MaxTrainLengthLabel"));
1851    private JLabel trainLengthAltLengthLabel;
1852    private final JSpinner maxTrainLengthSpinner = new JSpinner(); // initialized later
1853
1854    private void initializeAutoRunItems() {
1855        initializeRampCombo();
1856        initializeScaleLengthBox();
1857        pa1.setLayout(new FlowLayout());
1858        pa1.add(speedFactorLabel);
1859        speedFactorSpinner.setModel(new SpinnerNumberModel(Float.valueOf(1.0f), Float.valueOf(0.1f), Float.valueOf(2.0f), Float.valueOf(0.01f)));
1860        speedFactorSpinner.setEditor(new JSpinner.NumberEditor(speedFactorSpinner, "# %"));
1861        pa1.add(speedFactorSpinner);
1862        speedFactorSpinner.setToolTipText(Bundle.getMessage("SpeedFactorHint"));
1863        pa1.add(new JLabel("   "));
1864        pa1.add(maxSpeedLabel);
1865        maxSpeedSpinner.setModel(new SpinnerNumberModel(Float.valueOf(1.0f), Float.valueOf(0.1f), Float.valueOf(1.0f), Float.valueOf(0.01f)));
1866        maxSpeedSpinner.setEditor(new JSpinner.NumberEditor(maxSpeedSpinner, "# %"));
1867        pa1.add(maxSpeedSpinner);
1868        maxSpeedSpinner.setToolTipText(Bundle.getMessage("MaxSpeedHint"));
1869        pa1.add(minReliableOperatingSpeedLabel);
1870        minReliableOperatingSpeedSpinner.setModel(new SpinnerNumberModel(Float.valueOf(0.0f), Float.valueOf(0.0f), Float.valueOf(1.0f), Float.valueOf(0.01f)));
1871        minReliableOperatingSpeedSpinner.setEditor(new JSpinner.NumberEditor(minReliableOperatingSpeedSpinner, "# %"));
1872        pa1.add(minReliableOperatingSpeedSpinner);
1873        minReliableOperatingSpeedSpinner.setToolTipText(Bundle.getMessage("MinReliableOperatingSpeedHint"));
1874        initiatePane.add(pa1);
1875        pa2.setLayout(new FlowLayout());
1876        pa2.add(rampRateLabel);
1877        pa2.add(rampRateBox);
1878        rampRateBox.setToolTipText(Bundle.getMessage("RampRateBoxHint"));
1879        pa2.add(useSpeedProfileLabel);
1880        pa2.add(useSpeedProfileCheckBox);
1881        useSpeedProfileCheckBox.setToolTipText(Bundle.getMessage("UseSpeedProfileHint"));
1882        initiatePane.add(pa2);
1883        pa2a.setLayout(new FlowLayout());
1884        pa2a.add(stopBySpeedProfileLabel);
1885        pa2a.add(stopBySpeedProfileCheckBox);
1886        stopBySpeedProfileCheckBox.setToolTipText(Bundle.getMessage("UseSpeedProfileHint")); // reuse identical hint for Stop
1887        pa2a.add(stopBySpeedProfileAdjustLabel);
1888        stopBySpeedProfileAdjustSpinner.setModel(new SpinnerNumberModel( Float.valueOf(1.0f), Float.valueOf(0.1f), Float.valueOf(5.0f), Float.valueOf(0.01f)));
1889        stopBySpeedProfileAdjustSpinner.setEditor(new JSpinner.NumberEditor(stopBySpeedProfileAdjustSpinner, "# %"));
1890        pa2a.add(stopBySpeedProfileAdjustSpinner);
1891        stopBySpeedProfileAdjustSpinner.setToolTipText(Bundle.getMessage("StopBySpeedProfileAdjustHint"));
1892        initiatePane.add(pa2a);
1893        pa3.setLayout(new FlowLayout());
1894        pa3.add(soundDecoderBox);
1895        soundDecoderBox.setToolTipText(Bundle.getMessage("SoundDecoderBoxHint"));
1896        pa3.add(new JLabel("   "));
1897        pa3.add(runInReverseBox);
1898        runInReverseBox.setToolTipText(Bundle.getMessage("RunInReverseBoxHint"));
1899        initiatePane.add(pa3);
1900        maxTrainLengthSpinner.setModel(new SpinnerNumberModel(Float.valueOf(18.0f), Float.valueOf(0.0f), Float.valueOf(10000.0f), Float.valueOf(0.5f)));
1901        maxTrainLengthSpinner.setEditor(new JSpinner.NumberEditor(maxTrainLengthSpinner, "###0.0"));
1902        maxTrainLengthSpinner.setToolTipText(Bundle.getMessage("MaxTrainLengthHint")); // won't be updated while Dispatcher is open
1903        maxTrainLengthSpinner.addChangeListener(new ChangeListener() {
1904            @Override
1905            public void stateChanged(ChangeEvent e) {
1906                handlemaxTrainLengthChangeUnitsLength(e);
1907            }
1908        });
1909        trainLengthUnitsComboBox.addActionListener(new ActionListener() {
1910            @Override
1911            public void actionPerformed(ActionEvent e) {
1912                handlemaxTrainLengthChangeUnitsLength(e);
1913            }
1914        });
1915        trainLengthAltLengthLabel=new JLabel();
1916        pa4.setLayout(new FlowLayout());
1917        pa4.add(trainLengthLabel);
1918        pa4.add(maxTrainLengthSpinner);
1919        pa4.add(trainLengthUnitsComboBox);
1920        pa4.add(trainLengthAltLengthLabel);
1921        initiatePane.add(pa4);
1922        hideAutoRunItems();   // initialize with auto run items hidden
1923    }
1924
1925    private void handlemaxTrainLengthChangeUnitsLength(Object e) {
1926        trainLengthAltLengthLabel.setText(maxTrainLengthCalculateAltFormatted(
1927                ((TrainLengthUnitsItem) trainLengthUnitsComboBox.getSelectedItem()).getValue(),
1928                (float) maxTrainLengthSpinner.getValue()));
1929    }
1930
1931    private String maxTrainLengthCalculateAltFormatted(TrainLengthUnits fromUnits, float fromValue) {
1932        float value = maxTrainLengthCalculateAlt(fromUnits, fromValue);
1933        switch (fromUnits) {
1934            case TRAINLENGTH_ACTUALINCHS:
1935                return String.format("%.2f %s", value, Bundle.getMessage("TrainLengthInScaleFeet"));
1936            case TRAINLENGTH_ACTUALCM:
1937                return String.format("%.1f %s", value, Bundle.getMessage("TrainLengthInScaleMeters"));
1938            case TRAINLENGTH_SCALEFEET:
1939                return String.format("%.1f %s", value, Bundle.getMessage("TrainLengthInActualInchs"));
1940            case TRAINLENGTH_SCALEMETERS:
1941                return String.format("%.0f %s", value, Bundle.getMessage("TrainLengthInActualcm"));
1942            default:
1943                log.error("Invalid TrainLengthUnits must have been updated, fix maxTrainLengthCalculateAltFormatted");
1944        }
1945        return "";
1946    }
1947
1948    private float maxTrainLengthToScaleMeters(TrainLengthUnits fromUnits, float fromValue) {
1949        float value;
1950        // convert to meters.
1951        switch (fromUnits) {
1952            case TRAINLENGTH_ACTUALINCHS:
1953                value = fromValue / 12.0f * (float) _dispatcher.getScale().getScaleRatio();
1954                value = value / 3.28084f;
1955                break;
1956            case TRAINLENGTH_ACTUALCM:
1957                value = fromValue / 100.0f * (float) _dispatcher.getScale().getScaleRatio();
1958                break;
1959           case TRAINLENGTH_SCALEFEET:
1960               value = fromValue / 3.28084f;
1961               break;
1962           case TRAINLENGTH_SCALEMETERS:
1963               value = fromValue;
1964               break;
1965           default:
1966               value = 0;
1967               log.error("Invalid TrainLengthUnits has been updated, fix me");
1968        }
1969        return value;
1970    }
1971
1972    /*
1973     * Calculates the reciprocal unit. Actual to Scale and vice versa
1974     */
1975    private float maxTrainLengthCalculateAlt(TrainLengthUnits fromUnits, float fromValue) {
1976        switch (fromUnits) {
1977            case TRAINLENGTH_ACTUALINCHS:
1978                // calc scale feet
1979                return (float) jmri.util.MathUtil.granulize(fromValue / 12 * (float) _dispatcher.getScale().getScaleRatio(),0.1f);
1980            case TRAINLENGTH_ACTUALCM:
1981                // calc scale meter
1982                return fromValue / 100 * (float) _dispatcher.getScale().getScaleRatio();
1983            case TRAINLENGTH_SCALEFEET:
1984                // calc actual inchs
1985                return fromValue * 12 * (float) _dispatcher.getScale().getScaleFactor();
1986           case TRAINLENGTH_SCALEMETERS:
1987                // calc actual cm.
1988                return fromValue * 100 * (float) _dispatcher.getScale().getScaleFactor();
1989           default:
1990               log.error("Invalid TrainLengthUnits has been updated, fix me");
1991        }
1992        return 0;
1993    }
1994
1995    private void hideAutoRunItems() {
1996        pa1.setVisible(false);
1997        pa2.setVisible(false);
1998        pa2a.setVisible(false);
1999        pa3.setVisible(false);
2000        pa4.setVisible(false);
2001    }
2002
2003    private void showAutoRunItems() {
2004        pa1.setVisible(true);
2005        pa2.setVisible(true);
2006        pa2a.setVisible(true);
2007        pa3.setVisible(true);
2008        pa4.setVisible(true);
2009    }
2010
2011    private void autoTrainInfoToDialog(TrainInfo info) {
2012        speedFactorSpinner.setValue(info.getSpeedFactor());
2013        maxSpeedSpinner.setValue(info.getMaxSpeed());
2014        minReliableOperatingSpeedSpinner.setValue(info.getMinReliableOperatingSpeed());
2015        setComboBox(rampRateBox, info.getRampRate());
2016        trainDetectionComboBox.setSelectedItemByValue(info.getTrainDetection());
2017        runInReverseBox.setSelected(info.getRunInReverse());
2018        soundDecoderBox.setSelected(info.getSoundDecoder());
2019        trainLengthUnitsComboBox.setSelectedItemByValue(info.getTrainLengthUnits());
2020        switch (info.getTrainLengthUnits()) {
2021            case TRAINLENGTH_SCALEFEET:
2022                maxTrainLengthSpinner.setValue(info.getMaxTrainLengthScaleFeet());
2023                break;
2024            case TRAINLENGTH_SCALEMETERS:
2025                maxTrainLengthSpinner.setValue(info.getMaxTrainLengthScaleMeters());
2026                break;
2027            case TRAINLENGTH_ACTUALINCHS:
2028                maxTrainLengthSpinner.setValue(info.getMaxTrainLengthScaleFeet() * 12.0f * (float)_dispatcher.getScale().getScaleFactor());
2029                break;
2030            case TRAINLENGTH_ACTUALCM:
2031                maxTrainLengthSpinner.setValue(info.getMaxTrainLengthScaleMeters() * 100.0f * (float)_dispatcher.getScale().getScaleFactor());
2032                break;
2033            default:
2034                maxTrainLengthSpinner.setValue(0.0f);
2035        }
2036        useSpeedProfileCheckBox.setSelected(info.getUseSpeedProfile());
2037        stopBySpeedProfileCheckBox.setSelected(info.getStopBySpeedProfile());
2038        stopBySpeedProfileAdjustSpinner.setValue(info.getStopBySpeedProfileAdjust());
2039        if (autoRunBox.isSelected()) {
2040            showAutoRunItems();
2041        } else {
2042            hideAutoRunItems();
2043        }
2044        initiateFrame.pack();
2045    }
2046
2047    private void autoRunItemsToTrainInfo(TrainInfo info) {
2048        info.setSpeedFactor((float) speedFactorSpinner.getValue());
2049        info.setMaxSpeed((float) maxSpeedSpinner.getValue());
2050        info.setMinReliableOperatingSpeed((float) minReliableOperatingSpeedSpinner.getValue());
2051        info.setRampRate((String) rampRateBox.getSelectedItem());
2052        info.setRunInReverse(runInReverseBox.isSelected());
2053        info.setSoundDecoder(soundDecoderBox.isSelected());
2054        info.setTrainLengthUnits(((TrainLengthUnitsItem) trainLengthUnitsComboBox.getSelectedItem()).getValue());
2055        info.setMaxTrainLengthScaleMeters(maxTrainLengthToScaleMeters( info.getTrainLengthUnits(), (float) maxTrainLengthSpinner.getValue()));
2056
2057        // Only use speed profile values if enabled
2058        if (useSpeedProfileCheckBox.isEnabled()) {
2059            info.setUseSpeedProfile(useSpeedProfileCheckBox.isSelected());
2060            info.setStopBySpeedProfile(stopBySpeedProfileCheckBox.isSelected());
2061            info.setStopBySpeedProfileAdjust((float) stopBySpeedProfileAdjustSpinner.getValue());
2062        } else {
2063            info.setUseSpeedProfile(false);
2064            info.setStopBySpeedProfile(false);
2065            info.setStopBySpeedProfileAdjust(1.0f);
2066        }
2067    }
2068
2069   private void initializeRampCombo() {
2070        rampRateBox.removeAllItems();
2071        rampRateBox.addItem(Bundle.getMessage("RAMP_NONE"));
2072        rampRateBox.addItem(Bundle.getMessage("RAMP_FAST"));
2073        rampRateBox.addItem(Bundle.getMessage("RAMP_MEDIUM"));
2074        rampRateBox.addItem(Bundle.getMessage("RAMP_MED_SLOW"));
2075        rampRateBox.addItem(Bundle.getMessage("RAMP_SLOW"));
2076        rampRateBox.addItem(Bundle.getMessage("RAMP_SPEEDPROFILE"));
2077        // Note: the order above must correspond to the numbers in AutoActiveTrain.java
2078    }
2079
2080    /**
2081     * Sets up the RadioButtons and visability of spinner for the allocation method
2082     *
2083     * @param value 0, Allocate by Safe spots, -1, allocate as far as possible Any
2084     *            other value the number of sections to allocate
2085     */
2086    private void setAllocateMethodButtons(int value) {
2087        switch (value) {
2088            case ActiveTrain.ALLOCATE_BY_SAFE_SECTIONS:
2089                allocateBySafeRadioButton.setSelected(true);
2090                allocateCustomSpinner.setVisible(false);
2091                break;
2092            case ActiveTrain.ALLOCATE_AS_FAR_AS_IT_CAN:
2093                allocateAllTheWayRadioButton.setSelected(true);
2094                allocateCustomSpinner.setVisible(false);
2095                break;
2096            default:
2097                allocateNumberOfBlocks.setSelected(true);
2098                allocateCustomSpinner.setVisible(true);
2099                allocateCustomSpinner.setValue(value);
2100        }
2101    }
2102
2103    /*
2104     * Layout block stuff
2105     */
2106    private ArrayList<LayoutBlock> getOccupiedBlockList() {
2107        LayoutBlockManager lBM = jmri.InstanceManager.getDefault(LayoutBlockManager.class);
2108        ArrayList<LayoutBlock> lBlocks = new ArrayList<LayoutBlock>();
2109        for (LayoutBlock lB : lBM.getNamedBeanSet()) {
2110            if (lB.getBlock().getState() == Block.OCCUPIED) {
2111                lBlocks.add(lB);
2112            }
2113        }
2114        return lBlocks;
2115    }
2116
2117    private void initializeStartingBlockComboDynamic() {
2118        startingBlockBox.removeAllItems();
2119        startingBlockBoxList.clear();
2120        for (LayoutBlock lB: getOccupiedBlockList()) {
2121            if (!startingBlockBoxList.contains(lB.getBlock())) {
2122                startingBlockBoxList.add(lB.getBlock());
2123                startingBlockBox.addItem(getBlockName(lB.getBlock()));
2124            }
2125        }
2126        JComboBoxUtil.setupComboBoxMaxRows(startingBlockBox);
2127    }
2128
2129    private void initializeViaBlockDynamicCombo() {
2130        String prevValue = (String) viaBlockBox.getSelectedItem();
2131        viaBlockBox.removeActionListener(viaBlockBoxListener);
2132        viaBlockBox.removeAllItems();
2133        viaBlockBoxList.clear();
2134        LayoutBlockManager lBM = jmri.InstanceManager.getDefault(LayoutBlockManager.class);
2135        if (startingBlockBox.getSelectedItem() != null) {
2136            LayoutBlock lBSrc = null;
2137            if (startingBlockBox.getSelectedIndex() >= 0) {
2138                lBSrc = lBM.getByUserName((String) startingBlockBox.getSelectedItem());
2139                if (lBSrc != null) {
2140                    int rX = lBSrc.getNumberOfNeighbours() - 1;
2141                    for (; rX > -1; rX--) {
2142                        viaBlockBox.addItem(lBSrc.getNeighbourAtIndex(rX).getDisplayName());
2143                        viaBlockBoxList.add(lBSrc.getNeighbourAtIndex(rX));
2144                    }
2145                }
2146            }
2147        }
2148        if (prevValue != null) {
2149            viaBlockBox.setSelectedItem(prevValue);
2150        }
2151        viaBlockBox.addActionListener(viaBlockBoxListener);
2152    }
2153
2154    private void initializeDestinationBlockDynamicCombo() {
2155        destinationBlockBox.removeAllItems();
2156        destinationBlockBoxList.clear();
2157        LayoutBlockManager lBM = jmri.InstanceManager.getDefault(LayoutBlockManager.class);
2158        if (startingBlockBox.getSelectedItem() != null) {
2159            LayoutBlock lBSrc = null;
2160            if (startingBlockBox.getSelectedIndex() >= 0
2161                    && viaBlockBox.getSelectedIndex() >= 0) {
2162                lBSrc = lBM.getByUserName((String) startingBlockBox.getSelectedItem());
2163                Block b = viaBlockBoxList.get(viaBlockBox.getSelectedIndex());
2164                if (lBSrc != null) {
2165                    int rX = lBSrc.getNumberOfRoutes() - 1;
2166                    for (; rX > -1; rX--) {
2167                        if (lBSrc.getRouteNextBlockAtIndex(rX) == b) {
2168                            destinationBlockBox.addItem(lBSrc.getRouteDestBlockAtIndex(rX).getDisplayName());
2169                            destinationBlockBoxList.add(lBSrc.getRouteDestBlockAtIndex(rX));
2170                        }
2171                    }
2172                }
2173            }
2174        }
2175    }
2176
2177    /*
2178     * Check Advanced routing
2179    */
2180    private boolean checkAdvancedRouting() {
2181        if (!InstanceManager.getDefault(LayoutBlockManager.class).isAdvancedRoutingEnabled()) {
2182            int response = JmriJOptionPane.showConfirmDialog(this, Bundle.getMessage("AdHocNeedsEnableBlockRouting"),
2183                    Bundle.getMessage("AdHocNeedsBlockRouting"), JmriJOptionPane.YES_NO_OPTION);
2184            if (response == 0) {
2185                InstanceManager.getDefault(LayoutBlockManager.class).enableAdvancedRouting(true);
2186                JmriJOptionPane.showMessageDialog(this, Bundle.getMessage("AdhocNeedsBlockRoutingEnabled"));
2187            } else {
2188                return false;
2189            }
2190        }
2191        return true;
2192    }
2193
2194    /*
2195     * ComboBox item.
2196     */
2197    protected static class TrainDetectionItem {
2198        private String key;
2199        private TrainDetection value;
2200        public TrainDetectionItem(String text, TrainDetection trainDetection ) {
2201            this.key = text;
2202            this.value = trainDetection;
2203        }
2204        @Override
2205        public String toString()
2206        {
2207            return key;
2208        }
2209        public String getKey()
2210        {
2211            return key;
2212        }
2213        public TrainDetection getValue()
2214        {
2215            return value;
2216        }
2217    }
2218
2219    /*
2220     * ComboBox item.
2221     */
2222    protected static class TrainLengthUnitsItem {
2223        private String key;
2224        private TrainLengthUnits value;
2225        public TrainLengthUnitsItem(String text, TrainLengthUnits trainLength ) {
2226            this.key = text;
2227            this.value = trainLength;
2228        }
2229        @Override
2230        public String toString()
2231        {
2232            return key;
2233        }
2234        public String getKey()
2235        {
2236            return key;
2237        }
2238        public TrainLengthUnits getValue()
2239        {
2240            return value;
2241        }
2242    }
2243
2244    private static final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(ActivateTrainFrame.class);
2245
2246}