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