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