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