001package jmri.jmrit.operations.locations;
002
003import java.awt.*;
004import java.util.ArrayList;
005import java.util.List;
006
007import javax.swing.*;
008
009import jmri.*;
010import jmri.jmrit.operations.OperationsFrame;
011import jmri.jmrit.operations.OperationsXml;
012import jmri.jmrit.operations.locations.tools.*;
013import jmri.jmrit.operations.rollingstock.cars.*;
014import jmri.jmrit.operations.rollingstock.engines.EngineTypes;
015import jmri.jmrit.operations.routes.Route;
016import jmri.jmrit.operations.routes.RouteManager;
017import jmri.jmrit.operations.setup.Control;
018import jmri.jmrit.operations.setup.Setup;
019import jmri.jmrit.operations.trains.*;
020import jmri.swing.NamedBeanComboBox;
021import jmri.util.swing.JmriJOptionPane;
022
023/**
024 * Frame for user edit of tracks. Base for edit of all track types.
025 *
026 * @author Dan Boudreau Copyright (C) 2008, 2010, 2011, 2012, 2013, 2023
027 */
028public abstract class TrackEditFrame extends OperationsFrame implements java.beans.PropertyChangeListener {
029
030    // where in the tool menu new items are inserted
031    protected static final int TOOL_MENU_OFFSET = 4;
032
033    // Managers
034    TrainManager trainManager = InstanceManager.getDefault(TrainManager.class);
035    RouteManager routeManager = InstanceManager.getDefault(RouteManager.class);
036
037    public Location _location = null;
038    public Track _track = null;
039    String _type = "";
040    JMenu _toolMenu = new JMenu(Bundle.getMessage("MenuTools"));
041
042    List<JCheckBox> checkBoxes = new ArrayList<>();
043
044    // panels
045    JPanel panelCheckBoxes = new JPanel();
046    JScrollPane paneCheckBoxes = new JScrollPane(panelCheckBoxes);
047    JPanel panelTrainDir = new JPanel();
048    JPanel pShipLoadOption = new JPanel();
049    JPanel pDestinationOption = new JPanel();
050    JPanel panelOrder = new JPanel();
051
052    // Alternate tool buttons
053    JButton loadOptionButton = new JButton(Bundle.getMessage("AcceptsAllLoads"));
054    JButton shipLoadOptionButton = new JButton(Bundle.getMessage("ShipsAllLoads"));
055    JButton roadOptionButton = new JButton(Bundle.getMessage("AcceptsAllRoads"));
056    JButton destinationOptionButton = new JButton();
057
058    // major buttons
059    JButton clearButton = new JButton(Bundle.getMessage("ClearAll"));
060    JButton setButton = new JButton(Bundle.getMessage("SelectAll"));
061    JButton autoSelectButton = new JButton(Bundle.getMessage("AutoSelect"));
062    
063    JButton saveTrackButton = new JButton(Bundle.getMessage("SaveTrack"));
064    JButton deleteTrackButton = new JButton(Bundle.getMessage("DeleteTrack"));
065    JButton addTrackButton = new JButton(Bundle.getMessage("AddTrack"));
066
067    JButton deleteDropButton = new JButton(Bundle.getMessage("ButtonDelete"));
068    JButton addDropButton = new JButton(Bundle.getMessage("Add"));
069    JButton deletePickupButton = new JButton(Bundle.getMessage("ButtonDelete"));
070    JButton addPickupButton = new JButton(Bundle.getMessage("Add"));
071
072    // check boxes
073    JCheckBox northCheckBox = new JCheckBox(Bundle.getMessage("North"));
074    JCheckBox southCheckBox = new JCheckBox(Bundle.getMessage("South"));
075    JCheckBox eastCheckBox = new JCheckBox(Bundle.getMessage("East"));
076    JCheckBox westCheckBox = new JCheckBox(Bundle.getMessage("West"));
077    JCheckBox autoDropCheckBox = new JCheckBox(Bundle.getMessage("Auto"));
078    JCheckBox autoPickupCheckBox = new JCheckBox(Bundle.getMessage("Auto"));
079
080    // car pick up order controls
081    JRadioButton orderNormal = new JRadioButton(Bundle.getMessage("Normal"));
082    JRadioButton orderFIFO = new JRadioButton(Bundle.getMessage("DescriptiveFIFO"));
083    JRadioButton orderLIFO = new JRadioButton(Bundle.getMessage("DescriptiveLIFO"));
084
085    JRadioButton anyDrops = new JRadioButton(Bundle.getMessage("Any"));
086    JRadioButton trainDrop = new JRadioButton(Bundle.getMessage("Trains"));
087    JRadioButton routeDrop = new JRadioButton(Bundle.getMessage("Routes"));
088    JRadioButton excludeTrainDrop = new JRadioButton(Bundle.getMessage("ExcludeTrains"));
089    JRadioButton excludeRouteDrop = new JRadioButton(Bundle.getMessage("ExcludeRoutes"));
090
091    JRadioButton anyPickups = new JRadioButton(Bundle.getMessage("Any"));
092    JRadioButton trainPickup = new JRadioButton(Bundle.getMessage("Trains"));
093    JRadioButton routePickup = new JRadioButton(Bundle.getMessage("Routes"));
094    JRadioButton excludeTrainPickup = new JRadioButton(Bundle.getMessage("ExcludeTrains"));
095    JRadioButton excludeRoutePickup = new JRadioButton(Bundle.getMessage("ExcludeRoutes"));
096
097    JComboBox<Train> comboBoxDropTrains = trainManager.getTrainComboBox();
098    JComboBox<Route> comboBoxDropRoutes = routeManager.getComboBox();
099    JComboBox<Train> comboBoxPickupTrains = trainManager.getTrainComboBox();
100    JComboBox<Route> comboBoxPickupRoutes = routeManager.getComboBox();
101
102    // text field
103    JTextField trackNameTextField = new JTextField(Control.max_len_string_track_name);
104    JTextField trackLengthTextField = new JTextField(Control.max_len_string_track_length_name);
105
106    // text area
107    JTextArea commentTextArea = new JTextArea(2, 60);
108    JScrollPane commentScroller = new JScrollPane(commentTextArea, JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED,
109            JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED);
110
111    // optional panel for spurs, staging, and interchanges
112    JPanel dropPanel = new JPanel();
113    JPanel pickupPanel = new JPanel();
114    JPanel panelOpt3 = new JPanel(); // not currently used
115    JPanel panelOpt4 = new JPanel();
116
117    // Reader selection dropdown.
118    NamedBeanComboBox<Reporter> readerSelector;
119
120    public static final String DISPOSE = "dispose"; // NOI18N
121    public static final int MAX_NAME_LENGTH = Control.max_len_string_track_name;
122
123    public TrackEditFrame(String title) {
124        super(title);
125    }
126
127    protected abstract void initComponents(Track track);
128
129    public void initComponents(Location location, Track track) {
130        _location = location;
131        _track = track;
132
133        // tool tips
134        autoDropCheckBox.setToolTipText(Bundle.getMessage("TipAutoTrack"));
135        autoPickupCheckBox.setToolTipText(Bundle.getMessage("TipAutoTrack"));
136        trackLengthTextField.setToolTipText(Bundle.getMessage("TipTrackLength",
137                Setup.getLengthUnit().toLowerCase()));
138
139        // property changes
140        _location.addPropertyChangeListener(this);
141        // listen for car road name and type changes
142        InstanceManager.getDefault(CarRoads.class).addPropertyChangeListener(this);
143        InstanceManager.getDefault(CarLoads.class).addPropertyChangeListener(this);
144        InstanceManager.getDefault(CarTypes.class).addPropertyChangeListener(this);
145        InstanceManager.getDefault(Setup.class).addPropertyChangeListener(this);
146        trainManager.addPropertyChangeListener(this);
147        routeManager.addPropertyChangeListener(this);
148
149        // the following code sets the frame's initial state
150        getContentPane().setLayout(new BoxLayout(getContentPane(), BoxLayout.Y_AXIS));
151
152        // place all panels in a scroll pane.
153        JPanel panels = new JPanel();
154        panels.setLayout(new BoxLayout(panels, BoxLayout.Y_AXIS));
155        JScrollPane pane = new JScrollPane(panels);
156
157        // row 1
158        JPanel p1 = new JPanel();
159        p1.setLayout(new BoxLayout(p1, BoxLayout.X_AXIS));
160        JScrollPane p1Pane = new JScrollPane(p1);
161        p1Pane.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_NEVER);
162        p1Pane.setMinimumSize(new Dimension(300, 3 * trackNameTextField.getPreferredSize().height));
163        p1Pane.setBorder(BorderFactory.createTitledBorder(""));
164
165        // row 1a
166        JPanel pName = new JPanel();
167        pName.setLayout(new GridBagLayout());
168        pName.setBorder(BorderFactory.createTitledBorder(Bundle.getMessage("Name")));
169        addItem(pName, trackNameTextField, 0, 0);
170
171        // row 1b
172        JPanel pLength = new JPanel();
173        pLength.setLayout(new GridBagLayout());
174        pLength.setBorder(BorderFactory.createTitledBorder(Bundle.getMessage("Length")));
175        pLength.setMinimumSize(new Dimension(60, 1));
176        addItem(pLength, trackLengthTextField, 0, 0);
177
178        // row 1c
179        panelTrainDir.setLayout(new GridBagLayout());
180        panelTrainDir.setBorder(BorderFactory.createTitledBorder(Bundle.getMessage("TrainTrack")));
181        panelTrainDir.setPreferredSize(new Dimension(200, 10));
182        addItem(panelTrainDir, northCheckBox, 1, 1);
183        addItem(panelTrainDir, southCheckBox, 2, 1);
184        addItem(panelTrainDir, eastCheckBox, 3, 1);
185        addItem(panelTrainDir, westCheckBox, 4, 1);
186
187        p1.add(pName);
188        p1.add(pLength);
189        p1.add(panelTrainDir);
190
191        // row 2
192        paneCheckBoxes.setBorder(BorderFactory.createTitledBorder(Bundle.getMessage("TypesTrack")));
193        panelCheckBoxes.setLayout(new GridBagLayout());
194
195        // status panel for roads and loads
196        JPanel panelRoadAndLoadStatus = new JPanel();
197        panelRoadAndLoadStatus.setLayout(new BoxLayout(panelRoadAndLoadStatus, BoxLayout.X_AXIS));
198
199        // row 3
200        JPanel pRoadOption = new JPanel();
201        pRoadOption.setBorder(BorderFactory.createTitledBorder(Bundle.getMessage("RoadOption")));
202        pRoadOption.add(roadOptionButton);
203        roadOptionButton.addActionListener(new TrackRoadEditAction(this));
204
205        JPanel pLoadOption = new JPanel();
206        pLoadOption.setBorder(BorderFactory.createTitledBorder(Bundle.getMessage("LoadOption")));
207        pLoadOption.add(loadOptionButton);
208        loadOptionButton.addActionListener(new TrackLoadEditAction(this));
209
210        pShipLoadOption.setBorder(BorderFactory.createTitledBorder(Bundle.getMessage("ShipLoadOption")));
211        pShipLoadOption.add(shipLoadOptionButton);
212        shipLoadOptionButton.addActionListener(new TrackLoadEditAction(this));
213
214        pDestinationOption.setBorder(BorderFactory.createTitledBorder(Bundle.getMessage("Destinations")));
215        pDestinationOption.add(destinationOptionButton);
216        destinationOptionButton.addActionListener(new TrackDestinationEditAction(this));
217
218        panelRoadAndLoadStatus.add(pRoadOption);
219        panelRoadAndLoadStatus.add(pLoadOption);
220        panelRoadAndLoadStatus.add(pShipLoadOption);
221        panelRoadAndLoadStatus.add(pDestinationOption);
222
223        // only staging uses the ship load option
224        pShipLoadOption.setVisible(false);
225        // only classification/interchange tracks use the destination option
226        pDestinationOption.setVisible(false);
227
228        // row 4, order panel
229        panelOrder.setLayout(new GridBagLayout());
230        panelOrder.setBorder(BorderFactory.createTitledBorder(Bundle.getMessage("PickupOrder")));
231        panelOrder.add(orderNormal);
232        panelOrder.add(orderFIFO);
233        panelOrder.add(orderLIFO);
234
235        ButtonGroup orderGroup = new ButtonGroup();
236        orderGroup.add(orderNormal);
237        orderGroup.add(orderFIFO);
238        orderGroup.add(orderLIFO);
239
240        // row 5, drop panel
241        dropPanel.setLayout(new GridBagLayout());
242        dropPanel.setBorder(BorderFactory.createTitledBorder(Bundle.getMessage("TrainsOrRoutesDrops")));
243
244        // row 6, pickup panel
245        pickupPanel.setLayout(new GridBagLayout());
246        pickupPanel.setBorder(BorderFactory.createTitledBorder(Bundle.getMessage("TrainsOrRoutesPickups")));
247
248        // row 9
249        JPanel panelComment = new JPanel();
250        panelComment.setLayout(new GridBagLayout());
251        panelComment.setBorder(BorderFactory.createTitledBorder(Bundle.getMessage("Comment")));
252        addItem(panelComment, commentScroller, 0, 0);
253
254        // adjust text area width based on window size
255        adjustTextAreaColumnWidth(commentScroller, commentTextArea);
256
257        // row 10, reader row
258        JPanel readerPanel = new JPanel();
259        if (Setup.isRfidEnabled()) {
260            readerPanel.setLayout(new GridBagLayout());
261            readerPanel.setBorder(BorderFactory.createTitledBorder(Bundle.getMessage("idReporter")));
262            ReporterManager reporterManager = InstanceManager.getDefault(ReporterManager.class);
263            readerSelector = new NamedBeanComboBox<>(reporterManager);
264            readerSelector.setAllowNull(true);
265            addItem(readerPanel, readerSelector, 0, 0);
266        } else {
267            readerPanel.setVisible(false);
268        }
269
270        // row 11
271        JPanel panelButtons = new JPanel();
272        panelButtons.setLayout(new GridBagLayout());
273
274        addItem(panelButtons, deleteTrackButton, 0, 0);
275        addItem(panelButtons, addTrackButton, 1, 0);
276        addItem(panelButtons, saveTrackButton, 2, 0);
277
278        panels.add(p1Pane);
279        panels.add(paneCheckBoxes);
280        panels.add(panelRoadAndLoadStatus);
281        panels.add(panelOrder);
282        panels.add(dropPanel);
283        panels.add(pickupPanel);
284
285        // add optional panels
286        panels.add(panelOpt3);
287        panels.add(panelOpt4);
288
289        panels.add(panelComment);
290        panels.add(readerPanel);
291        panels.add(panelButtons);
292
293        getContentPane().add(pane);
294
295        // setup buttons
296        addButtonAction(setButton);
297        addButtonAction(clearButton);
298
299        addButtonAction(deleteTrackButton);
300        addButtonAction(addTrackButton);
301        addButtonAction(saveTrackButton);
302
303        addButtonAction(deleteDropButton);
304        addButtonAction(addDropButton);
305        addButtonAction(deletePickupButton);
306        addButtonAction(addPickupButton);
307
308        addRadioButtonAction(orderNormal);
309        addRadioButtonAction(orderFIFO);
310        addRadioButtonAction(orderLIFO);
311
312        addRadioButtonAction(anyDrops);
313        addRadioButtonAction(trainDrop);
314        addRadioButtonAction(routeDrop);
315        addRadioButtonAction(excludeTrainDrop);
316        addRadioButtonAction(excludeRouteDrop);
317
318        addRadioButtonAction(anyPickups);
319        addRadioButtonAction(trainPickup);
320        addRadioButtonAction(routePickup);
321        addRadioButtonAction(excludeTrainPickup);
322        addRadioButtonAction(excludeRoutePickup);
323
324        // addComboBoxAction(comboBoxTypes);
325        addCheckBoxAction(autoDropCheckBox);
326        addCheckBoxAction(autoPickupCheckBox);
327
328        autoDropCheckBox.setSelected(true);
329        autoPickupCheckBox.setSelected(true);
330
331        // load fields and enable buttons
332        if (_track != null) {
333            _track.addPropertyChangeListener(this);
334            trackNameTextField.setText(_track.getName());
335            commentTextArea.setText(_track.getComment());
336            trackLengthTextField.setText(Integer.toString(_track.getLength()));
337            enableButtons(true);
338            if (Setup.isRfidEnabled()) {
339                readerSelector.setSelectedItem(_track.getReporter());
340            }
341        } else {
342            enableButtons(false);
343        }
344
345        // build menu
346        JMenuBar menuBar = new JMenuBar();
347        _toolMenu.add(new TrackCopyAction(_track, _location));
348        _toolMenu.add(new TrackLoadEditAction(this));
349        _toolMenu.add(new TrackRoadEditAction(this));
350        _toolMenu.add(new PoolTrackAction(this));
351        _toolMenu.add(new IgnoreUsedTrackAction(this));
352        // spurs, interchanges, yards, and staging insert menu items here
353        _toolMenu.add(new TrackEditCommentsAction(this));
354        _toolMenu.addSeparator();
355        _toolMenu.add(new ShowCarsByLocationAction(false, _location, _track));
356        _toolMenu.add(new ShowTrainsServingLocationAction(_location, _track));
357
358        menuBar.add(_toolMenu);
359        setJMenuBar(menuBar);
360
361        // load
362        updateCheckboxes();
363        updateTrainDir();
364        updateCarOrder();
365        updateDropOptions();
366        updatePickupOptions();
367        updateRoadOption();
368        updateLoadOption();
369        updateDestinationOption();
370        updateTrainComboBox();
371        updateRouteComboBox();
372
373        setMinimumSize(new Dimension(Control.panelWidth500, Control.panelHeight600));
374    }
375
376    // Save, Delete, Add
377    @Override
378    public void buttonActionPerformed(java.awt.event.ActionEvent ae) {
379        if (ae.getSource() == addTrackButton) {
380            addNewTrack();
381        }
382        if (_track == null) {
383            return; // not possible
384        }
385        if (ae.getSource() == saveTrackButton) {
386            if (!checkUserInputs(_track)) {
387                return;
388            }
389            saveTrack(_track);
390            checkTrackPickups(_track); // warn user if there are car types that
391                                       // will be stranded
392            if (Setup.isCloseWindowOnSaveEnabled()) {
393                dispose();
394            }
395        }
396        if (ae.getSource() == deleteTrackButton) {
397            deleteTrack();
398        }
399        if (ae.getSource() == setButton) {
400            selectCheckboxes(true);
401        }
402        if (ae.getSource() == clearButton) {
403            selectCheckboxes(false);
404        }
405        if (ae.getSource() == addDropButton) {
406            addDropId();
407        }
408        if (ae.getSource() == deleteDropButton) {
409            deleteDropId();
410        }
411        if (ae.getSource() == addPickupButton) {
412            addPickupId();
413        }
414        if (ae.getSource() == deletePickupButton) {
415            deletePickupId();
416        }
417    }
418
419    private void addDropId() {
420        String id = "";
421        if (trainDrop.isSelected() || excludeTrainDrop.isSelected()) {
422            if (comboBoxDropTrains.getSelectedItem() == null) {
423                return;
424            }
425            Train train = ((Train) comboBoxDropTrains.getSelectedItem());
426            Route route = train.getRoute();
427            id = train.getId();
428            if (!checkRoute(route)) {
429                JmriJOptionPane.showMessageDialog(this,
430                        Bundle.getMessage("TrackNotByTrain", train.getName()),
431                        Bundle.getMessage("ErrorTitle"), JmriJOptionPane.ERROR_MESSAGE);
432                return;
433            }
434            selectNextItemComboBox(comboBoxDropTrains);
435        } else {
436            if (comboBoxDropRoutes.getSelectedItem() == null) {
437                return;
438            }
439            Route route = ((Route) comboBoxDropRoutes.getSelectedItem());
440            id = route.getId();
441            if (!checkRoute(route)) {
442                JmriJOptionPane.showMessageDialog(this,
443                        Bundle.getMessage("TrackNotByRoute", route.getName()),
444                        Bundle.getMessage("ErrorTitle"), JmriJOptionPane.ERROR_MESSAGE);
445                return;
446            }
447            selectNextItemComboBox(comboBoxDropRoutes);
448        }
449        _track.addDropId(id);
450    }
451
452    private void deleteDropId() {
453        String id = "";
454        if (trainDrop.isSelected() || excludeTrainDrop.isSelected()) {
455            if (comboBoxDropTrains.getSelectedItem() == null) {
456                return;
457            }
458            id = ((Train) comboBoxDropTrains.getSelectedItem()).getId();
459            selectNextItemComboBox(comboBoxDropTrains);
460        } else {
461            if (comboBoxDropRoutes.getSelectedItem() == null) {
462                return;
463            }
464            id = ((Route) comboBoxDropRoutes.getSelectedItem()).getId();
465            selectNextItemComboBox(comboBoxDropRoutes);
466        }
467        _track.deleteDropId(id);
468    }
469
470    private void addPickupId() {
471        String id = "";
472        if (trainPickup.isSelected() || excludeTrainPickup.isSelected()) {
473            if (comboBoxPickupTrains.getSelectedItem() == null) {
474                return;
475            }
476            Train train = ((Train) comboBoxPickupTrains.getSelectedItem());
477            Route route = train.getRoute();
478            id = train.getId();
479            if (!checkRoute(route)) {
480                JmriJOptionPane.showMessageDialog(this,
481                        Bundle.getMessage("TrackNotByTrain", train.getName()),
482                        Bundle.getMessage("ErrorTitle"), JmriJOptionPane.ERROR_MESSAGE);
483                return;
484            }
485            selectNextItemComboBox(comboBoxPickupTrains);
486        } else {
487            if (comboBoxPickupRoutes.getSelectedItem() == null) {
488                return;
489            }
490            Route route = ((Route) comboBoxPickupRoutes.getSelectedItem());
491            id = route.getId();
492            if (!checkRoute(route)) {
493                JmriJOptionPane.showMessageDialog(this,
494                        Bundle.getMessage("TrackNotByRoute", route.getName()),
495                        Bundle.getMessage("ErrorTitle"), JmriJOptionPane.ERROR_MESSAGE);
496                return;
497            }
498            selectNextItemComboBox(comboBoxPickupRoutes);
499        }
500        _track.addPickupId(id);
501    }
502
503    private void deletePickupId() {
504        String id = "";
505        if (trainPickup.isSelected() || excludeTrainPickup.isSelected()) {
506            if (comboBoxPickupTrains.getSelectedItem() == null) {
507                return;
508            }
509            id = ((Train) comboBoxPickupTrains.getSelectedItem()).getId();
510            selectNextItemComboBox(comboBoxPickupTrains);
511        } else {
512            if (comboBoxPickupRoutes.getSelectedItem() == null) {
513                return;
514            }
515            id = ((Route) comboBoxPickupRoutes.getSelectedItem()).getId();
516            selectNextItemComboBox(comboBoxPickupRoutes);
517        }
518        _track.deletePickupId(id);
519    }
520
521    protected void addNewTrack() {
522        // check that track name is valid
523        if (!checkName(Bundle.getMessage("add"))) {
524            return;
525        }
526        // check to see if track already exists
527        Track check = _location.getTrackByName(trackNameTextField.getText(), null);
528        if (check != null) {
529            reportTrackExists(Bundle.getMessage("add"));
530            return;
531        }
532        // add track to this location
533        _track = _location.addTrack(trackNameTextField.getText(), _type);
534        // check track length
535        checkLength(_track);
536
537        // save window size so it doesn't change during the following updates
538        setPreferredSize(getSize());
539
540        // reset all of the track's attributes
541        updateTrainDir();
542        updateCheckboxes();
543        updateDropOptions();
544        updatePickupOptions();
545        updateRoadOption();
546        updateLoadOption();
547        updateDestinationOption();
548
549        _track.addPropertyChangeListener(this);
550
551        // setup check boxes
552        selectCheckboxes(true);
553        // store comment
554        _track.setComment(commentTextArea.getText());
555        // enable
556        enableButtons(true);
557        // save location file
558        OperationsXml.save();
559    }
560
561    protected void deleteTrack() {
562        if (_track != null) {
563            int rs = _track.getNumberRS();
564            if (rs > 0) {
565                if (JmriJOptionPane.showConfirmDialog(this,
566                        Bundle.getMessage("ThereAreCars", Integer.toString(rs)),
567                        Bundle.getMessage("deleteTrack?"),
568                        JmriJOptionPane.YES_NO_OPTION) != JmriJOptionPane.YES_OPTION) {
569                    return;
570                }
571            }
572            selectCheckboxes(false);
573            _location.deleteTrack(_track);
574            _track = null;
575            enableButtons(false);
576            // save location file
577            OperationsXml.save();
578        }
579    }
580
581    // check to see if the route services this location
582    private boolean checkRoute(Route route) {
583        if (route == null) {
584            return false;
585        }
586        return route.getLastLocationByName(_location.getName()) != null;
587    }
588
589    protected void saveTrack(Track track) {
590        saveTrackDirections(track);
591        track.setName(trackNameTextField.getText());
592        track.setComment(commentTextArea.getText());
593
594        if (Setup.isRfidEnabled()) {
595            _track.setReporter(readerSelector.getSelectedItem());
596        }
597
598        // save current window size so it doesn't change during updates
599        setPreferredSize(getSize());
600
601        // enable
602        enableButtons(true);
603        // save location file
604        OperationsXml.save();
605    }
606
607    private void saveTrackDirections(Track track) {
608        // save train directions serviced by this location
609        int direction = 0;
610        if (northCheckBox.isSelected()) {
611            direction += Track.NORTH;
612        }
613        if (southCheckBox.isSelected()) {
614            direction += Track.SOUTH;
615        }
616        if (eastCheckBox.isSelected()) {
617            direction += Track.EAST;
618        }
619        if (westCheckBox.isSelected()) {
620            direction += Track.WEST;
621        }
622        track.setTrainDirections(direction);
623    }
624
625    private boolean checkUserInputs(Track track) {
626        // check that track name is valid
627        if (!checkName(Bundle.getMessage("save"))) {
628            return false;
629        }
630        // check to see if track already exists
631        Track check = _location.getTrackByName(trackNameTextField.getText(), null);
632        if (check != null && check != track) {
633            reportTrackExists(Bundle.getMessage("save"));
634            return false;
635        }
636        // check track length
637        if (!checkLength(track)) {
638            return false;
639        }
640        // check trains and route option
641        if (!checkService(track)) {
642            return false;
643        }
644
645        return true;
646    }
647
648    /**
649     * @return true if name is less than 26 characters
650     */
651    private boolean checkName(String s) {
652        String trackName = trackNameTextField.getText().trim();
653        if (trackName.isEmpty()) {
654            log.debug("Must enter a track name");
655            JmriJOptionPane.showMessageDialog(this, Bundle.getMessage("MustEnterName"),
656                    Bundle.getMessage("CanNotTrack", s),
657                    JmriJOptionPane.ERROR_MESSAGE);
658            return false;
659        }
660        String[] check = trackName.split(TrainCommon.HYPHEN);
661        if (check.length == 0) {
662            JmriJOptionPane.showMessageDialog(this, Bundle.getMessage("HyphenFeature"),
663                    Bundle.getMessage("CanNotTrack", s),
664                    JmriJOptionPane.ERROR_MESSAGE);
665
666            return false;
667        }
668        if (TrainCommon.splitString(trackName).length() > MAX_NAME_LENGTH) {
669            JmriJOptionPane.showMessageDialog(this,
670                    Bundle.getMessage("TrackNameLengthMax", Integer.toString(MAX_NAME_LENGTH + 1)),
671                    Bundle.getMessage("CanNotTrack", s),
672                    JmriJOptionPane.ERROR_MESSAGE);
673            return false;
674        }
675        return true;
676    }
677
678    private boolean checkLength(Track track) {
679        // convert track length if in inches
680        String length = trackLengthTextField.getText();
681        if (length.endsWith("\"")) { // NOI18N
682            length = length.substring(0, length.length() - 1);
683            try {
684                double inches = Double.parseDouble(length);
685                int feet = (int) (inches * Setup.getScaleRatio() / 12);
686                length = Integer.toString(feet);
687            } catch (NumberFormatException e) {
688                JmriJOptionPane.showMessageDialog(this, Bundle.getMessage("CanNotConvertFeet"),
689                        Bundle.getMessage("ErrorTrackLength"), JmriJOptionPane.ERROR_MESSAGE);
690                return false;
691            }
692        }
693        if (length.endsWith("cm")) { // NOI18N
694            length = length.substring(0, length.length() - 2);
695            try {
696                double cm = Double.parseDouble(length);
697                int meter = (int) (cm * Setup.getScaleRatio() / 100);
698                length = Integer.toString(meter);
699            } catch (NumberFormatException e) {
700                // log.error("Can not convert from cm to meters");
701                JmriJOptionPane.showMessageDialog(this, Bundle.getMessage("CanNotConvertMeter"),
702                        Bundle.getMessage("ErrorTrackLength"), JmriJOptionPane.ERROR_MESSAGE);
703                return false;
704            }
705        }
706        // confirm that length is a number and less than 10000 feet
707        int trackLength = 0;
708        try {
709            trackLength = Integer.parseInt(length);
710            if (length.length() > Control.max_len_string_track_length_name) {
711                JmriJOptionPane.showMessageDialog(this,
712                        Bundle.getMessage("TrackMustBeLessThan",
713                                Math.pow(10, Control.max_len_string_track_length_name),
714                                Setup.getLengthUnit().toLowerCase()),
715                        Bundle.getMessage("ErrorTrackLength"), JmriJOptionPane.ERROR_MESSAGE);
716                return false;
717            }
718        } catch (NumberFormatException e) {
719            // log.error("Track length not an integer");
720            JmriJOptionPane.showMessageDialog(this, Bundle.getMessage("TrackMustBeNumber"),
721                    Bundle.getMessage("ErrorTrackLength"), JmriJOptionPane.ERROR_MESSAGE);
722            return false;
723        }
724        // track length can not be less than than the sum of used and reserved
725        // length
726        if (trackLength != track.getLength() && trackLength < track.getUsedLength() + track.getReserved()) {
727            // log.warn("Track length should not be less than used and
728            // reserved");
729            JmriJOptionPane.showMessageDialog(this, Bundle.getMessage("TrackMustBeGreater"),
730                    Bundle.getMessage("ErrorTrackLength"), JmriJOptionPane.ERROR_MESSAGE);
731            // does the user want to force the track length?
732            if (JmriJOptionPane.showConfirmDialog(this,
733                    Bundle.getMessage("TrackForceLength", track.getLength(), trackLength,
734                            Setup.getLengthUnit().toLowerCase()),
735                    Bundle.getMessage("ErrorTrackLength"),
736                    JmriJOptionPane.YES_NO_OPTION) != JmriJOptionPane.YES_OPTION) {
737                return false;
738            }
739        }
740        // if everything is okay, save length
741        track.setLength(trackLength);
742        return true;
743    }
744
745    private boolean checkService(Track track) {
746        // check train and route restrictions
747        if ((trainDrop.isSelected() || routeDrop.isSelected()) && track.getDropIds().length == 0) {
748            log.debug("Must enter trains or routes for this track");
749            JmriJOptionPane.showMessageDialog(this, Bundle.getMessage("UseAddTrainsOrRoutes"),
750                    Bundle.getMessage("SetOutDisabled"), JmriJOptionPane.ERROR_MESSAGE);
751            return false;
752        }
753        if ((trainPickup.isSelected() || routePickup.isSelected()) && track.getPickupIds().length == 0) {
754            log.debug("Must enter trains or routes for this track");
755            JmriJOptionPane.showMessageDialog(this, Bundle.getMessage("UseAddTrainsOrRoutes"),
756                    Bundle.getMessage("PickUpsDisabled"), JmriJOptionPane.ERROR_MESSAGE);
757            return false;
758        }
759        return true;
760    }
761
762    private boolean checkTrackPickups(Track track) {
763        // check to see if all car types can be pulled from this track
764        String status = track.checkPickups();
765        if (!status.equals(Track.PICKUP_OKAY) && !track.getPickupOption().equals(Track.ANY)) {
766            JmriJOptionPane.showMessageDialog(this, status, Bundle.getMessage("ErrorStrandedCar"),
767                    JmriJOptionPane.ERROR_MESSAGE);
768            return false;
769        }
770        return true;
771    }
772
773    private void reportTrackExists(String s) {
774        JmriJOptionPane.showMessageDialog(this, Bundle.getMessage("TrackAlreadyExists"),
775                Bundle.getMessage("CanNotTrack", s), JmriJOptionPane.ERROR_MESSAGE);
776    }
777
778    protected void enableButtons(boolean enabled) {
779        _toolMenu.setEnabled(enabled);
780        northCheckBox.setEnabled(enabled);
781        southCheckBox.setEnabled(enabled);
782        eastCheckBox.setEnabled(enabled);
783        westCheckBox.setEnabled(enabled);
784        clearButton.setEnabled(enabled);
785        setButton.setEnabled(enabled);
786        deleteTrackButton.setEnabled(enabled);
787        saveTrackButton.setEnabled(enabled);
788        roadOptionButton.setEnabled(enabled);
789        loadOptionButton.setEnabled(enabled);
790        shipLoadOptionButton.setEnabled(enabled);
791        destinationOptionButton.setEnabled(enabled);
792        anyDrops.setEnabled(enabled);
793        trainDrop.setEnabled(enabled);
794        routeDrop.setEnabled(enabled);
795        excludeTrainDrop.setEnabled(enabled);
796        excludeRouteDrop.setEnabled(enabled);
797        anyPickups.setEnabled(enabled);
798        trainPickup.setEnabled(enabled);
799        routePickup.setEnabled(enabled);
800        excludeTrainPickup.setEnabled(enabled);
801        excludeRoutePickup.setEnabled(enabled);
802        orderNormal.setEnabled(enabled);
803        orderFIFO.setEnabled(enabled);
804        orderLIFO.setEnabled(enabled);
805        enableCheckboxes(enabled);
806        if (readerSelector != null) {
807            // enable readerSelect.
808            readerSelector.setEnabled(enabled && Setup.isRfidEnabled());
809        }
810    }
811
812    @Override
813    public void radioButtonActionPerformed(java.awt.event.ActionEvent ae) {
814        log.debug("radio button activated");
815        if (ae.getSource() == orderNormal) {
816            _track.setServiceOrder(Track.NORMAL);
817        }
818        if (ae.getSource() == orderFIFO) {
819            _track.setServiceOrder(Track.FIFO);
820        }
821        if (ae.getSource() == orderLIFO) {
822            _track.setServiceOrder(Track.LIFO);
823        }
824        if (ae.getSource() == anyDrops) {
825            _track.setDropOption(Track.ANY);
826            updateDropOptions();
827        }
828        if (ae.getSource() == trainDrop) {
829            _track.setDropOption(Track.TRAINS);
830            updateDropOptions();
831        }
832        if (ae.getSource() == routeDrop) {
833            _track.setDropOption(Track.ROUTES);
834            updateDropOptions();
835        }
836        if (ae.getSource() == excludeTrainDrop) {
837            _track.setDropOption(Track.EXCLUDE_TRAINS);
838            updateDropOptions();
839        }
840        if (ae.getSource() == excludeRouteDrop) {
841            _track.setDropOption(Track.EXCLUDE_ROUTES);
842            updateDropOptions();
843        }
844        if (ae.getSource() == anyPickups) {
845            _track.setPickupOption(Track.ANY);
846            updatePickupOptions();
847        }
848        if (ae.getSource() == trainPickup) {
849            _track.setPickupOption(Track.TRAINS);
850            updatePickupOptions();
851        }
852        if (ae.getSource() == routePickup) {
853            _track.setPickupOption(Track.ROUTES);
854            updatePickupOptions();
855        }
856        if (ae.getSource() == excludeTrainPickup) {
857            _track.setPickupOption(Track.EXCLUDE_TRAINS);
858            updatePickupOptions();
859        }
860        if (ae.getSource() == excludeRoutePickup) {
861            _track.setPickupOption(Track.EXCLUDE_ROUTES);
862            updatePickupOptions();
863        }
864    }
865
866    // TODO only update comboBox when train or route list changes.
867    private void updateDropOptions() {
868        dropPanel.removeAll();
869        int numberOfItems = getNumberOfCheckboxesPerLine();
870
871        JPanel p = new JPanel();
872        p.setLayout(new GridBagLayout());
873        p.add(anyDrops);
874        p.add(trainDrop);
875        p.add(routeDrop);
876        p.add(excludeTrainDrop);
877        p.add(excludeRouteDrop);
878        GridBagConstraints gc = new GridBagConstraints();
879        gc.gridwidth = numberOfItems + 1;
880        dropPanel.add(p, gc);
881
882        int y = 1; // vertical position in panel
883
884        if (_track != null) {
885            // set radio button
886            anyDrops.setSelected(_track.getDropOption().equals(Track.ANY));
887            trainDrop.setSelected(_track.getDropOption().equals(Track.TRAINS));
888            routeDrop.setSelected(_track.getDropOption().equals(Track.ROUTES));
889            excludeTrainDrop.setSelected(_track.getDropOption().equals(Track.EXCLUDE_TRAINS));
890            excludeRouteDrop.setSelected(_track.getDropOption().equals(Track.EXCLUDE_ROUTES));
891
892            if (!anyDrops.isSelected()) {
893                p = new JPanel();
894                p.setLayout(new FlowLayout());
895                if (trainDrop.isSelected() || excludeTrainDrop.isSelected()) {
896                    p.add(comboBoxDropTrains);
897                } else {
898                    p.add(comboBoxDropRoutes);
899                }
900                p.add(addDropButton);
901                p.add(deleteDropButton);
902                p.add(autoDropCheckBox);
903                gc.gridy = y++;
904                dropPanel.add(p, gc);
905                y++;
906
907                String[] dropIds = _track.getDropIds();
908                int x = 0;
909                for (String id : dropIds) {
910                    JLabel names = new JLabel();
911                    String name = "<deleted>"; // NOI18N
912                    if (trainDrop.isSelected() || excludeTrainDrop.isSelected()) {
913                        Train train = trainManager.getTrainById(id);
914                        if (train != null) {
915                            name = train.getName();
916                        }
917                    } else {
918                        Route route = routeManager.getRouteById(id);
919                        if (route != null) {
920                            name = route.getName();
921                        }
922                    }
923                    if (name.equals("<deleted>")) // NOI18N
924                    {
925                        _track.deleteDropId(id);
926                    }
927                    names.setText(name);
928                    addItem(dropPanel, names, x++, y);
929                    if (x > numberOfItems) {
930                        y++;
931                        x = 0;
932                    }
933                }
934            }
935        } else {
936            anyDrops.setSelected(true);
937        }
938        dropPanel.revalidate();
939        dropPanel.repaint();
940        revalidate();
941    }
942
943    private void updatePickupOptions() {
944        log.debug("update pick up options");
945        pickupPanel.removeAll();
946        int numberOfCheckboxes = getNumberOfCheckboxesPerLine();
947
948        JPanel p = new JPanel();
949        p.setLayout(new GridBagLayout());
950        p.add(anyPickups);
951        p.add(trainPickup);
952        p.add(routePickup);
953        p.add(excludeTrainPickup);
954        p.add(excludeRoutePickup);
955        GridBagConstraints gc = new GridBagConstraints();
956        gc.gridwidth = numberOfCheckboxes + 1;
957        pickupPanel.add(p, gc);
958
959        int y = 1; // vertical position in panel
960
961        if (_track != null) {
962            // set radio button
963            anyPickups.setSelected(_track.getPickupOption().equals(Track.ANY));
964            trainPickup.setSelected(_track.getPickupOption().equals(Track.TRAINS));
965            routePickup.setSelected(_track.getPickupOption().equals(Track.ROUTES));
966            excludeTrainPickup.setSelected(_track.getPickupOption().equals(Track.EXCLUDE_TRAINS));
967            excludeRoutePickup.setSelected(_track.getPickupOption().equals(Track.EXCLUDE_ROUTES));
968
969            if (!anyPickups.isSelected()) {
970                p = new JPanel();
971                p.setLayout(new FlowLayout());
972                if (trainPickup.isSelected() || excludeTrainPickup.isSelected()) {
973                    p.add(comboBoxPickupTrains);
974                } else {
975                    p.add(comboBoxPickupRoutes);
976                }
977                p.add(addPickupButton);
978                p.add(deletePickupButton);
979                p.add(autoPickupCheckBox);
980                gc.gridy = y++;
981                pickupPanel.add(p, gc);
982                y++;
983
984                int x = 0;
985                for (String id : _track.getPickupIds()) {
986                    JLabel names = new JLabel();
987                    String name = "<deleted>"; // NOI18N
988                    if (trainPickup.isSelected() || excludeTrainPickup.isSelected()) {
989                        Train train = trainManager.getTrainById(id);
990                        if (train != null) {
991                            name = train.getName();
992                        }
993                    } else {
994                        Route route = routeManager.getRouteById(id);
995                        if (route != null) {
996                            name = route.getName();
997                        }
998                    }
999                    if (name.equals("<deleted>")) // NOI18N
1000                    {
1001                        _track.deletePickupId(id);
1002                    }
1003                    names.setText(name);
1004                    addItem(pickupPanel, names, x++, y);
1005                    if (x > numberOfCheckboxes) {
1006                        y++;
1007                        x = 0;
1008                    }
1009                }
1010            }
1011        } else {
1012            anyPickups.setSelected(true);
1013        }
1014        pickupPanel.revalidate();
1015        pickupPanel.repaint();
1016        revalidate();
1017    }
1018
1019    protected void updateTrainComboBox() {
1020        trainManager.updateTrainComboBox(comboBoxPickupTrains);
1021        if (autoPickupCheckBox.isSelected()) {
1022            autoTrainComboBox(comboBoxPickupTrains);
1023        }
1024        trainManager.updateTrainComboBox(comboBoxDropTrains);
1025        if (autoDropCheckBox.isSelected()) {
1026            autoTrainComboBox(comboBoxDropTrains);
1027        }
1028    }
1029
1030    // filter all trains not serviced by this track
1031    private void autoTrainComboBox(JComboBox<Train> box) {
1032        for (int i = 0; i < box.getItemCount(); i++) {
1033            Train train = box.getItemAt(i);
1034            if (train == null || !checkRoute(train.getRoute())) {
1035                box.removeItemAt(i--);
1036            }
1037        }
1038    }
1039
1040    protected void updateRouteComboBox() {
1041        routeManager.updateComboBox(comboBoxPickupRoutes);
1042        if (autoPickupCheckBox.isSelected()) {
1043            autoRouteComboBox(comboBoxPickupRoutes);
1044        }
1045        routeManager.updateComboBox(comboBoxDropRoutes);
1046        if (autoDropCheckBox.isSelected()) {
1047            autoRouteComboBox(comboBoxDropRoutes);
1048        }
1049    }
1050
1051    // filter out all routes not serviced by this track
1052    private void autoRouteComboBox(JComboBox<Route> box) {
1053        for (int i = 0; i < box.getItemCount(); i++) {
1054            Route route = box.getItemAt(i);
1055            if (!checkRoute(route)) {
1056                box.removeItemAt(i--);
1057            }
1058        }
1059    }
1060
1061    private void enableCheckboxes(boolean enable) {
1062        for (int i = 0; i < checkBoxes.size(); i++) {
1063            checkBoxes.get(i).setEnabled(enable);
1064        }
1065    }
1066
1067    private void selectCheckboxes(boolean enable) {
1068        for (int i = 0; i < checkBoxes.size(); i++) {
1069            JCheckBox checkBox = checkBoxes.get(i);
1070            checkBox.setSelected(enable);
1071            if (_track != null) {
1072                if (enable) {
1073                    _track.addTypeName(checkBox.getText());
1074                } else {
1075                    _track.deleteTypeName(checkBox.getText());
1076                }
1077            }
1078        }
1079    }
1080    
1081    // car and loco types
1082    private void updateCheckboxes() {
1083        // log.debug("Update all checkboxes");
1084        checkBoxes.clear();
1085        panelCheckBoxes.removeAll();
1086        numberOfCheckBoxes = getNumberOfCheckboxesPerLine();
1087        x = 0;
1088        y = 0; // vertical position in panel
1089        loadTypes(InstanceManager.getDefault(CarTypes.class).getNames());
1090
1091        // add space between car and loco types
1092        checkNewLine();
1093
1094        loadTypes(InstanceManager.getDefault(EngineTypes.class).getNames());
1095        enableCheckboxes(_track != null);
1096
1097        JPanel p = new JPanel();
1098        p.add(clearButton);
1099        p.add(setButton);
1100        if (_track != null && _track.isSpur()) {
1101            p.add(autoSelectButton);
1102        }
1103        GridBagConstraints gc = new GridBagConstraints();
1104        gc.gridwidth = getNumberOfCheckboxesPerLine() + 1;
1105        gc.gridy = ++y;
1106        panelCheckBoxes.add(p, gc);
1107
1108        panelCheckBoxes.revalidate();
1109        panelCheckBoxes.repaint();
1110    }
1111
1112    int x = 0;
1113    int y = 0; // vertical position in panel
1114
1115    private void loadTypes(String[] types) {
1116        for (String type : types) {
1117            if (_location.acceptsTypeName(type)) {
1118                JCheckBox checkBox = new JCheckBox();
1119                checkBoxes.add(checkBox);
1120                checkBox.setText(type);
1121                addCheckBoxAction(checkBox);
1122                addItemLeft(panelCheckBoxes, checkBox, x, y);
1123                if (_track != null && _track.isTypeNameAccepted(type)) {
1124                    checkBox.setSelected(true);
1125                }
1126                checkNewLine();
1127            }
1128        }
1129    }
1130
1131    int numberOfCheckBoxes;
1132
1133    private void checkNewLine() {
1134        if (++x > numberOfCheckBoxes) {
1135            y++;
1136            x = 0;
1137        }
1138    }
1139
1140    private void updateRoadOption() {
1141        if (_track != null) {
1142            roadOptionButton.setText(_track.getRoadOptionString());
1143        }
1144    }
1145
1146    private void updateLoadOption() {
1147        if (_track != null) {
1148            loadOptionButton.setText(_track.getLoadOptionString());
1149            shipLoadOptionButton.setText(_track.getShipLoadOptionString());
1150        }
1151    }
1152
1153    private void updateTrainDir() {
1154        northCheckBox.setVisible(((Setup.getTrainDirection() & Setup.NORTH) &
1155                (_location.getTrainDirections() & Location.NORTH)) == Location.NORTH);
1156        southCheckBox.setVisible(((Setup.getTrainDirection() & Setup.SOUTH) &
1157                (_location.getTrainDirections() & Location.SOUTH)) == Location.SOUTH);
1158        eastCheckBox.setVisible(((Setup.getTrainDirection() & Setup.EAST) &
1159                (_location.getTrainDirections() & Location.EAST)) == Location.EAST);
1160        westCheckBox.setVisible(((Setup.getTrainDirection() & Setup.WEST) &
1161                (_location.getTrainDirections() & Location.WEST)) == Location.WEST);
1162
1163        if (_track != null) {
1164            northCheckBox.setSelected((_track.getTrainDirections() & Track.NORTH) == Track.NORTH);
1165            southCheckBox.setSelected((_track.getTrainDirections() & Track.SOUTH) == Track.SOUTH);
1166            eastCheckBox.setSelected((_track.getTrainDirections() & Track.EAST) == Track.EAST);
1167            westCheckBox.setSelected((_track.getTrainDirections() & Track.WEST) == Track.WEST);
1168        }
1169        panelTrainDir.revalidate();
1170        revalidate();
1171    }
1172
1173    @Override
1174    public void checkBoxActionPerformed(java.awt.event.ActionEvent ae) {
1175        if (ae.getSource() == autoDropCheckBox || ae.getSource() == autoPickupCheckBox) {
1176            updateTrainComboBox();
1177            updateRouteComboBox();
1178            return;
1179        }
1180        JCheckBox b = (JCheckBox) ae.getSource();
1181        log.debug("checkbox change {}", b.getText());
1182        if (b.isSelected()) {
1183            _track.addTypeName(b.getText());
1184        } else {
1185            _track.deleteTypeName(b.getText());
1186        }
1187    }
1188
1189    // set the service order
1190    private void updateCarOrder() {
1191        if (_track != null) {
1192            orderNormal.setSelected(_track.getServiceOrder().equals(Track.NORMAL));
1193            orderFIFO.setSelected(_track.getServiceOrder().equals(Track.FIFO));
1194            orderLIFO.setSelected(_track.getServiceOrder().equals(Track.LIFO));
1195        }
1196    }
1197
1198    protected void updateDestinationOption() {
1199        if (_track != null) {
1200            if (_track.getDestinationOption().equals(Track.INCLUDE_DESTINATIONS)) {
1201                pDestinationOption.setVisible(true);
1202                destinationOptionButton.setText(Bundle.getMessage("AcceptOnly") +
1203                        " " +
1204                        _track.getDestinationListSize() +
1205                        " " +
1206                        Bundle.getMessage("Destinations"));
1207            } else if (_track.getDestinationOption().equals(Track.EXCLUDE_DESTINATIONS)) {
1208                pDestinationOption.setVisible(true);
1209                destinationOptionButton.setText(Bundle.getMessage("Exclude") +
1210                        " " +
1211                        (InstanceManager.getDefault(LocationManager.class).getNumberOfLocations() -
1212                                _track.getDestinationListSize()) +
1213                        " " +
1214                        Bundle.getMessage("Destinations"));
1215            } else {
1216                destinationOptionButton.setText(Bundle.getMessage("AcceptAll"));
1217            }
1218        }
1219    }
1220
1221    @Override
1222    public void dispose() {
1223        if (_track != null) {
1224            _track.removePropertyChangeListener(this);
1225        }
1226        if (_location != null) {
1227            _location.removePropertyChangeListener(this);
1228        }
1229        InstanceManager.getDefault(CarRoads.class).removePropertyChangeListener(this);
1230        InstanceManager.getDefault(CarLoads.class).removePropertyChangeListener(this);
1231        InstanceManager.getDefault(CarTypes.class).removePropertyChangeListener(this);
1232        trainManager.removePropertyChangeListener(this);
1233        routeManager.removePropertyChangeListener(this);
1234        super.dispose();
1235    }
1236
1237    @Override
1238    public void propertyChange(java.beans.PropertyChangeEvent e) {
1239        if (Control.SHOW_PROPERTY) {
1240            log.debug("Property change: ({}) old: ({}) new: ({})", e.getPropertyName(), e.getOldValue(),
1241                    e.getNewValue());
1242        }
1243        if (e.getPropertyName().equals(Location.TYPES_CHANGED_PROPERTY) ||
1244                e.getPropertyName().equals(CarTypes.CARTYPES_CHANGED_PROPERTY) ||
1245                e.getPropertyName().equals(Track.TYPES_CHANGED_PROPERTY)) {
1246            updateCheckboxes();
1247        }
1248        if (e.getPropertyName().equals(Location.TRAIN_DIRECTION_CHANGED_PROPERTY) ||
1249                e.getPropertyName().equals(Track.TRAIN_DIRECTION_CHANGED_PROPERTY) ||
1250                e.getPropertyName().equals(Setup.TRAIN_DIRECTION_PROPERTY_CHANGE)) {
1251            updateTrainDir();
1252        }
1253        if (e.getPropertyName().equals(TrainManager.LISTLENGTH_CHANGED_PROPERTY)) {
1254            updateTrainComboBox();
1255            updateDropOptions();
1256            updatePickupOptions();
1257        }
1258        if (e.getPropertyName().equals(RouteManager.LISTLENGTH_CHANGED_PROPERTY)) {
1259            updateRouteComboBox();
1260            updateDropOptions();
1261            updatePickupOptions();
1262        }
1263        if (e.getPropertyName().equals(Track.ROADS_CHANGED_PROPERTY)) {
1264            updateRoadOption();
1265        }
1266        if (e.getPropertyName().equals(Track.LOADS_CHANGED_PROPERTY)) {
1267            updateLoadOption();
1268        }
1269        if (e.getPropertyName().equals(Track.DROP_CHANGED_PROPERTY)) {
1270            updateDropOptions();
1271        }
1272        if (e.getPropertyName().equals(Track.PICKUP_CHANGED_PROPERTY)) {
1273            updatePickupOptions();
1274        }
1275        if (e.getPropertyName().equals(Track.SERVICE_ORDER_CHANGED_PROPERTY)) {
1276            updateCarOrder();
1277        }
1278        if (e.getPropertyName().equals(Track.DESTINATIONS_CHANGED_PROPERTY) ||
1279                e.getPropertyName().equals(Track.DESTINATION_OPTIONS_CHANGED_PROPERTY)) {
1280            updateDestinationOption();
1281        }
1282        if (e.getPropertyName().equals(Track.LENGTH_CHANGED_PROPERTY)) {
1283            trackLengthTextField.setText(Integer.toString(_track.getLength()));
1284        }
1285    }
1286
1287    private static final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(TrackEditFrame.class);
1288}