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