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.isTextUserModified(_train.getCommentWithColor())
347                    ? _train.getCommentWithColor() : _train.getComment());
348            cabooseRadioButton.setSelected(_train.isCabooseNeeded());
349            fredRadioButton.setSelected(_train.isFredNeeded());
350            updateDepartureTime();
351            enableButtons(true);
352            // listen for train changes
353            _train.addPropertyChangeListener(this);
354
355            Route route = _train.getRoute();
356            if (route != null) {
357                if (_train.getTrainDepartsRouteLocation() != null &&
358                        _train.getTrainDepartsRouteLocation().getLocation() != null &&
359                        !_train.getTrainDepartsRouteLocation().getLocation().isStaging())
360                    numEnginesBox.addItem(Train.AUTO_HPT);
361            }
362            numEnginesBox.setSelectedItem(_train.getNumberEngines());
363        } else {
364            setTitle(Bundle.getMessage("TitleTrainAdd"));
365            enableButtons(false);
366        }
367
368        modelEngineBox.setEnabled(!numEnginesBox.getSelectedItem().equals("0"));
369        roadEngineBox.setEnabled(!numEnginesBox.getSelectedItem().equals("0"));
370
371        // load route location checkboxes
372        updateLocationCheckboxes();
373        updateCarTypeCheckboxes();
374        updateEngineTypeCheckboxes();
375        updateRoadAndLoadStatus();
376        updateCabooseRoadComboBox();
377        updateEngineRoadComboBox();
378
379        // setup combobox
380        addComboBoxAction(numEnginesBox);
381        addComboBoxAction(routeBox);
382        addComboBoxAction(modelEngineBox);
383
384        // get notified if combo box gets modified
385        routeManager.addPropertyChangeListener(this);
386        // get notified if car types or roads gets modified
387        InstanceManager.getDefault(CarTypes.class).addPropertyChangeListener(this);
388        InstanceManager.getDefault(CarRoads.class).addPropertyChangeListener(this);
389        InstanceManager.getDefault(EngineTypes.class).addPropertyChangeListener(this);
390        InstanceManager.getDefault(EngineModels.class).addPropertyChangeListener(this);
391        InstanceManager.getDefault(LocationManager.class).addPropertyChangeListener(this);
392
393        initMinimumSize(new Dimension(Control.panelWidth600, Control.panelHeight600));
394    }
395
396    private void loadToolMenu(JMenu toolMenu) {
397        toolMenu.removeAll();
398        // first 4 menu items will also close when the edit train window closes
399        toolMenu.add(new TrainEditBuildOptionsAction(this));
400        toolMenu.add(new TrainLoadOptionsAction(this));
401        toolMenu.add(new TrainRoadOptionsAction(this));
402        toolMenu.add(new TrainManifestOptionAction(this));
403        toolMenu.addSeparator();
404        toolMenu.add(new TrainManualBuildAction(_train));
405        toolMenu.addSeparator();
406        toolMenu.add(new TrainCopyAction(_train));
407        toolMenu.addSeparator();
408        // scripts window closes when the edit train window closes
409        toolMenu.add(new TrainScriptAction(this));
410        toolMenu.addSeparator();
411        toolMenu.add(new TrainConductorAction(_train));
412        toolMenu.addSeparator();
413        toolMenu.add(new TrainByCarTypeAction(_train));
414        toolMenu.addSeparator();
415        toolMenu.add(new PrintTrainAction(false, _train));
416        toolMenu.add(new PrintTrainAction(true, _train));
417        toolMenu.add(new PrintTrainManifestAction(false, _train));
418        toolMenu.add(new PrintTrainManifestAction(true, _train));
419        toolMenu.add(new PrintShowCarsInTrainRouteAction(false, _train));
420        toolMenu.add(new PrintShowCarsInTrainRouteAction(true, _train));
421        toolMenu.add(new PrintTrainBuildReportAction(false, _train));
422        toolMenu.add(new PrintTrainBuildReportAction(true, _train));
423        toolMenu.add(new PrintSavedTrainManifestAction(false, _train));
424        toolMenu.add(new PrintSavedTrainManifestAction(true, _train));
425        toolMenu.add(new PrintSavedBuildReportAction(false, _train));
426        toolMenu.add(new PrintSavedBuildReportAction(true, _train));
427    }
428
429    // Save, Delete, Add, Edit, Reset, Set, Clear
430    @Override
431    public void buttonActionPerformed(java.awt.event.ActionEvent ae) {
432        Train train = trainManager.getTrainByName(trainNameTextField.getText().trim());
433        if (ae.getSource() == saveTrainButton) {
434            log.debug("train save button activated");
435            if (_train == null && train == null) {
436                saveNewTrain(); // this can't happen, Save button is disabled
437            } else {
438                if (train != null && train != _train) {
439                    reportTrainExists(Bundle.getMessage("save"));
440                    return;
441                }
442                // check to see if user supplied a route
443                if (!checkRoute() || !saveTrain()) {
444                    return;
445                }
446            }
447            if (Setup.isCloseWindowOnSaveEnabled()) {
448                dispose();
449            }
450        }
451        if (ae.getSource() == deleteTrainButton) {
452            log.debug("train delete button activated");
453            if (train == null) {
454                return;
455            }
456            if (train.isBuilt()) {
457                JmriJOptionPane.showMessageDialog(this,
458                        Bundle.getMessage("BuiltTrain"),
459                        Bundle.getMessage("CanNotDeleteTrain"), JmriJOptionPane.ERROR_MESSAGE);
460                return;
461            }
462            if (!_train.reset()) {
463                JmriJOptionPane.showMessageDialog(this,
464                        Bundle.getMessage("TrainIsInRoute",
465                                train.getTrainTerminatesName()),
466                        Bundle.getMessage("CanNotDeleteTrain"), JmriJOptionPane.ERROR_MESSAGE);
467                return;
468            }
469            if (JmriJOptionPane.showConfirmDialog(this,
470                    Bundle.getMessage("deleteMsg", train.getName()),
471                    Bundle.getMessage("deleteTrain"), JmriJOptionPane.YES_NO_OPTION) != JmriJOptionPane.YES_OPTION) {
472                return;
473            }
474            routeBox.setSelectedItem(null);
475            trainManager.deregister(train);
476            for (Frame frame : children) {
477                frame.dispose();
478            }
479            _train = null;
480            enableButtons(false);
481            // save train file
482            OperationsXml.save();
483        }
484        if (ae.getSource() == addTrainButton) {
485            if (train != null) {
486                reportTrainExists(Bundle.getMessage("add"));
487                return;
488            }
489            saveNewTrain();
490        }
491        if (ae.getSource() == editButton) {
492            editAddRoute();
493        }
494        if (ae.getSource() == setButton) {
495            selectCheckboxes(true);
496        }
497        if (ae.getSource() == clearButton) {
498            selectCheckboxes(false);
499        }
500        if (ae.getSource() == autoSelectButton) {
501            autoSelect();
502        }
503        if (ae.getSource() == resetButton) {
504            if (_train != null) {
505                if (_train.checkDepartureTrack()) {
506                    int results = JmriJOptionPane.showConfirmDialog(null,
507                            Bundle.getMessage("StagingTrackUsed",
508                                    _train.getDepartureTrack().getName()),
509                            Bundle.getMessage("ShouldNotResetTrain"), JmriJOptionPane.OK_CANCEL_OPTION);
510                    if (results == JmriJOptionPane.OK_CANCEL_OPTION) {
511                        return;
512                    }
513                }
514                Train t = trainManager.getTrainBuiltAfter(train);
515                if (Setup.isBuildOnTime() && t != null) {
516                    JmriJOptionPane.showMessageDialog(null,
517                            Bundle.getMessage("TrainAfterBuilt", t, train), Bundle.getMessage("CanNotResetTrain"),
518                            JmriJOptionPane.WARNING_MESSAGE);
519                } else if (!_train.reset()) {
520                    JmriJOptionPane.showMessageDialog(this,
521                            Bundle.getMessage("TrainIsInRoute",
522                                    _train.getTrainTerminatesName()),
523                            Bundle.getMessage("CanNotResetTrain"), JmriJOptionPane.ERROR_MESSAGE);
524                }
525            }
526        }
527    }
528
529    @Override
530    public void radioButtonActionPerformed(java.awt.event.ActionEvent ae) {
531        log.debug("radio button activated");
532        if (_train != null) {
533            if (ae.getSource() == noneRadioButton ||
534                    ae.getSource() == cabooseRadioButton ||
535                    ae.getSource() == fredRadioButton) {
536                updateCabooseRoadComboBox();
537            }
538        }
539    }
540
541    private void saveNewTrain() {
542        if (!checkName(Bundle.getMessage("add"))) {
543            return;
544        }
545        Train train = trainManager.newTrain(trainNameTextField.getText());
546        _train = train;
547        _train.addPropertyChangeListener(this);
548
549        // update check boxes
550        updateCarTypeCheckboxes();
551        updateEngineTypeCheckboxes();
552        // enable check boxes and buttons
553        enableButtons(true);
554        saveTrain();
555        loadToolMenu(toolMenu);
556    }
557
558    private boolean saveTrain() {
559        if (!checkName(Bundle.getMessage("save"))) {
560            return false;
561        }
562        if (!checkModel() || !checkEngineRoad() || !checkCabooseRoad()) {
563            return false;
564        }
565        if (!_train.getName().equals(trainNameTextField.getText().trim()) ||
566                !_train.getRawDescription().equals(trainDescriptionTextField.getText()) ||
567                !_train.getCommentWithColor().equals(
568                        TrainCommon.formatColorString(commentTextArea.getText(), commentColorChooser.getColor(),
569                                boldCheckBox.isSelected()))) {
570            _train.setModified(true);
571        }
572        _train.setDepartureTime(dayBox.getSelectedItem().toString(), hourBox.getSelectedItem().toString(),
573                minuteBox.getSelectedItem().toString());
574        _train.setNumberEngines((String) numEnginesBox.getSelectedItem());
575        if (_train.getNumberEngines().equals("0")) {
576            modelEngineBox.setSelectedIndex(0);
577            roadEngineBox.setSelectedIndex(0);
578        }
579        _train.setEngineRoad((String) roadEngineBox.getSelectedItem());
580        _train.setEngineModel((String) modelEngineBox.getSelectedItem());
581        if (cabooseRadioButton.isSelected()) {
582            _train.setRequirements(Train.CABOOSE);
583        }
584        if (fredRadioButton.isSelected()) {
585            _train.setRequirements(Train.FRED);
586        }
587        if (noneRadioButton.isSelected()) {
588            _train.setRequirements(Train.NO_CABOOSE_OR_FRED);
589        }
590        _train.setCabooseRoad((String) roadCabooseBox.getSelectedItem());
591        _train.setName(trainNameTextField.getText().trim());
592        _train.setDescription(trainDescriptionTextField.getText());
593        _train.setComment(TrainCommon.formatColorString(commentTextArea.getText(), commentColorChooser.getColor(),
594                boldCheckBox.isSelected()));
595        // save train file
596        OperationsXml.save();
597        return true;
598    }
599
600    /**
601     * @return true if name isn't too long and is at least one character
602     */
603    private boolean checkName(String s) {
604        String trainName = trainNameTextField.getText().trim();
605        if (trainName.isEmpty()) {
606            log.debug("Must enter a train name");
607            JmriJOptionPane.showMessageDialog(this, Bundle.getMessage("MustEnterName"),
608                    Bundle.getMessage("CanNot", s), JmriJOptionPane.ERROR_MESSAGE);
609            return false;
610        }
611        if (trainName.length() > Control.max_len_string_train_name) {
612            JmriJOptionPane.showMessageDialog(this,
613                    Bundle.getMessage("TrainNameLess",
614                            Control.max_len_string_train_name + 1),
615                    Bundle.getMessage("CanNot", s), JmriJOptionPane.ERROR_MESSAGE);
616            return false;
617        }
618        if (!OperationsXml.checkFileName(trainName)) { // NOI18N
619            log.error("Train name must not contain reserved characters");
620            JmriJOptionPane.showMessageDialog(this,
621                    Bundle.getMessage("NameResChar") + NEW_LINE + Bundle.getMessage("ReservedChar"),
622                    Bundle.getMessage("CanNot", s), JmriJOptionPane.ERROR_MESSAGE);
623            return false;
624        }
625
626        return true;
627    }
628
629    private boolean checkModel() {
630        String model = (String) modelEngineBox.getSelectedItem();
631        if (numEnginesBox.getSelectedItem().equals("0") || model.equals(NONE)) {
632            return true;
633        }
634        String type = InstanceManager.getDefault(EngineModels.class).getModelType(model);
635        if (!_train.isTypeNameAccepted(type)) {
636            JmriJOptionPane.showMessageDialog(this,
637                    Bundle.getMessage("TrainModelService", model, type),
638                    Bundle.getMessage("CanNot", Bundle.getMessage("save")),
639                    JmriJOptionPane.ERROR_MESSAGE);
640            return false;
641        }
642        if (roadEngineBox.getItemCount() == 1) {
643            log.debug("No locos available that match the model selected!");
644            JmriJOptionPane.showMessageDialog(this,
645                    Bundle.getMessage("NoLocosModel", model),
646                    Bundle.getMessage("TrainWillNotBuild", _train.getName()),
647                    JmriJOptionPane.WARNING_MESSAGE);
648        }
649        return true;
650    }
651
652    private boolean checkEngineRoad() {
653        String road = (String) roadEngineBox.getSelectedItem();
654        if (numEnginesBox.getSelectedItem().equals("0") || road.equals(NONE)) {
655            return true;
656        }
657        if (!road.equals(NONE) && !_train.isLocoRoadNameAccepted(road)) {
658            JmriJOptionPane.showMessageDialog(this,
659                    Bundle.getMessage("TrainNotThisRoad", _train.getName(), road),
660                    Bundle.getMessage("TrainWillNotBuild", _train.getName()),
661                    JmriJOptionPane.WARNING_MESSAGE);
662            return false;
663        }
664        for (RollingStock rs : InstanceManager.getDefault(EngineManager.class).getList()) {
665            if (!_train.isTypeNameAccepted(rs.getTypeName())) {
666                continue;
667            }
668            if (rs.getRoadName().equals(road)) {
669                return true;
670            }
671        }
672        JmriJOptionPane.showMessageDialog(this,
673                Bundle.getMessage("NoLocoRoad", road),
674                Bundle.getMessage("TrainWillNotBuild", _train.getName()),
675                JmriJOptionPane.WARNING_MESSAGE);
676        return false; // couldn't find a loco with the selected road
677    }
678
679    private boolean checkCabooseRoad() {
680        String road = (String) roadCabooseBox.getSelectedItem();
681        if (!road.equals(NONE) && cabooseRadioButton.isSelected() && !_train.isCabooseRoadNameAccepted(road)) {
682            JmriJOptionPane.showMessageDialog(this,
683                    Bundle.getMessage("TrainNotCabooseRoad", _train.getName(), road),
684                    Bundle.getMessage("TrainWillNotBuild", _train.getName()),
685                    JmriJOptionPane.WARNING_MESSAGE);
686            return false;
687        }
688        return true;
689    }
690
691    private boolean checkRoute() {
692        if (_train.getRoute() == null) {
693            JmriJOptionPane.showMessageDialog(this, Bundle.getMessage("TrainNeedsRoute"),
694                    Bundle.getMessage("TrainNoRoute"),
695                    JmriJOptionPane.WARNING_MESSAGE);
696            return false;
697        }
698        return true;
699
700    }
701
702    private void reportTrainExists(String s) {
703        log.debug("Can not {}, train already exists", s);
704        JmriJOptionPane.showMessageDialog(this, Bundle.getMessage("TrainNameExists"),
705                Bundle.getMessage("CanNot", s), JmriJOptionPane.ERROR_MESSAGE);
706    }
707
708    private void enableButtons(boolean enabled) {
709        toolMenu.setEnabled(enabled);
710        editButton.setEnabled(enabled);
711        routeBox.setEnabled(enabled && _train != null && !_train.isBuilt());
712        clearButton.setEnabled(enabled);
713        resetButton.setEnabled(enabled);
714        autoSelectButton.setEnabled(enabled);
715        setButton.setEnabled(enabled);
716        saveTrainButton.setEnabled(enabled);
717        deleteTrainButton.setEnabled(enabled);
718        numEnginesBox.setEnabled(enabled);
719        enableCheckboxes(enabled);
720        noneRadioButton.setEnabled(enabled);
721        fredRadioButton.setEnabled(enabled);
722        cabooseRadioButton.setEnabled(enabled);
723        roadOptionButton.setEnabled(enabled);
724        loadOptionButton.setEnabled(enabled);
725        // the inverse!
726        addTrainButton.setEnabled(!enabled);
727    }
728
729    private void selectCheckboxes(boolean enable) {
730        for (int i = 0; i < typeCarCheckBoxes.size(); i++) {
731            JCheckBox checkBox = typeCarCheckBoxes.get(i);
732            checkBox.setSelected(enable);
733            if (_train != null) {
734                _train.removePropertyChangeListener(this);
735                if (enable) {
736                    _train.addTypeName(checkBox.getText());
737                } else {
738                    _train.deleteTypeName(checkBox.getText());
739                }
740                _train.addPropertyChangeListener(this);
741            }
742        }
743    }
744
745    private void autoSelect() {
746        if (_train != null) {
747            Route route = _train.getRoute();
748            if (route != null) {
749                typeLoop: for (String type : InstanceManager.getDefault(CarTypes.class).getNames()) {
750                    for (RouteLocation rl : route.getLocationsBySequenceList()) {
751                        if (rl.getMaxCarMoves() > 0 && (rl.isDropAllowed() || rl.isLocalMovesAllowed())) {
752                            if (!_train.isLocationSkipped(rl) && rl.getLocation().acceptsTypeName(type)) {
753                                continue typeLoop;
754                            }
755                        }
756                    }
757                    _train.deleteTypeName(type);
758                }
759            }
760        }
761    }
762
763    @Override
764    public void comboBoxActionPerformed(java.awt.event.ActionEvent ae) {
765        if (_train == null) {
766            return;
767        }
768        if (ae.getSource() == numEnginesBox) {
769            modelEngineBox.setEnabled(!numEnginesBox.getSelectedItem().equals("0"));
770            roadEngineBox.setEnabled(!numEnginesBox.getSelectedItem().equals("0"));
771        }
772        if (ae.getSource() == modelEngineBox) {
773            updateEngineRoadComboBox();
774        }
775        if (ae.getSource() == routeBox) {
776            if (routeBox.isEnabled()) {
777                Route route = _train.getRoute();
778                if (route != null) {
779                    route.removePropertyChangeListener(this);
780                }
781                Object selected = routeBox.getSelectedItem();
782                if (selected != null) {
783                    route = (Route) selected;
784                    _train.setRoute(route);
785                    route.addPropertyChangeListener(this);
786                } else {
787                    _train.setRoute(null);
788                }
789                updateLocationCheckboxes();
790                updateDepartureTime();
791                pack();
792                repaint();
793            }
794        }
795    }
796
797    private void enableCheckboxes(boolean enable) {
798        for (int i = 0; i < typeCarCheckBoxes.size(); i++) {
799            typeCarCheckBoxes.get(i).setEnabled(enable);
800        }
801        for (int i = 0; i < typeEngineCheckBoxes.size(); i++) {
802            typeEngineCheckBoxes.get(i).setEnabled(enable);
803        }
804    }
805
806    private void addLocationCheckBoxAction(JCheckBox b) {
807        b.addActionListener(new java.awt.event.ActionListener() {
808            @Override
809            public void actionPerformed(java.awt.event.ActionEvent e) {
810                locationCheckBoxActionPerformed(e);
811            }
812        });
813    }
814
815    public void locationCheckBoxActionPerformed(java.awt.event.ActionEvent ae) {
816        JCheckBox b = (JCheckBox) ae.getSource();
817        log.debug("checkbox change {}", b.getText());
818        if (_train == null) {
819            return;
820        }
821        String id = b.getName();
822        RouteLocation rl = _train.getRoute().getRouteLocationById(id);
823        if (b.isSelected()) {
824            _train.deleteTrainSkipsLocation(rl);
825        } else {
826            // check to see if skipped location is staging
827            if (_train.getRoute().getRouteLocationById(id).getLocation().isStaging()) {
828                int result = JmriJOptionPane.showConfirmDialog(this,
829                        Bundle.getMessage("TrainRouteStaging",
830                                _train.getName(), _train.getRoute().getRouteLocationById(id).getName()),
831                        Bundle.getMessage("TrainRouteNotStaging"), JmriJOptionPane.OK_CANCEL_OPTION);
832                if (result != JmriJOptionPane.OK_OPTION) {
833                    b.setSelected(true);
834                    return; // don't skip staging
835                }
836            }
837            _train.addTrainSkipsLocation(rl);
838        }
839    }
840
841    private void updateRouteComboBox() {
842        routeBox.setEnabled(false);
843        routeManager.updateComboBox(routeBox);
844        if (_train != null) {
845            routeBox.setSelectedItem(_train.getRoute());
846        }
847        routeBox.setEnabled(true);
848    }
849
850    private void updateCarTypeCheckboxes() {
851        typeCarCheckBoxes.clear();
852        typeCarPanelCheckBoxes.removeAll();
853        loadCarTypes();
854        enableCheckboxes(_train != null);
855        typeCarPanelCheckBoxes.revalidate();
856        repaint();
857    }
858
859    private void loadCarTypes() {
860        int numberOfCheckboxes = getNumberOfCheckboxesPerLine(); // number per line
861        int x = 0;
862        int y = 1; // vertical position in panel
863        for (String type : InstanceManager.getDefault(CarTypes.class).getNames()) {
864            JCheckBox checkBox = new javax.swing.JCheckBox();
865            typeCarCheckBoxes.add(checkBox);
866            checkBox.setText(type);
867            addTypeCheckBoxAction(checkBox);
868            addItemLeft(typeCarPanelCheckBoxes, checkBox, x++, y);
869            if (_train != null && _train.isTypeNameAccepted(type)) {
870                checkBox.setSelected(true);
871            }
872            if (x > numberOfCheckboxes) {
873                y++;
874                x = 0;
875            }
876        }
877
878        JPanel p = new JPanel();
879        p.add(clearButton);
880        p.add(setButton);
881        p.add(autoSelectButton);
882        GridBagConstraints gc = new GridBagConstraints();
883        gc.gridwidth = getNumberOfCheckboxesPerLine() + 1;
884        gc.gridy = ++y;
885        typeCarPanelCheckBoxes.add(p, gc);
886
887    }
888
889    private void updateEngineTypeCheckboxes() {
890        typeEngineCheckBoxes.clear();
891        typeEnginePanelCheckBoxes.removeAll();
892        loadEngineTypes();
893        enableCheckboxes(_train != null);
894        typeEnginePanelCheckBoxes.revalidate();
895        repaint();
896    }
897
898    private void loadEngineTypes() {
899        int numberOfCheckboxes = getNumberOfCheckboxesPerLine(); // number per line
900        int x = 0;
901        int y = 1;
902        for (String type : InstanceManager.getDefault(EngineTypes.class).getNames()) {
903            JCheckBox checkBox = new javax.swing.JCheckBox();
904            typeEngineCheckBoxes.add(checkBox);
905            checkBox.setText(type);
906            addTypeCheckBoxAction(checkBox);
907            addItemLeft(typeEnginePanelCheckBoxes, checkBox, x++, y);
908            if (_train != null && _train.isTypeNameAccepted(type)) {
909                checkBox.setSelected(true);
910            }
911            if (x > numberOfCheckboxes) {
912                y++;
913                x = 0;
914            }
915        }
916    }
917
918    private void updateRoadComboBoxes() {
919        updateCabooseRoadComboBox();
920        updateEngineRoadComboBox();
921    }
922
923    // update caboose road box based on radio selection
924    private void updateCabooseRoadComboBox() {
925        roadCabooseBox.removeAllItems();
926        roadCabooseBox.addItem(NONE);
927        if (noneRadioButton.isSelected()) {
928            roadCabooseBox.setEnabled(false);
929            return;
930        }
931        roadCabooseBox.setEnabled(true);
932        List<String> roads;
933        if (cabooseRadioButton.isSelected()) {
934            roads = InstanceManager.getDefault(CarManager.class).getCabooseRoadNames();
935        } else {
936            roads = InstanceManager.getDefault(CarManager.class).getFredRoadNames();
937        }
938        for (String road : roads) {
939            roadCabooseBox.addItem(road);
940        }
941        if (_train != null) {
942            roadCabooseBox.setSelectedItem(_train.getCabooseRoad());
943        }
944        OperationsPanel.padComboBox(roadCabooseBox);
945    }
946
947    private void updateEngineRoadComboBox() {
948        String engineModel = (String) modelEngineBox.getSelectedItem();
949        if (engineModel == null) {
950            return;
951        }
952        InstanceManager.getDefault(EngineManager.class).updateEngineRoadComboBox(engineModel, roadEngineBox);
953        if (_train != null) {
954            roadEngineBox.setSelectedItem(_train.getEngineRoad());
955        }
956    }
957
958    private void addTypeCheckBoxAction(JCheckBox b) {
959        b.addActionListener(new java.awt.event.ActionListener() {
960            @Override
961            public void actionPerformed(java.awt.event.ActionEvent e) {
962                typeCheckBoxActionPerformed(e);
963            }
964        });
965    }
966
967    public void typeCheckBoxActionPerformed(java.awt.event.ActionEvent ae) {
968        JCheckBox b = (JCheckBox) ae.getSource();
969        log.debug("checkbox change {}", b.getText());
970        if (_train == null) {
971            return;
972        }
973        if (b.isSelected()) {
974            _train.addTypeName(b.getText());
975        } else {
976            _train.deleteTypeName(b.getText());
977        }
978    }
979
980    // the train's route shown as locations with checkboxes
981    private void updateLocationCheckboxes() {
982        updateRouteStatus();
983        locationCheckBoxes.clear();
984        locationPanelCheckBoxes.removeAll();
985        int y = 0; // vertical position in panel
986        Route route = null;
987        if (_train != null) {
988            route = _train.getRoute();
989        }
990        if (route != null) {
991            List<RouteLocation> routeList = route.getLocationsBySequenceList();
992            for (RouteLocation rl : routeList) {
993                JCheckBox checkBox = new javax.swing.JCheckBox();
994                locationCheckBoxes.add(checkBox);
995                checkBox.setText(rl.toString());
996                checkBox.setName(rl.getId());
997                addItemLeft(locationPanelCheckBoxes, checkBox, 0, y++);
998                Location loc = InstanceManager.getDefault(LocationManager.class).getLocationByName(rl.getName());
999                // does the location exist?
1000                if (loc != null) {
1001                    // need to listen for name and direction changes
1002                    loc.removePropertyChangeListener(this);
1003                    loc.addPropertyChangeListener(this);
1004                    boolean services = false;
1005                    // does train direction service location?
1006                    if ((rl.getTrainDirection() & loc.getTrainDirections()) != 0) {
1007                        services = true;
1008                    } // train must service last location or single location
1009                    else if (_train.isLocalSwitcher() || rl == _train.getTrainTerminatesRouteLocation()) {
1010                        services = true;
1011                    }
1012                    // check can drop and pick up, and moves > 0
1013                    if (services &&
1014                            (rl.isDropAllowed() || rl.isPickUpAllowed() || rl.isLocalMovesAllowed()) &&
1015                            rl.getMaxCarMoves() > 0) {
1016                        checkBox.setSelected(!_train.isLocationSkipped(rl));
1017                    } else {
1018                        checkBox.setEnabled(false);
1019                    }
1020                    addLocationCheckBoxAction(checkBox);
1021                } else {
1022                    checkBox.setEnabled(false);
1023                }
1024            }
1025        }
1026        locationPanelCheckBoxes.revalidate();
1027    }
1028
1029    private void updateRouteStatus() {
1030        Route route = null;
1031        textRouteStatus.setText(NONE); // clear out previous status
1032        if (_train != null) {
1033            route = _train.getRoute();
1034        }
1035        if (route != null) {
1036            if (!route.getStatus().equals(Route.OKAY)) {
1037                textRouteStatus.setText(route.getStatus());
1038                textRouteStatus.setForeground(Color.RED);
1039            }
1040        }
1041    }
1042
1043    RouteEditFrame ref;
1044
1045    private void editAddRoute() {
1046        log.debug("Edit/add route");
1047        if (ref != null) {
1048            ref.dispose();
1049        }
1050        ref = new RouteEditFrame();
1051        setChildFrame(ref);
1052        Route route = (Route) routeBox.getSelectedItem();
1053        ref.initComponents(route, _train);
1054    }
1055
1056    private void updateDepartureTime() {
1057        dayBox.setSelectedItem(_train.getDepartureTimeDay());
1058        hourBox.setSelectedItem(_train.getDepartureTimeHour());
1059        minuteBox.setSelectedItem(_train.getDepartureTimeMinute());
1060        // check to see if route has a departure time from the 1st location
1061        RouteLocation rl = _train.getTrainDepartsRouteLocation();
1062        if (rl != null && !rl.getDepartureTimeHourMinutes().equals(NONE)) {
1063            dayBox.setEnabled(false);
1064            hourBox.setEnabled(false);
1065            minuteBox.setEnabled(false);
1066        } else {
1067            dayBox.setEnabled(!_train.isBuilt());
1068            hourBox.setEnabled(!_train.isBuilt());
1069            minuteBox.setEnabled(!_train.isBuilt());
1070        }
1071    }
1072
1073    private void updateRoadAndLoadStatus() {
1074        if (_train != null) {
1075            // road options
1076            if (_train.getCarRoadOption().equals(Train.INCLUDE_ROADS)) {
1077                roadOptionButton.setText(Bundle.getMessage(
1078                        "AcceptOnly") + " " + _train.getCarRoadNames().length + " " + Bundle.getMessage("RoadsCar"));
1079            } else if (_train.getCarRoadOption().equals(Train.EXCLUDE_ROADS)) {
1080                roadOptionButton.setText(Bundle.getMessage(
1081                        "Exclude") + " " + _train.getCarRoadNames().length + " " + Bundle.getMessage("RoadsCar"));
1082            } else if (_train.getCabooseRoadOption().equals(Train.INCLUDE_ROADS)) {
1083                roadOptionButton.setText(Bundle.getMessage(
1084                        "AcceptOnly") +
1085                        " " +
1086                        _train.getCabooseRoadNames().length +
1087                        " " +
1088                        Bundle.getMessage("RoadsCaboose"));
1089            } else if (_train.getCabooseRoadOption().equals(Train.EXCLUDE_ROADS)) {
1090                roadOptionButton.setText(Bundle.getMessage(
1091                        "Exclude") +
1092                        " " +
1093                        _train.getCabooseRoadNames().length +
1094                        " " +
1095                        Bundle.getMessage("RoadsCaboose"));
1096            } else if (_train.getLocoRoadOption().equals(Train.INCLUDE_ROADS)) {
1097                roadOptionButton.setText(Bundle.getMessage(
1098                        "AcceptOnly") + " " + _train.getLocoRoadNames().length + " " + Bundle.getMessage("RoadsLoco"));
1099            } else if (_train.getLocoRoadOption().equals(Train.EXCLUDE_ROADS)) {
1100                roadOptionButton.setText(Bundle.getMessage(
1101                        "Exclude") + " " + _train.getLocoRoadNames().length + " " + Bundle.getMessage("RoadsLoco"));
1102            } else {
1103                roadOptionButton.setText(Bundle.getMessage("AcceptAll"));
1104            }
1105            // load options
1106            if (_train.getLoadOption().equals(Train.ALL_LOADS)) {
1107                loadOptionButton.setText(Bundle.getMessage("AcceptAll"));
1108            } else if (_train.getLoadOption().equals(Train.INCLUDE_LOADS)) {
1109                loadOptionButton.setText(Bundle.getMessage(
1110                        "AcceptOnly") + " " + _train.getLoadNames().length + " " + Bundle.getMessage("Loads"));
1111            } else {
1112                loadOptionButton.setText(Bundle.getMessage(
1113                        "Exclude") + " " + _train.getLoadNames().length + " " + Bundle.getMessage("Loads"));
1114            }
1115            if (!_train.getCarRoadOption().equals(Train.ALL_ROADS) ||
1116                    !_train.getCabooseRoadOption().equals(Train.ALL_ROADS) ||
1117                    !_train.getLocoRoadOption().equals(Train.ALL_ROADS) ||
1118                    !_train.getLoadOption().equals(Train.ALL_LOADS)) {
1119                roadAndLoadStatusPanel.setVisible(true);
1120            }
1121        }
1122    }
1123
1124    List<Frame> children = new ArrayList<>();
1125
1126    public void setChildFrame(Frame frame) {
1127        if (children.contains(frame)) {
1128            return;
1129        }
1130        children.add(frame);
1131    }
1132
1133    @Override
1134    public void dispose() {
1135        InstanceManager.getDefault(LocationManager.class).removePropertyChangeListener(this);
1136        InstanceManager.getDefault(EngineTypes.class).removePropertyChangeListener(this);
1137        InstanceManager.getDefault(EngineModels.class).removePropertyChangeListener(this);
1138        InstanceManager.getDefault(CarTypes.class).removePropertyChangeListener(this);
1139        InstanceManager.getDefault(CarRoads.class).removePropertyChangeListener(this);
1140        routeManager.removePropertyChangeListener(this);
1141        for (Frame frame : children) {
1142            frame.dispose();
1143        }
1144        if (_train != null) {
1145            _train.removePropertyChangeListener(this);
1146            Route route = _train.getRoute();
1147            if (route != null) {
1148                for (RouteLocation rl : route.getLocationsBySequenceList()) {
1149                    Location loc = rl.getLocation();
1150                    if (loc != null) {
1151                        loc.removePropertyChangeListener(this);
1152                    }
1153                }
1154            }
1155        }
1156        super.dispose();
1157    }
1158
1159    @Override
1160    public void propertyChange(java.beans.PropertyChangeEvent e) {
1161        if (Control.SHOW_PROPERTY) {
1162            log.debug("Property change ({}) old: ({}) new: ({})", e.getPropertyName(), e.getOldValue(),
1163                    e.getNewValue()); // NOI18N
1164        }
1165        if (e.getPropertyName().equals(CarTypes.CARTYPES_CHANGED_PROPERTY) ||
1166                e.getPropertyName().equals(Train.TYPES_CHANGED_PROPERTY)) {
1167            updateCarTypeCheckboxes();
1168        }
1169        if (e.getPropertyName().equals(EngineTypes.ENGINETYPES_CHANGED_PROPERTY)) {
1170            updateEngineTypeCheckboxes();
1171        }
1172        if (e.getPropertyName().equals(RouteManager.LISTLENGTH_CHANGED_PROPERTY)) {
1173            updateRouteComboBox();
1174        }
1175        if (e.getPropertyName().equals(Route.LISTCHANGE_CHANGED_PROPERTY) ||
1176                e.getPropertyName().equals(LocationManager.LISTLENGTH_CHANGED_PROPERTY) ||
1177                e.getPropertyName().equals(Location.NAME_CHANGED_PROPERTY) ||
1178                e.getPropertyName().equals(Location.TRAIN_DIRECTION_CHANGED_PROPERTY)) {
1179            updateLocationCheckboxes();
1180            pack();
1181            repaint();
1182        }
1183        if (e.getPropertyName().equals(CarRoads.CARROADS_CHANGED_PROPERTY)) {
1184            updateRoadComboBoxes();
1185        }
1186        if (e.getPropertyName().equals(EngineModels.ENGINEMODELS_CHANGED_PROPERTY)) {
1187            InstanceManager.getDefault(EngineModels.class).updateComboBox(modelEngineBox);
1188            modelEngineBox.insertItemAt(NONE, 0);
1189            modelEngineBox.setSelectedIndex(0);
1190            if (_train != null) {
1191                modelEngineBox.setSelectedItem(_train.getEngineModel());
1192            }
1193        }
1194        if (e.getPropertyName().equals(Train.DEPARTURETIME_CHANGED_PROPERTY)) {
1195            updateDepartureTime();
1196        }
1197        if (e.getPropertyName().equals(Train.TRAIN_ROUTE_CHANGED_PROPERTY) && _train != null) {
1198            routeBox.setSelectedItem(_train.getRoute());
1199        }
1200        if (e.getPropertyName().equals(Route.ROUTE_STATUS_CHANGED_PROPERTY)) {
1201            updateDepartureTime();
1202            enableButtons(_train != null);
1203            updateRouteStatus();
1204        }
1205        if (e.getPropertyName().equals(Train.ROADS_CHANGED_PROPERTY) ||
1206                e.getPropertyName().equals(Train.LOADS_CHANGED_PROPERTY)) {
1207            updateRoadAndLoadStatus();
1208        }
1209    }
1210
1211    private static final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(TrainEditFrame.class);
1212}