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