001package jmri.jmrit.operations.trains;
002
003import java.awt.*;
004import java.util.ArrayList;
005import java.util.List;
006
007import javax.swing.*;
008
009import jmri.InstanceManager;
010import jmri.jmrit.operations.*;
011import jmri.jmrit.operations.locations.Location;
012import jmri.jmrit.operations.locations.LocationManager;
013import jmri.jmrit.operations.rollingstock.RollingStock;
014import jmri.jmrit.operations.rollingstock.cars.*;
015import jmri.jmrit.operations.rollingstock.engines.*;
016import jmri.jmrit.operations.routes.*;
017import jmri.jmrit.operations.setup.Control;
018import jmri.jmrit.operations.setup.Setup;
019import jmri.jmrit.operations.trains.tools.*;
020import jmri.util.swing.JmriJOptionPane;
021
022/**
023 * Frame for user edit of a train
024 *
025 * @author Dan Boudreau Copyright (C) 2008, 2011, 2012, 2013, 2014
026 */
027public class TrainEditFrame extends OperationsFrame implements java.beans.PropertyChangeListener {
028
029    TrainManager trainManager = InstanceManager.getDefault(TrainManager.class);
030    RouteManager routeManager = InstanceManager.getDefault(RouteManager.class);
031
032    public Train _train = null;
033    List<JCheckBox> typeCarCheckBoxes = new ArrayList<>();
034    List<JCheckBox> typeEngineCheckBoxes = new ArrayList<>();
035    List<JCheckBox> locationCheckBoxes = new ArrayList<>();
036    JPanel typeCarPanelCheckBoxes = new JPanel();
037    JPanel typeEnginePanelCheckBoxes = new JPanel();
038    JPanel roadAndLoadStatusPanel = new JPanel();
039    JPanel locationPanelCheckBoxes = new JPanel();
040    JScrollPane typeCarPane;
041    JScrollPane typeEnginePane;
042    JScrollPane locationsPane;
043
044    // labels
045    JLabel textRouteStatus = new JLabel();
046    JLabel textModel = new JLabel(Bundle.getMessage("Model"));
047    JLabel textRoad2 = new JLabel(Bundle.getMessage("Road"));
048    JLabel textRoad3 = new JLabel(Bundle.getMessage("Road"));
049    JLabel textEngine = new JLabel(Bundle.getMessage("Engines"));
050
051    // major buttons
052    JButton editButton = new JButton(Bundle.getMessage("ButtonEdit")); // edit route
053    JButton clearButton = new JButton(Bundle.getMessage("ClearAll"));
054    JButton setButton = new JButton(Bundle.getMessage("SelectAll"));
055    JButton resetButton = new JButton(Bundle.getMessage("ResetTrain"));
056    JButton saveTrainButton = new JButton(Bundle.getMessage("SaveTrain"));
057    JButton deleteTrainButton = new JButton(Bundle.getMessage("DeleteTrain"));
058    JButton addTrainButton = new JButton(Bundle.getMessage("AddTrain"));
059
060    // alternate buttons
061    JButton loadOptionButton = new JButton(Bundle.getMessage("AcceptAll"));
062    JButton roadOptionButton = new JButton(Bundle.getMessage("AcceptAll"));
063
064    // radio buttons
065    JRadioButton noneRadioButton = new JRadioButton(Bundle.getMessage("None"));
066    JRadioButton cabooseRadioButton = new JRadioButton(Bundle.getMessage("Caboose"));
067    JRadioButton fredRadioButton = new JRadioButton(Bundle.getMessage("FRED"));
068    ButtonGroup group = new ButtonGroup();
069
070    // text field
071    JTextField trainNameTextField = new JTextField(Control.max_len_string_train_name);
072    JTextField trainDescriptionTextField = new JTextField(30);
073
074    // text area
075    JTextArea commentTextArea = new JTextArea(2, 70);
076    JScrollPane commentScroller = new JScrollPane(commentTextArea);
077    JColorChooser commentColorChooser = new JColorChooser(Color.black);
078
079    // for padding out panel
080    JLabel space1 = new JLabel(" "); // before hour
081    JLabel space2 = new JLabel(" "); // between hour and minute
082    JLabel space3 = new JLabel(" "); // after minute
083    JLabel space4 = new JLabel(" "); // between route and edit
084    JLabel space5 = new JLabel(" "); // after edit
085
086    // combo boxes
087    JComboBox<String> hourBox = new JComboBox<>();
088    JComboBox<String> minuteBox = new JComboBox<>();
089    JComboBox<Route> routeBox = routeManager.getComboBox();
090    JComboBox<String> roadCabooseBox = new JComboBox<>();
091    JComboBox<String> roadEngineBox = new JComboBox<>();
092    JComboBox<String> modelEngineBox = InstanceManager.getDefault(EngineModels.class).getComboBox();
093    JComboBox<String> numEnginesBox = new JComboBox<>();
094
095    JMenu toolMenu = new JMenu(Bundle.getMessage("MenuTools"));
096
097    public static final String DISPOSE = "dispose"; // NOI18N
098
099    public TrainEditFrame(Train train) {
100        super(Bundle.getMessage("TitleTrainEdit"));
101        // Set up the jtable in a Scroll Pane..
102        locationsPane = new JScrollPane(locationPanelCheckBoxes);
103        locationsPane.setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED);
104        locationsPane.setBorder(BorderFactory.createTitledBorder(Bundle.getMessage("Stops")));
105
106        typeCarPane = new JScrollPane(typeCarPanelCheckBoxes);
107        typeCarPane.setBorder(BorderFactory.createTitledBorder(Bundle.getMessage("TypesCar")));
108        typeCarPane.setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED);
109
110        typeEnginePane = new JScrollPane(typeEnginePanelCheckBoxes);
111        typeEnginePane.setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED);
112        typeEnginePane.setBorder(BorderFactory.createTitledBorder(Bundle.getMessage("TypesEngine")));
113
114        _train = train;
115
116        getContentPane().setLayout(new BoxLayout(getContentPane(), BoxLayout.Y_AXIS));
117
118        // Set up the panels
119        JPanel p = new JPanel();
120        p.setLayout(new BoxLayout(p, BoxLayout.Y_AXIS));
121        JScrollPane pPane = new JScrollPane(p);
122        pPane.setMinimumSize(new Dimension(300, 5 * trainNameTextField.getPreferredSize().height));
123        pPane.setBorder(BorderFactory.createTitledBorder(""));
124
125        // Layout the panel by rows
126        // row 1
127        JPanel p1 = new JPanel();
128        p1.setLayout(new BoxLayout(p1, BoxLayout.X_AXIS));
129        // row 1a
130        JPanel pName = new JPanel();
131        pName.setLayout(new GridBagLayout());
132        pName.setBorder(BorderFactory.createTitledBorder(Bundle.getMessage("Name")));
133        addItem(pName, trainNameTextField, 0, 0);
134        // row 1b
135        JPanel pDesc = new JPanel();
136        pDesc.setLayout(new GridBagLayout());
137        pDesc.setBorder(BorderFactory.createTitledBorder(Bundle.getMessage("Description")));
138        trainDescriptionTextField.setToolTipText(Bundle.getMessage("TipTrainDescription"));
139        addItem(pDesc, trainDescriptionTextField, 0, 0);
140
141        p1.add(pName);
142        p1.add(pDesc);
143
144        // row 2
145        JPanel p2 = new JPanel();
146        p2.setLayout(new BoxLayout(p2, BoxLayout.X_AXIS));
147        // row 2a
148        JPanel pdt = new JPanel();
149        pdt.setLayout(new GridBagLayout());
150        pdt.setBorder(BorderFactory.createTitledBorder(Bundle.getMessage("DepartTime")));
151
152        // build hour and minute menus
153        hourBox.setPrototypeDisplayValue("0000"); // needed for font size 9
154        minuteBox.setPrototypeDisplayValue("0000");
155        for (int i = 0; i < 24; i++) {
156            if (i < 10) {
157                hourBox.addItem("0" + Integer.toString(i));
158            } else {
159                hourBox.addItem(Integer.toString(i));
160            }
161        }
162        for (int i = 0; i < 60; i += 1) {
163            if (i < 10) {
164                minuteBox.addItem("0" + Integer.toString(i));
165            } else {
166                minuteBox.addItem(Integer.toString(i));
167            }
168        }
169
170        addItem(pdt, space1, 0, 5);
171        addItem(pdt, hourBox, 1, 5);
172        addItem(pdt, space2, 2, 5);
173        addItem(pdt, minuteBox, 3, 5);
174        addItem(pdt, space3, 4, 5);
175        // row 2b
176        // BUG! routeBox needs its own panel when resizing frame!
177        JPanel pr = new JPanel();
178        pr.setLayout(new GridBagLayout());
179        pr.setBorder(BorderFactory.createTitledBorder(Bundle.getMessage("Route")));
180        addItem(pr, routeBox, 0, 5);
181        addItem(pr, space4, 1, 5);
182        addItem(pr, editButton, 2, 5);
183        addItem(pr, space5, 3, 5);
184        addItem(pr, textRouteStatus, 4, 5);
185
186        p2.add(pdt);
187        p2.add(pr);
188
189        p.add(p1);
190        p.add(p2);
191
192        // row 5
193        locationPanelCheckBoxes.setLayout(new GridBagLayout());
194
195        // row 6
196        typeCarPanelCheckBoxes.setLayout(new GridBagLayout());
197
198        // row 8
199        typeEnginePanelCheckBoxes.setLayout(new GridBagLayout());
200
201        // status panel for roads and loads
202        roadAndLoadStatusPanel.setLayout(new BoxLayout(roadAndLoadStatusPanel, BoxLayout.X_AXIS));
203        JPanel pRoadOption = new JPanel();
204        pRoadOption.setBorder(BorderFactory.createTitledBorder(Bundle.getMessage("RoadOption")));
205        pRoadOption.add(roadOptionButton);
206        roadOptionButton.addActionListener(new TrainRoadOptionsAction(this));
207
208        JPanel pLoadOption = new JPanel();
209        pLoadOption.setBorder(BorderFactory.createTitledBorder(Bundle.getMessage("LoadOption")));
210        pLoadOption.add(loadOptionButton);
211        loadOptionButton.addActionListener(new TrainLoadOptionsAction(this));
212
213        roadAndLoadStatusPanel.add(pRoadOption);
214        roadAndLoadStatusPanel.add(pLoadOption);
215        roadAndLoadStatusPanel.setVisible(false); // don't show unless there's a restriction
216
217        // row 10
218        JPanel trainReq = new JPanel();
219        trainReq.setLayout(new GridBagLayout());
220        trainReq.setBorder(BorderFactory.createTitledBorder(Bundle.getMessage("TrainRequires")));
221
222        for (int i = 0; i < Setup.getMaxNumberEngines() + 1; i++) {
223            numEnginesBox.addItem(Integer.toString(i));
224        }
225        numEnginesBox.addItem(Train.AUTO);
226        numEnginesBox.setMinimumSize(new Dimension(100, 20));
227        numEnginesBox.setToolTipText(Bundle.getMessage("TipNumberOfLocos"));
228        addItem(trainReq, textEngine, 1, 1);
229        addItem(trainReq, numEnginesBox, 2, 1);
230        addItem(trainReq, textModel, 3, 1);
231        modelEngineBox.insertItemAt(NONE, 0);
232        modelEngineBox.setSelectedIndex(0);
233        modelEngineBox.setMinimumSize(new Dimension(120, 20));
234        modelEngineBox.setToolTipText(Bundle.getMessage("ModelEngineTip"));
235        addItem(trainReq, modelEngineBox, 4, 1);
236        addItem(trainReq, textRoad2, 5, 1);
237        roadEngineBox.insertItemAt(NONE, 0);
238        roadEngineBox.setSelectedIndex(0);
239        roadEngineBox.setMinimumSize(new Dimension(120, 20));
240        roadEngineBox.setToolTipText(Bundle.getMessage("RoadEngineTip"));
241        addItem(trainReq, roadEngineBox, 6, 1);
242
243        JPanel trainLastCar = new JPanel();
244        trainLastCar.setLayout(new GridBagLayout());
245        trainLastCar.setBorder(BorderFactory.createTitledBorder(Bundle.getMessage("TrainLastCar")));
246
247        addItem(trainLastCar, noneRadioButton, 2, 2);
248        noneRadioButton.setToolTipText(Bundle.getMessage("TipNoCabooseOrFRED"));
249        addItem(trainLastCar, fredRadioButton, 3, 2);
250        fredRadioButton.setToolTipText(Bundle.getMessage("TipFRED"));
251        addItem(trainLastCar, cabooseRadioButton, 4, 2);
252        cabooseRadioButton.setToolTipText(Bundle.getMessage("TipCaboose"));
253        addItem(trainLastCar, textRoad3, 5, 2);
254        roadCabooseBox.setMinimumSize(new Dimension(120, 20));
255        roadCabooseBox.setToolTipText(Bundle.getMessage("RoadCabooseTip"));
256        addItem(trainLastCar, roadCabooseBox, 6, 2);
257        group.add(noneRadioButton);
258        group.add(cabooseRadioButton);
259        group.add(fredRadioButton);
260        noneRadioButton.setSelected(true);
261
262        // row 13 comment
263        JPanel pC = new JPanel();
264        pC.setBorder(BorderFactory.createTitledBorder(Bundle.getMessage("Comment")));
265        pC.setLayout(new GridBagLayout());
266        addItem(pC, commentScroller, 1, 0);
267        if (_train != null) {
268            addItem(pC, OperationsPanel.getColorChooserPanel(_train.getCommentWithColor(), commentColorChooser), 2, 0);
269        } else {
270            addItem(pC, OperationsPanel.getColorChooserPanel("", commentColorChooser), 2, 0);
271        }
272
273        // adjust text area width based on window size less color chooser
274        Dimension d = new Dimension(getPreferredSize().width - 100, getPreferredSize().height);
275        adjustTextAreaColumnWidth(commentScroller, commentTextArea, d);
276
277        // row 15 buttons
278        JPanel pB = new JPanel();
279        pB.setLayout(new GridBagLayout());
280        addItem(pB, deleteTrainButton, 0, 0);
281        addItem(pB, resetButton, 1, 0);
282        addItem(pB, addTrainButton, 2, 0);
283        addItem(pB, saveTrainButton, 3, 0);
284
285        getContentPane().add(pPane);
286        getContentPane().add(locationsPane);
287        getContentPane().add(typeCarPane);
288        getContentPane().add(typeEnginePane);
289        getContentPane().add(roadAndLoadStatusPanel);
290        getContentPane().add(trainReq);
291        getContentPane().add(trainLastCar);
292        getContentPane().add(pC);
293        getContentPane().add(pB);
294
295        // setup buttons
296        addButtonAction(editButton);
297        addButtonAction(setButton);
298        addButtonAction(clearButton);
299        addButtonAction(resetButton);
300        addButtonAction(deleteTrainButton);
301        addButtonAction(addTrainButton);
302        addButtonAction(saveTrainButton);
303
304        addRadioButtonAction(noneRadioButton);
305        addRadioButtonAction(cabooseRadioButton);
306        addRadioButtonAction(fredRadioButton);
307
308        // tool tips
309        resetButton.setToolTipText(Bundle.getMessage("TipTrainReset"));
310
311        // build menu
312        JMenuBar menuBar = new JMenuBar();
313        menuBar.add(toolMenu);
314        loadToolMenu(toolMenu);
315        setJMenuBar(menuBar);
316        addHelpMenu("package.jmri.jmrit.operations.Operations_TrainEdit", true); // NOI18N
317
318        if (_train != null) {
319            trainNameTextField.setText(_train.getName());
320            trainDescriptionTextField.setText(_train.getRawDescription());
321            routeBox.setSelectedItem(_train.getRoute());
322            modelEngineBox.setSelectedItem(_train.getEngineModel());
323            commentTextArea.setText(TrainCommon.getTextColorString(_train.getCommentWithColor()));
324            cabooseRadioButton.setSelected(_train.isCabooseNeeded());
325            fredRadioButton.setSelected(_train.isFredNeeded());
326            updateDepartureTime();
327            enableButtons(true);
328            // listen for train changes
329            _train.addPropertyChangeListener(this);
330
331            Route route = _train.getRoute();
332            if (route != null) {
333                if (_train.getTrainDepartsRouteLocation() != null &&
334                        _train.getTrainDepartsRouteLocation().getLocation() != null &&
335                        !_train.getTrainDepartsRouteLocation().getLocation().isStaging())
336                    numEnginesBox.addItem(Train.AUTO_HPT);
337            }
338            numEnginesBox.setSelectedItem(_train.getNumberEngines());
339        } else {
340            setTitle(Bundle.getMessage("TitleTrainAdd"));
341            enableButtons(false);
342        }
343
344        modelEngineBox.setEnabled(!numEnginesBox.getSelectedItem().equals("0"));
345        roadEngineBox.setEnabled(!numEnginesBox.getSelectedItem().equals("0"));
346
347        // load route location checkboxes
348        updateLocationCheckboxes();
349        updateCarTypeCheckboxes();
350        updateEngineTypeCheckboxes();
351        updateRoadAndLoadStatus();
352        updateCabooseRoadComboBox();
353        updateEngineRoadComboBox();
354
355        // setup combobox
356        addComboBoxAction(numEnginesBox);
357        addComboBoxAction(routeBox);
358        addComboBoxAction(modelEngineBox);
359
360        // get notified if combo box gets modified
361        routeManager.addPropertyChangeListener(this);
362        // get notified if car types or roads gets modified
363        InstanceManager.getDefault(CarTypes.class).addPropertyChangeListener(this);
364        InstanceManager.getDefault(CarRoads.class).addPropertyChangeListener(this);
365        InstanceManager.getDefault(EngineTypes.class).addPropertyChangeListener(this);
366        InstanceManager.getDefault(EngineModels.class).addPropertyChangeListener(this);
367        InstanceManager.getDefault(LocationManager.class).addPropertyChangeListener(this);
368
369        initMinimumSize(new Dimension(Control.panelWidth600, Control.panelHeight600));
370    }
371
372    private void loadToolMenu(JMenu toolMenu) {
373        toolMenu.removeAll();
374        // first 5 menu items will also close when the edit train window closes
375        toolMenu.add(new TrainEditBuildOptionsAction(this));
376        toolMenu.add(new TrainLoadOptionsAction(this));
377        toolMenu.add(new TrainRoadOptionsAction(this));
378        toolMenu.add(new TrainManifestOptionAction(this));
379        toolMenu.add(new TrainCopyAction(_train));
380        toolMenu.addSeparator();
381        toolMenu.add(new TrainScriptAction(this));
382        toolMenu.add(new TrainConductorAction(_train));
383        toolMenu.addSeparator();
384        toolMenu.add(new TrainByCarTypeAction(_train));
385        toolMenu.addSeparator();
386        toolMenu.add(new PrintTrainAction(false, _train));
387        toolMenu.add(new PrintTrainAction(true, _train));
388        toolMenu.add(new PrintTrainManifestAction(false, _train));
389        toolMenu.add(new PrintTrainManifestAction(true, _train));
390        toolMenu.add(new PrintShowCarsInTrainRouteAction(false, _train));
391        toolMenu.add(new PrintShowCarsInTrainRouteAction(true, _train));
392        toolMenu.add(new PrintTrainBuildReportAction(false, _train));
393        toolMenu.add(new PrintTrainBuildReportAction(true, _train));
394        toolMenu.add(new PrintSavedTrainManifestAction(false, _train));
395        toolMenu.add(new PrintSavedTrainManifestAction(true, _train));
396        toolMenu.add(new PrintSavedBuildReportAction(false, _train));
397        toolMenu.add(new PrintSavedBuildReportAction(true, _train));
398    }
399
400    // Save, Delete, Add, Edit, Reset, Set, Clear
401    @Override
402    public void buttonActionPerformed(java.awt.event.ActionEvent ae) {
403        Train train = trainManager.getTrainByName(trainNameTextField.getText().trim());
404        if (ae.getSource() == saveTrainButton) {
405            log.debug("train save button activated");
406            if (_train == null && train == null) {
407                saveNewTrain(); // this can't happen, Save button is disabled
408            } else {
409                if (train != null && train != _train) {
410                    reportTrainExists(Bundle.getMessage("save"));
411                    return;
412                }
413                // check to see if user supplied a route
414                if (!checkRoute() || !saveTrain()) {
415                    return;
416                }
417            }
418            if (Setup.isCloseWindowOnSaveEnabled()) {
419                dispose();
420            }
421        }
422        if (ae.getSource() == deleteTrainButton) {
423            log.debug("train delete button activated");
424            if (train == null) {
425                return;
426            }
427            if (!_train.reset()) {
428                JmriJOptionPane.showMessageDialog(this,
429                        Bundle.getMessage("TrainIsInRoute",
430                                train.getTrainTerminatesName()),
431                        Bundle.getMessage("CanNotDeleteTrain"), JmriJOptionPane.ERROR_MESSAGE);
432                return;
433            }
434            if (JmriJOptionPane.showConfirmDialog(this,
435                    Bundle.getMessage("deleteMsg", train.getName()),
436                    Bundle.getMessage("deleteTrain"), JmriJOptionPane.YES_NO_OPTION) != JmriJOptionPane.YES_OPTION) {
437                return;
438            }
439            routeBox.setSelectedItem(null);
440            trainManager.deregister(train);
441            for (Frame frame : children) {
442                frame.dispose();
443            }
444            _train = null;
445            enableButtons(false);
446            // save train file
447            OperationsXml.save();
448        }
449        if (ae.getSource() == addTrainButton) {
450            if (train != null) {
451                reportTrainExists(Bundle.getMessage("add"));
452                return;
453            }
454            saveNewTrain();
455        }
456        if (ae.getSource() == editButton) {
457            editAddRoute();
458        }
459        if (ae.getSource() == setButton) {
460            selectCheckboxes(true);
461        }
462        if (ae.getSource() == clearButton) {
463            selectCheckboxes(false);
464        }
465        if (ae.getSource() == resetButton) {
466            if (_train != null) {
467                if (!_train.reset()) {
468                    JmriJOptionPane.showMessageDialog(this,
469                            Bundle.getMessage("TrainIsInRoute",
470                                    _train.getTrainTerminatesName()),
471                            Bundle.getMessage("CanNotResetTrain"), JmriJOptionPane.ERROR_MESSAGE);
472                }
473            }
474        }
475    }
476
477    @Override
478    public void radioButtonActionPerformed(java.awt.event.ActionEvent ae) {
479        log.debug("radio button activated");
480        if (_train != null) {
481            if (ae.getSource() == noneRadioButton ||
482                    ae.getSource() == cabooseRadioButton ||
483                    ae.getSource() == fredRadioButton) {
484                updateCabooseRoadComboBox();
485            }
486        }
487    }
488
489    private void saveNewTrain() {
490        if (!checkName(Bundle.getMessage("add"))) {
491            return;
492        }
493        Train train = trainManager.newTrain(trainNameTextField.getText());
494        _train = train;
495        _train.addPropertyChangeListener(this);
496
497        // update check boxes
498        updateCarTypeCheckboxes();
499        updateEngineTypeCheckboxes();
500        // enable check boxes and buttons
501        enableButtons(true);
502        saveTrain();
503        loadToolMenu(toolMenu);
504    }
505
506    private boolean saveTrain() {
507        if (!checkName(Bundle.getMessage("save"))) {
508            return false;
509        }
510        if (!checkModel() || !checkEngineRoad() || !checkCabooseRoad()) {
511            return false;
512        }
513        if (!_train.getName().equals(trainNameTextField.getText().trim()) ||
514                !_train.getRawDescription().equals(trainDescriptionTextField.getText()) ||
515                !_train.getCommentWithColor().equals(
516                        TrainCommon.formatColorString(commentTextArea.getText(), commentColorChooser.getColor()))) {
517            _train.setModified(true);
518        }
519        _train.setDepartureTime(hourBox.getSelectedItem().toString(), minuteBox.getSelectedItem().toString());
520        _train.setNumberEngines((String) numEnginesBox.getSelectedItem());
521        if (_train.getNumberEngines().equals("0")) {
522            modelEngineBox.setSelectedIndex(0);
523            roadEngineBox.setSelectedIndex(0);
524        }
525        _train.setEngineRoad((String) roadEngineBox.getSelectedItem());
526        _train.setEngineModel((String) modelEngineBox.getSelectedItem());
527        if (cabooseRadioButton.isSelected()) {
528            _train.setRequirements(Train.CABOOSE);
529        }
530        if (fredRadioButton.isSelected()) {
531            _train.setRequirements(Train.FRED);
532        }
533        if (noneRadioButton.isSelected()) {
534            _train.setRequirements(Train.NO_CABOOSE_OR_FRED);
535        }
536        _train.setCabooseRoad((String) roadCabooseBox.getSelectedItem());
537        _train.setName(trainNameTextField.getText().trim());
538        _train.setDescription(trainDescriptionTextField.getText());
539        _train.setComment(TrainCommon.formatColorString(commentTextArea.getText(), commentColorChooser.getColor()));
540        // save train file
541        OperationsXml.save();
542        return true;
543    }
544
545    /**
546     *
547     * @return true if name isn't too long and is at least one character
548     */
549    private boolean checkName(String s) {
550        String trainName = trainNameTextField.getText().trim();
551        if (trainName.isEmpty()) {
552            log.debug("Must enter a train name");
553            JmriJOptionPane.showMessageDialog(this, Bundle.getMessage("MustEnterName"),
554                    Bundle.getMessage("CanNot", s), JmriJOptionPane.ERROR_MESSAGE);
555            return false;
556        }
557        if (trainName.length() > Control.max_len_string_train_name) {
558            JmriJOptionPane.showMessageDialog(this,
559                    Bundle.getMessage("TrainNameLess",
560                            Control.max_len_string_train_name + 1),
561                    Bundle.getMessage("CanNot", s), JmriJOptionPane.ERROR_MESSAGE);
562            return false;
563        }
564        if (!OperationsXml.checkFileName(trainName)) { // NOI18N
565            log.error("Train name must not contain reserved characters");
566            JmriJOptionPane.showMessageDialog(this,
567                    Bundle.getMessage("NameResChar") + NEW_LINE + Bundle.getMessage("ReservedChar"),
568                    Bundle.getMessage("CanNot", s), JmriJOptionPane.ERROR_MESSAGE);
569            return false;
570        }
571
572        return true;
573    }
574
575    private boolean checkModel() {
576        String model = (String) modelEngineBox.getSelectedItem();
577        if (numEnginesBox.getSelectedItem().equals("0") || model.equals(NONE)) {
578            return true;
579        }
580        String type = InstanceManager.getDefault(EngineModels.class).getModelType(model);
581        if (!_train.isTypeNameAccepted(type)) {
582            JmriJOptionPane.showMessageDialog(this,
583                    Bundle.getMessage("TrainModelService", model, type),
584                    Bundle.getMessage("CanNot", Bundle.getMessage("save")),
585                    JmriJOptionPane.ERROR_MESSAGE);
586            return false;
587        }
588        if (roadEngineBox.getItemCount() == 1) {
589            log.debug("No locos available that match the model selected!");
590            JmriJOptionPane.showMessageDialog(this,
591                    Bundle.getMessage("NoLocosModel", model),
592                    Bundle.getMessage("TrainWillNotBuild", _train.getName()),
593                    JmriJOptionPane.WARNING_MESSAGE);
594        }
595        return true;
596    }
597
598    private boolean checkEngineRoad() {
599        String road = (String) roadEngineBox.getSelectedItem();
600        if (numEnginesBox.getSelectedItem().equals("0") || road.equals(NONE)) {
601            return true;
602        }
603        if (!road.equals(NONE) && !_train.isLocoRoadNameAccepted(road)) {
604            JmriJOptionPane.showMessageDialog(this,
605                    Bundle.getMessage("TrainNotThisRoad", _train.getName(), road),
606                    Bundle.getMessage("TrainWillNotBuild", _train.getName()),
607                    JmriJOptionPane.WARNING_MESSAGE);
608            return false;
609        }
610        for (RollingStock rs : InstanceManager.getDefault(EngineManager.class).getList()) {
611            if (!_train.isTypeNameAccepted(rs.getTypeName())) {
612                continue;
613            }
614            if (rs.getRoadName().equals(road)) {
615                return true;
616            }
617        }
618        JmriJOptionPane.showMessageDialog(this,
619                Bundle.getMessage("NoLocoRoad", road),
620                Bundle.getMessage("TrainWillNotBuild", _train.getName()),
621                JmriJOptionPane.WARNING_MESSAGE);
622        return false; // couldn't find a loco with the selected road
623    }
624
625    private boolean checkCabooseRoad() {
626        String road = (String) roadCabooseBox.getSelectedItem();
627        if (!road.equals(NONE) && cabooseRadioButton.isSelected() && !_train.isCabooseRoadNameAccepted(road)) {
628            JmriJOptionPane.showMessageDialog(this,
629                    Bundle.getMessage("TrainNotCabooseRoad", _train.getName(), road),
630                    Bundle.getMessage("TrainWillNotBuild", _train.getName()),
631                    JmriJOptionPane.WARNING_MESSAGE);
632            return false;
633        }
634        return true;
635    }
636
637    private boolean checkRoute() {
638        if (_train.getRoute() == null) {
639            JmriJOptionPane.showMessageDialog(this, Bundle.getMessage("TrainNeedsRoute"), Bundle.getMessage("TrainNoRoute"),
640                    JmriJOptionPane.WARNING_MESSAGE);
641            return false;
642        }
643        return true;
644
645    }
646
647    private void reportTrainExists(String s) {
648        log.debug("Can not {}, train already exists", s);
649        JmriJOptionPane.showMessageDialog(this, Bundle.getMessage("TrainNameExists"),
650                Bundle.getMessage("CanNot", s), JmriJOptionPane.ERROR_MESSAGE);
651    }
652
653    private void enableButtons(boolean enabled) {
654        toolMenu.setEnabled(enabled);
655        editButton.setEnabled(enabled);
656        routeBox.setEnabled(enabled && _train != null && !_train.isBuilt());
657        clearButton.setEnabled(enabled);
658        resetButton.setEnabled(enabled);
659        setButton.setEnabled(enabled);
660        saveTrainButton.setEnabled(enabled);
661        deleteTrainButton.setEnabled(enabled);
662        numEnginesBox.setEnabled(enabled);
663        enableCheckboxes(enabled);
664        noneRadioButton.setEnabled(enabled);
665        fredRadioButton.setEnabled(enabled);
666        cabooseRadioButton.setEnabled(enabled);
667        roadOptionButton.setEnabled(enabled);
668        loadOptionButton.setEnabled(enabled);
669        // the inverse!
670        addTrainButton.setEnabled(!enabled);
671    }
672
673    private void selectCheckboxes(boolean enable) {
674        for (int i = 0; i < typeCarCheckBoxes.size(); i++) {
675            JCheckBox checkBox = typeCarCheckBoxes.get(i);
676            checkBox.setSelected(enable);
677            if (_train != null) {
678                _train.removePropertyChangeListener(this);
679                if (enable) {
680                    _train.addTypeName(checkBox.getText());
681                } else {
682                    _train.deleteTypeName(checkBox.getText());
683                }
684                _train.addPropertyChangeListener(this);
685            }
686        }
687    }
688
689    @Override
690    public void comboBoxActionPerformed(java.awt.event.ActionEvent ae) {
691        if (_train == null) {
692            return;
693        }
694        if (ae.getSource() == numEnginesBox) {
695            modelEngineBox.setEnabled(!numEnginesBox.getSelectedItem().equals("0"));
696            roadEngineBox.setEnabled(!numEnginesBox.getSelectedItem().equals("0"));
697        }
698        if (ae.getSource() == modelEngineBox) {
699            updateEngineRoadComboBox();
700        }
701        if (ae.getSource() == routeBox) {
702            if (routeBox.isEnabled()) {
703                Route route = _train.getRoute();
704                if (route != null) {
705                    route.removePropertyChangeListener(this);
706                }
707                Object selected = routeBox.getSelectedItem();
708                if (selected != null) {
709                    route = (Route) selected;
710                    _train.setRoute(route);
711                    route.addPropertyChangeListener(this);
712                } else {
713                    _train.setRoute(null);
714                }
715                updateLocationCheckboxes();
716                updateDepartureTime();
717                pack();
718                repaint();
719            }
720        }
721    }
722
723    private void enableCheckboxes(boolean enable) {
724        for (int i = 0; i < typeCarCheckBoxes.size(); i++) {
725            typeCarCheckBoxes.get(i).setEnabled(enable);
726        }
727        for (int i = 0; i < typeEngineCheckBoxes.size(); i++) {
728            typeEngineCheckBoxes.get(i).setEnabled(enable);
729        }
730    }
731
732    private void addLocationCheckBoxAction(JCheckBox b) {
733        b.addActionListener(new java.awt.event.ActionListener() {
734            @Override
735            public void actionPerformed(java.awt.event.ActionEvent e) {
736                locationCheckBoxActionPerformed(e);
737            }
738        });
739    }
740
741    public void locationCheckBoxActionPerformed(java.awt.event.ActionEvent ae) {
742        JCheckBox b = (JCheckBox) ae.getSource();
743        log.debug("checkbox change {}", b.getText());
744        if (_train == null) {
745            return;
746        }
747        String id = b.getName();
748        if (b.isSelected()) {
749            _train.deleteTrainSkipsLocation(id);
750        } else {
751            // check to see if skipped location is staging
752            if (_train.getRoute().getLocationById(id).getLocation().isStaging()) {
753                int result = JmriJOptionPane.showConfirmDialog(this,
754                        Bundle.getMessage("TrainRouteStaging",
755                                _train.getName(), _train.getRoute().getLocationById(id).getName()),
756                        Bundle.getMessage("TrainRouteNotStaging"), JmriJOptionPane.OK_CANCEL_OPTION);
757                if (result != JmriJOptionPane.OK_OPTION ) {
758                    b.setSelected(true);
759                    return; // don't skip staging
760                }
761            }
762            _train.addTrainSkipsLocation(id);
763        }
764    }
765
766    private void updateRouteComboBox() {
767        routeBox.setEnabled(false);
768        routeManager.updateComboBox(routeBox);
769        if (_train != null) {
770            routeBox.setSelectedItem(_train.getRoute());
771        }
772        routeBox.setEnabled(true);
773    }
774
775    private void updateCarTypeCheckboxes() {
776        typeCarCheckBoxes.clear();
777        typeCarPanelCheckBoxes.removeAll();
778        loadCarTypes();
779        enableCheckboxes(_train != null);
780        typeCarPanelCheckBoxes.revalidate();
781        repaint();
782    }
783
784    private void loadCarTypes() {
785        int numberOfCheckboxes = getNumberOfCheckboxesPerLine(); // number per line
786        int x = 0;
787        int y = 1; // vertical position in panel
788        for (String type : InstanceManager.getDefault(CarTypes.class).getNames()) {
789            JCheckBox checkBox = new javax.swing.JCheckBox();
790            typeCarCheckBoxes.add(checkBox);
791            checkBox.setText(type);
792            addTypeCheckBoxAction(checkBox);
793            addItemLeft(typeCarPanelCheckBoxes, checkBox, x++, y);
794            if (_train != null && _train.isTypeNameAccepted(type)) {
795                checkBox.setSelected(true);
796            }
797            if (x > numberOfCheckboxes) {
798                y++;
799                x = 0;
800            }
801        }
802
803        JPanel p = new JPanel();
804        p.add(clearButton);
805        p.add(setButton);
806        GridBagConstraints gc = new GridBagConstraints();
807        gc.gridwidth = getNumberOfCheckboxesPerLine() + 1;
808        gc.gridy = ++y;
809        typeCarPanelCheckBoxes.add(p, gc);
810
811    }
812
813    private void updateEngineTypeCheckboxes() {
814        typeEngineCheckBoxes.clear();
815        typeEnginePanelCheckBoxes.removeAll();
816        loadEngineTypes();
817        enableCheckboxes(_train != null);
818        typeEnginePanelCheckBoxes.revalidate();
819        repaint();
820    }
821
822    private void loadEngineTypes() {
823        int numberOfCheckboxes = getNumberOfCheckboxesPerLine(); // number per line
824        int x = 0;
825        int y = 1;
826        for (String type : InstanceManager.getDefault(EngineTypes.class).getNames()) {
827            JCheckBox checkBox = new javax.swing.JCheckBox();
828            typeEngineCheckBoxes.add(checkBox);
829            checkBox.setText(type);
830            addTypeCheckBoxAction(checkBox);
831            addItemLeft(typeEnginePanelCheckBoxes, checkBox, x++, y);
832            if (_train != null && _train.isTypeNameAccepted(type)) {
833                checkBox.setSelected(true);
834            }
835            if (x > numberOfCheckboxes) {
836                y++;
837                x = 0;
838            }
839        }
840    }
841
842    private void updateRoadComboBoxes() {
843        updateCabooseRoadComboBox();
844        updateEngineRoadComboBox();
845    }
846
847    // update caboose road box based on radio selection
848    private void updateCabooseRoadComboBox() {
849        roadCabooseBox.removeAllItems();
850        roadCabooseBox.addItem(NONE);
851        if (noneRadioButton.isSelected()) {
852            roadCabooseBox.setEnabled(false);
853            return;
854        }
855        roadCabooseBox.setEnabled(true);
856        List<String> roads;
857        if (cabooseRadioButton.isSelected()) {
858            roads = InstanceManager.getDefault(CarManager.class).getCabooseRoadNames();
859        } else {
860            roads = InstanceManager.getDefault(CarManager.class).getFredRoadNames();
861        }
862        for (String road : roads) {
863            roadCabooseBox.addItem(road);
864        }
865        if (_train != null) {
866            roadCabooseBox.setSelectedItem(_train.getCabooseRoad());
867        }
868        OperationsPanel.padComboBox(roadCabooseBox);
869    }
870
871    private void updateEngineRoadComboBox() {
872        String engineModel = (String) modelEngineBox.getSelectedItem();
873        if (engineModel == null) {
874            return;
875        }
876        InstanceManager.getDefault(EngineManager.class).updateEngineRoadComboBox(engineModel, roadEngineBox);
877        if (_train != null) {
878            roadEngineBox.setSelectedItem(_train.getEngineRoad());
879        }
880    }
881
882    private void addTypeCheckBoxAction(JCheckBox b) {
883        b.addActionListener(new java.awt.event.ActionListener() {
884            @Override
885            public void actionPerformed(java.awt.event.ActionEvent e) {
886                typeCheckBoxActionPerformed(e);
887            }
888        });
889    }
890
891    public void typeCheckBoxActionPerformed(java.awt.event.ActionEvent ae) {
892        JCheckBox b = (JCheckBox) ae.getSource();
893        log.debug("checkbox change {}", b.getText());
894        if (_train == null) {
895            return;
896        }
897        if (b.isSelected()) {
898            _train.addTypeName(b.getText());
899        } else {
900            _train.deleteTypeName(b.getText());
901        }
902    }
903
904    // the train's route shown as locations with checkboxes
905    private void updateLocationCheckboxes() {
906        updateRouteStatus();
907        locationCheckBoxes.clear();
908        locationPanelCheckBoxes.removeAll();
909        int y = 0; // vertical position in panel
910        Route route = null;
911        if (_train != null) {
912            route = _train.getRoute();
913        }
914        if (route != null) {
915            List<RouteLocation> routeList = route.getLocationsBySequenceList();
916            for (RouteLocation rl : routeList) {
917                JCheckBox checkBox = new javax.swing.JCheckBox();
918                locationCheckBoxes.add(checkBox);
919                checkBox.setText(rl.toString());
920                checkBox.setName(rl.getId());
921                addItemLeft(locationPanelCheckBoxes, checkBox, 0, y++);
922                Location loc = InstanceManager.getDefault(LocationManager.class).getLocationByName(rl.getName());
923                // does the location exist?
924                if (loc != null) {
925                    // need to listen for name and direction changes
926                    loc.removePropertyChangeListener(this);
927                    loc.addPropertyChangeListener(this);
928                    boolean services = false;
929                    // does train direction service location?
930                    if ((rl.getTrainDirection() & loc.getTrainDirections()) != 0) {
931                        services = true;
932                    } // train must service last location or single location
933                    else if (_train.isLocalSwitcher() || rl == _train.getTrainTerminatesRouteLocation()) {
934                        services = true;
935                    }
936                    // check can drop and pick up, and moves > 0
937                    if (services && (rl.isDropAllowed() || rl.isPickUpAllowed()) && rl.getMaxCarMoves() > 0) {
938                        checkBox.setSelected(!_train.isLocationSkipped(rl.getId()));
939                    } else {
940                        checkBox.setEnabled(false);
941                    }
942                    addLocationCheckBoxAction(checkBox);
943                } else {
944                    checkBox.setEnabled(false);
945                }
946            }
947        }
948        locationPanelCheckBoxes.revalidate();
949    }
950
951    private void updateRouteStatus() {
952        Route route = null;
953        textRouteStatus.setText(NONE); // clear out previous status
954        if (_train != null) {
955            route = _train.getRoute();
956        }
957        if (route != null) {
958            if (!route.getStatus().equals(Route.OKAY)) {
959                textRouteStatus.setText(route.getStatus());
960                textRouteStatus.setForeground(Color.RED);
961            }
962        }
963    }
964
965    RouteEditFrame ref;
966
967    private void editAddRoute() {
968        log.debug("Edit/add route");
969        if (ref != null) {
970            ref.dispose();
971        }
972        ref = new RouteEditFrame();
973        setChildFrame(ref);
974        Route route = null;
975        Object selected = routeBox.getSelectedItem();
976        if (selected != null) {
977            route = (Route) selected;
978        }
979        // warn user if train is built that they shouldn't edit the train's route
980        if (route != null && route.getStatus().equals(Route.TRAIN_BUILT)) {
981            // list the built trains for this route
982            StringBuffer buf = new StringBuffer(Bundle.getMessage("DoNotModifyRoute"));
983            for (Train train : InstanceManager.getDefault(TrainManager.class).getTrainsByIdList()) {
984                if (train.getRoute() == route && train.isBuilt()) {
985                    buf.append(NEW_LINE +
986                            Bundle.getMessage("TrainIsBuilt",
987                                    train.getName(), route.getName()));
988                }
989            }
990            JmriJOptionPane.showMessageDialog(this, buf.toString(), Bundle.getMessage("BuiltTrain"),
991                    JmriJOptionPane.WARNING_MESSAGE);
992        }
993        ref.initComponents(route, _train);
994    }
995
996    private void updateDepartureTime() {
997        hourBox.setSelectedItem(_train.getDepartureTimeHour());
998        minuteBox.setSelectedItem(_train.getDepartureTimeMinute());
999        // check to see if route has a departure time from the 1st location
1000        RouteLocation rl = _train.getTrainDepartsRouteLocation();
1001        if (rl != null && !rl.getDepartureTime().equals(NONE)) {
1002            hourBox.setEnabled(false);
1003            minuteBox.setEnabled(false);
1004        } else {
1005            hourBox.setEnabled(true);
1006            minuteBox.setEnabled(true);
1007        }
1008    }
1009
1010    private void updateRoadAndLoadStatus() {
1011        if (_train != null) {
1012            // road options
1013            if (_train.getCarRoadOption().equals(Train.INCLUDE_ROADS)) {
1014                roadOptionButton.setText(Bundle.getMessage(
1015                        "AcceptOnly") + " " + _train.getCarRoadNames().length + " " + Bundle.getMessage("RoadsCar"));
1016            } else if (_train.getCarRoadOption().equals(Train.EXCLUDE_ROADS)) {
1017                roadOptionButton.setText(Bundle.getMessage(
1018                        "Exclude") + " " + _train.getCarRoadNames().length + " " + Bundle.getMessage("RoadsCar"));
1019            } else if (_train.getCabooseRoadOption().equals(Train.INCLUDE_ROADS)) {
1020                roadOptionButton.setText(Bundle.getMessage(
1021                        "AcceptOnly") +
1022                        " " +
1023                        _train.getCabooseRoadNames().length +
1024                        " " +
1025                        Bundle.getMessage("RoadsCaboose"));
1026            } else if (_train.getCabooseRoadOption().equals(Train.EXCLUDE_ROADS)) {
1027                roadOptionButton.setText(Bundle.getMessage(
1028                        "Exclude") +
1029                        " " +
1030                        _train.getCabooseRoadNames().length +
1031                        " " +
1032                        Bundle.getMessage("RoadsCaboose"));
1033            } else if (_train.getLocoRoadOption().equals(Train.INCLUDE_ROADS)) {
1034                roadOptionButton.setText(Bundle.getMessage(
1035                        "AcceptOnly") + " " + _train.getLocoRoadNames().length + " " + Bundle.getMessage("RoadsLoco"));
1036            } else if (_train.getLocoRoadOption().equals(Train.EXCLUDE_ROADS)) {
1037                roadOptionButton.setText(Bundle.getMessage(
1038                        "Exclude") + " " + _train.getLocoRoadNames().length + " " + Bundle.getMessage("RoadsLoco"));
1039            } else {
1040                roadOptionButton.setText(Bundle.getMessage("AcceptAll"));
1041            }
1042            // load options
1043            if (_train.getLoadOption().equals(Train.ALL_LOADS)) {
1044                loadOptionButton.setText(Bundle.getMessage("AcceptAll"));
1045            } else if (_train.getLoadOption().equals(Train.INCLUDE_LOADS)) {
1046                loadOptionButton.setText(Bundle.getMessage(
1047                        "AcceptOnly") + " " + _train.getLoadNames().length + " " + Bundle.getMessage("Loads"));
1048            } else {
1049                loadOptionButton.setText(Bundle.getMessage(
1050                        "Exclude") + " " + _train.getLoadNames().length + " " + Bundle.getMessage("Loads"));
1051            }
1052            if (!_train.getCarRoadOption().equals(Train.ALL_ROADS) ||
1053                    !_train.getCabooseRoadOption().equals(Train.ALL_ROADS) ||
1054                    !_train.getLocoRoadOption().equals(Train.ALL_ROADS) ||
1055                    !_train.getLoadOption().equals(Train.ALL_LOADS)) {
1056                roadAndLoadStatusPanel.setVisible(true);
1057            }
1058        }
1059    }
1060
1061    List<Frame> children = new ArrayList<>();
1062
1063    public void setChildFrame(Frame frame) {
1064        if (children.contains(frame)) {
1065            return;
1066        }
1067        children.add(frame);
1068    }
1069
1070    @Override
1071    public void dispose() {
1072        InstanceManager.getDefault(LocationManager.class).removePropertyChangeListener(this);
1073        InstanceManager.getDefault(EngineTypes.class).removePropertyChangeListener(this);
1074        InstanceManager.getDefault(EngineModels.class).removePropertyChangeListener(this);
1075        InstanceManager.getDefault(CarTypes.class).removePropertyChangeListener(this);
1076        InstanceManager.getDefault(CarRoads.class).removePropertyChangeListener(this);
1077        routeManager.removePropertyChangeListener(this);
1078        for (Frame frame : children) {
1079            frame.dispose();
1080        }
1081        if (_train != null) {
1082            _train.removePropertyChangeListener(this);
1083            Route route = _train.getRoute();
1084            if (route != null) {
1085                for (RouteLocation rl : route.getLocationsBySequenceList()) {
1086                    Location loc = rl.getLocation();
1087                    if (loc != null) {
1088                        loc.removePropertyChangeListener(this);
1089                    }
1090                }
1091            }
1092        }
1093        super.dispose();
1094    }
1095
1096    @Override
1097    public void propertyChange(java.beans.PropertyChangeEvent e) {
1098        if (Control.SHOW_PROPERTY) {
1099            log.debug("Property change ({}) old: ({}) new: ({})", e.getPropertyName(), e.getOldValue(),
1100                    e.getNewValue()); // NOI18N
1101        }
1102        if (e.getPropertyName().equals(CarTypes.CARTYPES_CHANGED_PROPERTY) ||
1103                e.getPropertyName().equals(Train.TYPES_CHANGED_PROPERTY)) {
1104            updateCarTypeCheckboxes();
1105        }
1106        if (e.getPropertyName().equals(EngineTypes.ENGINETYPES_CHANGED_PROPERTY)) {
1107            updateEngineTypeCheckboxes();
1108        }
1109        if (e.getPropertyName().equals(RouteManager.LISTLENGTH_CHANGED_PROPERTY)) {
1110            updateRouteComboBox();
1111        }
1112        if (e.getPropertyName().equals(Route.LISTCHANGE_CHANGED_PROPERTY) ||
1113                e.getPropertyName().equals(LocationManager.LISTLENGTH_CHANGED_PROPERTY) ||
1114                e.getPropertyName().equals(Location.NAME_CHANGED_PROPERTY) ||
1115                e.getPropertyName().equals(Location.TRAIN_DIRECTION_CHANGED_PROPERTY)) {
1116            updateLocationCheckboxes();
1117            pack();
1118            repaint();
1119        }
1120        if (e.getPropertyName().equals(CarRoads.CARROADS_CHANGED_PROPERTY)) {
1121            updateRoadComboBoxes();
1122        }
1123        if (e.getPropertyName().equals(EngineModels.ENGINEMODELS_CHANGED_PROPERTY)) {
1124            InstanceManager.getDefault(EngineModels.class).updateComboBox(modelEngineBox);
1125            modelEngineBox.insertItemAt(NONE, 0);
1126            modelEngineBox.setSelectedIndex(0);
1127            if (_train != null) {
1128                modelEngineBox.setSelectedItem(_train.getEngineModel());
1129            }
1130        }
1131        if (e.getPropertyName().equals(Train.DEPARTURETIME_CHANGED_PROPERTY)) {
1132            updateDepartureTime();
1133        }
1134        if (e.getPropertyName().equals(Train.TRAIN_ROUTE_CHANGED_PROPERTY) && _train != null) {
1135            routeBox.setSelectedItem(_train.getRoute());
1136        }
1137        if (e.getPropertyName().equals(Route.ROUTE_STATUS_CHANGED_PROPERTY)) {
1138            enableButtons(_train != null);
1139            updateRouteStatus();
1140        }
1141        if (e.getPropertyName().equals(Train.ROADS_CHANGED_PROPERTY) ||
1142                e.getPropertyName().equals(Train.LOADS_CHANGED_PROPERTY)) {
1143            updateRoadAndLoadStatus();
1144        }
1145    }
1146
1147    private static final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(TrainEditFrame.class);
1148}