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 = 6;
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        // spurs, interchanges, and staging insert menu items here
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        _toolMenu.add(new TrackEditCommentsAction(this));
353        _toolMenu.addSeparator();
354        // spurs, interchanges, and yards insert menu items here
355        _toolMenu.add(new TrackCopyAction(_track, _location));
356        _toolMenu.addSeparator();
357        _toolMenu.add(new ShowCarsByLocationAction(false, _location, _track));
358        _toolMenu.add(new ShowTrainsServingLocationAction(_location, _track));
359
360        menuBar.add(_toolMenu);
361        setJMenuBar(menuBar);
362
363        // load
364        updateCheckboxes();
365        updateTrainDir();
366        updateCarOrder();
367        updateDropOptions();
368        updatePickupOptions();
369        updateRoadOption();
370        updateLoadOption();
371        updateDestinationOption();
372        updateTrainComboBox();
373        updateRouteComboBox();
374
375        setMinimumSize(new Dimension(Control.panelWidth500, Control.panelHeight600));
376    }
377
378    // Save, Delete, Add
379    @Override
380    public void buttonActionPerformed(java.awt.event.ActionEvent ae) {
381        if (ae.getSource() == addTrackButton) {
382            addNewTrack();
383        }
384        if (_track == null) {
385            return; // not possible
386        }
387        if (ae.getSource() == saveTrackButton) {
388            if (!checkUserInputs(_track)) {
389                return;
390            }
391            saveTrack(_track);
392            checkTrackPickups(_track); // warn user if there are car types that
393                                       // will be stranded
394            if (Setup.isCloseWindowOnSaveEnabled()) {
395                dispose();
396            }
397        }
398        if (ae.getSource() == deleteTrackButton) {
399            deleteTrack();
400        }
401        if (ae.getSource() == setButton) {
402            selectCheckboxes(true);
403        }
404        if (ae.getSource() == clearButton) {
405            selectCheckboxes(false);
406        }
407        if (ae.getSource() == addDropButton) {
408            addDropId();
409        }
410        if (ae.getSource() == deleteDropButton) {
411            deleteDropId();
412        }
413        if (ae.getSource() == addPickupButton) {
414            addPickupId();
415        }
416        if (ae.getSource() == deletePickupButton) {
417            deletePickupId();
418        }
419    }
420
421    private void addDropId() {
422        String id = "";
423        if (trainDrop.isSelected() || excludeTrainDrop.isSelected()) {
424            if (comboBoxDropTrains.getSelectedItem() == null) {
425                return;
426            }
427            Train train = ((Train) comboBoxDropTrains.getSelectedItem());
428            Route route = train.getRoute();
429            id = train.getId();
430            if (!checkRoute(route)) {
431                JmriJOptionPane.showMessageDialog(this,
432                        Bundle.getMessage("TrackNotByTrain", train.getName()),
433                        Bundle.getMessage("ErrorTitle"), JmriJOptionPane.ERROR_MESSAGE);
434                return;
435            }
436            selectNextItemComboBox(comboBoxDropTrains);
437        } else {
438            if (comboBoxDropRoutes.getSelectedItem() == null) {
439                return;
440            }
441            Route route = ((Route) comboBoxDropRoutes.getSelectedItem());
442            id = route.getId();
443            if (!checkRoute(route)) {
444                JmriJOptionPane.showMessageDialog(this,
445                        Bundle.getMessage("TrackNotByRoute", route.getName()),
446                        Bundle.getMessage("ErrorTitle"), JmriJOptionPane.ERROR_MESSAGE);
447                return;
448            }
449            selectNextItemComboBox(comboBoxDropRoutes);
450        }
451        _track.addDropId(id);
452    }
453
454    private void deleteDropId() {
455        String id = "";
456        if (trainDrop.isSelected() || excludeTrainDrop.isSelected()) {
457            if (comboBoxDropTrains.getSelectedItem() == null) {
458                return;
459            }
460            id = ((Train) comboBoxDropTrains.getSelectedItem()).getId();
461            selectNextItemComboBox(comboBoxDropTrains);
462        } else {
463            if (comboBoxDropRoutes.getSelectedItem() == null) {
464                return;
465            }
466            id = ((Route) comboBoxDropRoutes.getSelectedItem()).getId();
467            selectNextItemComboBox(comboBoxDropRoutes);
468        }
469        _track.deleteDropId(id);
470    }
471
472    private void addPickupId() {
473        String id = "";
474        if (trainPickup.isSelected() || excludeTrainPickup.isSelected()) {
475            if (comboBoxPickupTrains.getSelectedItem() == null) {
476                return;
477            }
478            Train train = ((Train) comboBoxPickupTrains.getSelectedItem());
479            Route route = train.getRoute();
480            id = train.getId();
481            if (!checkRoute(route)) {
482                JmriJOptionPane.showMessageDialog(this,
483                        Bundle.getMessage("TrackNotByTrain", train.getName()),
484                        Bundle.getMessage("ErrorTitle"), JmriJOptionPane.ERROR_MESSAGE);
485                return;
486            }
487            selectNextItemComboBox(comboBoxPickupTrains);
488        } else {
489            if (comboBoxPickupRoutes.getSelectedItem() == null) {
490                return;
491            }
492            Route route = ((Route) comboBoxPickupRoutes.getSelectedItem());
493            id = route.getId();
494            if (!checkRoute(route)) {
495                JmriJOptionPane.showMessageDialog(this,
496                        Bundle.getMessage("TrackNotByRoute", route.getName()),
497                        Bundle.getMessage("ErrorTitle"), JmriJOptionPane.ERROR_MESSAGE);
498                return;
499            }
500            selectNextItemComboBox(comboBoxPickupRoutes);
501        }
502        _track.addPickupId(id);
503    }
504
505    private void deletePickupId() {
506        String id = "";
507        if (trainPickup.isSelected() || excludeTrainPickup.isSelected()) {
508            if (comboBoxPickupTrains.getSelectedItem() == null) {
509                return;
510            }
511            id = ((Train) comboBoxPickupTrains.getSelectedItem()).getId();
512            selectNextItemComboBox(comboBoxPickupTrains);
513        } else {
514            if (comboBoxPickupRoutes.getSelectedItem() == null) {
515                return;
516            }
517            id = ((Route) comboBoxPickupRoutes.getSelectedItem()).getId();
518            selectNextItemComboBox(comboBoxPickupRoutes);
519        }
520        _track.deletePickupId(id);
521    }
522
523    protected void addNewTrack() {
524        // check that track name is valid
525        if (!checkName(Bundle.getMessage("add"))) {
526            return;
527        }
528        // check to see if track already exists
529        Track check = _location.getTrackByName(trackNameTextField.getText(), null);
530        if (check != null) {
531            reportTrackExists(Bundle.getMessage("add"));
532            return;
533        }
534        // add track to this location
535        _track = _location.addTrack(trackNameTextField.getText(), _type);
536        // check track length
537        checkLength(_track);
538
539        // save window size so it doesn't change during the following updates
540        setPreferredSize(getSize());
541
542        // reset all of the track's attributes
543        updateTrainDir();
544        updateCheckboxes();
545        updateDropOptions();
546        updatePickupOptions();
547        updateRoadOption();
548        updateLoadOption();
549        updateDestinationOption();
550
551        _track.addPropertyChangeListener(this);
552
553        // setup check boxes
554        selectCheckboxes(true);
555        // store comment
556        _track.setComment(commentTextArea.getText());
557        // enable
558        enableButtons(true);
559        // save location file
560        OperationsXml.save();
561    }
562
563    protected void deleteTrack() {
564        if (_track != null) {
565            int rs = _track.getNumberRS();
566            if (rs > 0) {
567                if (JmriJOptionPane.showConfirmDialog(this,
568                        Bundle.getMessage("ThereAreCars", Integer.toString(rs)),
569                        Bundle.getMessage("deleteTrack?"),
570                        JmriJOptionPane.YES_NO_OPTION) != JmriJOptionPane.YES_OPTION) {
571                    return;
572                }
573            }
574            selectCheckboxes(false);
575            _location.deleteTrack(_track);
576            _track = null;
577            enableButtons(false);
578            // save location file
579            OperationsXml.save();
580        }
581    }
582
583    // check to see if the route services this location
584    private boolean checkRoute(Route route) {
585        if (route == null) {
586            return false;
587        }
588        return route.getLastLocationByName(_location.getName()) != null;
589    }
590
591    protected void saveTrack(Track track) {
592        saveTrackDirections(track);
593        track.setName(trackNameTextField.getText());
594        track.setComment(commentTextArea.getText());
595
596        if (Setup.isRfidEnabled()) {
597            _track.setReporter(readerSelector.getSelectedItem());
598        }
599
600        // save current window size so it doesn't change during updates
601        setPreferredSize(getSize());
602
603        // enable
604        enableButtons(true);
605        // save location file
606        OperationsXml.save();
607    }
608
609    private void saveTrackDirections(Track track) {
610        // save train directions serviced by this location
611        int direction = 0;
612        if (northCheckBox.isSelected()) {
613            direction += Track.NORTH;
614        }
615        if (southCheckBox.isSelected()) {
616            direction += Track.SOUTH;
617        }
618        if (eastCheckBox.isSelected()) {
619            direction += Track.EAST;
620        }
621        if (westCheckBox.isSelected()) {
622            direction += Track.WEST;
623        }
624        track.setTrainDirections(direction);
625    }
626
627    private boolean checkUserInputs(Track track) {
628        // check that track name is valid
629        if (!checkName(Bundle.getMessage("save"))) {
630            return false;
631        }
632        // check to see if track already exists
633        Track check = _location.getTrackByName(trackNameTextField.getText(), null);
634        if (check != null && check != track) {
635            reportTrackExists(Bundle.getMessage("save"));
636            return false;
637        }
638        // check track length
639        if (!checkLength(track)) {
640            return false;
641        }
642        // check trains and route option
643        if (!checkService(track)) {
644            return false;
645        }
646
647        return true;
648    }
649
650    /**
651     * @return true if name is less than 26 characters
652     */
653    private boolean checkName(String s) {
654        String trackName = trackNameTextField.getText().trim();
655        if (trackName.isEmpty()) {
656            log.debug("Must enter a track name");
657            JmriJOptionPane.showMessageDialog(this, Bundle.getMessage("MustEnterName"),
658                    Bundle.getMessage("CanNotTrack", s),
659                    JmriJOptionPane.ERROR_MESSAGE);
660            return false;
661        }
662        String[] check = trackName.split(TrainCommon.HYPHEN);
663        if (check.length == 0) {
664            JmriJOptionPane.showMessageDialog(this, Bundle.getMessage("HyphenFeature"),
665                    Bundle.getMessage("CanNotTrack", s),
666                    JmriJOptionPane.ERROR_MESSAGE);
667
668            return false;
669        }
670        if (TrainCommon.splitString(trackName).length() > MAX_NAME_LENGTH) {
671            JmriJOptionPane.showMessageDialog(this,
672                    Bundle.getMessage("TrackNameLengthMax", Integer.toString(MAX_NAME_LENGTH + 1)),
673                    Bundle.getMessage("CanNotTrack", s),
674                    JmriJOptionPane.ERROR_MESSAGE);
675            return false;
676        }
677        return true;
678    }
679
680    private boolean checkLength(Track track) {
681        // convert track length if in inches
682        String length = trackLengthTextField.getText();
683        if (length.endsWith("\"")) { // NOI18N
684            length = length.substring(0, length.length() - 1);
685            try {
686                double inches = Double.parseDouble(length);
687                int feet = (int) (inches * Setup.getScaleRatio() / 12);
688                length = Integer.toString(feet);
689            } catch (NumberFormatException e) {
690                JmriJOptionPane.showMessageDialog(this, Bundle.getMessage("CanNotConvertFeet"),
691                        Bundle.getMessage("ErrorTrackLength"), JmriJOptionPane.ERROR_MESSAGE);
692                return false;
693            }
694        }
695        if (length.endsWith("cm")) { // NOI18N
696            length = length.substring(0, length.length() - 2);
697            try {
698                double cm = Double.parseDouble(length);
699                int meter = (int) (cm * Setup.getScaleRatio() / 100);
700                length = Integer.toString(meter);
701            } catch (NumberFormatException e) {
702                // log.error("Can not convert from cm to meters");
703                JmriJOptionPane.showMessageDialog(this, Bundle.getMessage("CanNotConvertMeter"),
704                        Bundle.getMessage("ErrorTrackLength"), JmriJOptionPane.ERROR_MESSAGE);
705                return false;
706            }
707        }
708        // confirm that length is a number and less than 10000 feet
709        int trackLength = 0;
710        try {
711            trackLength = Integer.parseInt(length);
712            if (length.length() > Control.max_len_string_track_length_name) {
713                JmriJOptionPane.showMessageDialog(this,
714                        Bundle.getMessage("TrackMustBeLessThan",
715                                Math.pow(10, Control.max_len_string_track_length_name),
716                                Setup.getLengthUnit().toLowerCase()),
717                        Bundle.getMessage("ErrorTrackLength"), JmriJOptionPane.ERROR_MESSAGE);
718                return false;
719            }
720        } catch (NumberFormatException e) {
721            // log.error("Track length not an integer");
722            JmriJOptionPane.showMessageDialog(this, Bundle.getMessage("TrackMustBeNumber"),
723                    Bundle.getMessage("ErrorTrackLength"), JmriJOptionPane.ERROR_MESSAGE);
724            return false;
725        }
726        // track length can not be less than than the sum of used and reserved
727        // length
728        if (trackLength != track.getLength() && trackLength < track.getUsedLength() + track.getReserved()) {
729            // log.warn("Track length should not be less than used and
730            // reserved");
731            JmriJOptionPane.showMessageDialog(this, Bundle.getMessage("TrackMustBeGreater"),
732                    Bundle.getMessage("ErrorTrackLength"), JmriJOptionPane.ERROR_MESSAGE);
733            // does the user want to force the track length?
734            if (JmriJOptionPane.showConfirmDialog(this,
735                    Bundle.getMessage("TrackForceLength", track.getLength(), trackLength,
736                            Setup.getLengthUnit().toLowerCase()),
737                    Bundle.getMessage("ErrorTrackLength"),
738                    JmriJOptionPane.YES_NO_OPTION) != JmriJOptionPane.YES_OPTION) {
739                return false;
740            }
741        }
742        // if everything is okay, save length
743        track.setLength(trackLength);
744        return true;
745    }
746
747    private boolean checkService(Track track) {
748        // check train and route restrictions
749        if ((trainDrop.isSelected() || routeDrop.isSelected()) && track.getDropIds().length == 0) {
750            log.debug("Must enter trains or routes for this track");
751            JmriJOptionPane.showMessageDialog(this, Bundle.getMessage("UseAddTrainsOrRoutes"),
752                    Bundle.getMessage("SetOutDisabled"), JmriJOptionPane.ERROR_MESSAGE);
753            return false;
754        }
755        if ((trainPickup.isSelected() || routePickup.isSelected()) && track.getPickupIds().length == 0) {
756            log.debug("Must enter trains or routes for this track");
757            JmriJOptionPane.showMessageDialog(this, Bundle.getMessage("UseAddTrainsOrRoutes"),
758                    Bundle.getMessage("PickUpsDisabled"), JmriJOptionPane.ERROR_MESSAGE);
759            return false;
760        }
761        return true;
762    }
763
764    private boolean checkTrackPickups(Track track) {
765        // check to see if all car types can be pulled from this track
766        String status = track.checkPickups();
767        if (!status.equals(Track.PICKUP_OKAY) && !track.getPickupOption().equals(Track.ANY)) {
768            JmriJOptionPane.showMessageDialog(this, status, Bundle.getMessage("ErrorStrandedCar"),
769                    JmriJOptionPane.ERROR_MESSAGE);
770            return false;
771        }
772        return true;
773    }
774
775    private void reportTrackExists(String s) {
776        JmriJOptionPane.showMessageDialog(this, Bundle.getMessage("TrackAlreadyExists"),
777                Bundle.getMessage("CanNotTrack", s), JmriJOptionPane.ERROR_MESSAGE);
778    }
779
780    protected void enableButtons(boolean enabled) {
781        _toolMenu.setEnabled(enabled);
782        northCheckBox.setEnabled(enabled);
783        southCheckBox.setEnabled(enabled);
784        eastCheckBox.setEnabled(enabled);
785        westCheckBox.setEnabled(enabled);
786        clearButton.setEnabled(enabled);
787        setButton.setEnabled(enabled);
788        deleteTrackButton.setEnabled(enabled);
789        saveTrackButton.setEnabled(enabled);
790        roadOptionButton.setEnabled(enabled);
791        loadOptionButton.setEnabled(enabled);
792        shipLoadOptionButton.setEnabled(enabled);
793        destinationOptionButton.setEnabled(enabled);
794        anyDrops.setEnabled(enabled);
795        trainDrop.setEnabled(enabled);
796        routeDrop.setEnabled(enabled);
797        excludeTrainDrop.setEnabled(enabled);
798        excludeRouteDrop.setEnabled(enabled);
799        anyPickups.setEnabled(enabled);
800        trainPickup.setEnabled(enabled);
801        routePickup.setEnabled(enabled);
802        excludeTrainPickup.setEnabled(enabled);
803        excludeRoutePickup.setEnabled(enabled);
804        orderNormal.setEnabled(enabled);
805        orderFIFO.setEnabled(enabled);
806        orderLIFO.setEnabled(enabled);
807        enableCheckboxes(enabled);
808        if (readerSelector != null) {
809            // enable readerSelect.
810            readerSelector.setEnabled(enabled && Setup.isRfidEnabled());
811        }
812    }
813
814    @Override
815    public void radioButtonActionPerformed(java.awt.event.ActionEvent ae) {
816        log.debug("radio button activated");
817        if (ae.getSource() == orderNormal) {
818            _track.setServiceOrder(Track.NORMAL);
819        }
820        if (ae.getSource() == orderFIFO) {
821            _track.setServiceOrder(Track.FIFO);
822        }
823        if (ae.getSource() == orderLIFO) {
824            _track.setServiceOrder(Track.LIFO);
825        }
826        if (ae.getSource() == anyDrops) {
827            _track.setDropOption(Track.ANY);
828            updateDropOptions();
829        }
830        if (ae.getSource() == trainDrop) {
831            _track.setDropOption(Track.TRAINS);
832            updateDropOptions();
833        }
834        if (ae.getSource() == routeDrop) {
835            _track.setDropOption(Track.ROUTES);
836            updateDropOptions();
837        }
838        if (ae.getSource() == excludeTrainDrop) {
839            _track.setDropOption(Track.EXCLUDE_TRAINS);
840            updateDropOptions();
841        }
842        if (ae.getSource() == excludeRouteDrop) {
843            _track.setDropOption(Track.EXCLUDE_ROUTES);
844            updateDropOptions();
845        }
846        if (ae.getSource() == anyPickups) {
847            _track.setPickupOption(Track.ANY);
848            updatePickupOptions();
849        }
850        if (ae.getSource() == trainPickup) {
851            _track.setPickupOption(Track.TRAINS);
852            updatePickupOptions();
853        }
854        if (ae.getSource() == routePickup) {
855            _track.setPickupOption(Track.ROUTES);
856            updatePickupOptions();
857        }
858        if (ae.getSource() == excludeTrainPickup) {
859            _track.setPickupOption(Track.EXCLUDE_TRAINS);
860            updatePickupOptions();
861        }
862        if (ae.getSource() == excludeRoutePickup) {
863            _track.setPickupOption(Track.EXCLUDE_ROUTES);
864            updatePickupOptions();
865        }
866    }
867
868    // TODO only update comboBox when train or route list changes.
869    private void updateDropOptions() {
870        dropPanel.removeAll();
871        int numberOfItems = getNumberOfCheckboxesPerLine();
872
873        JPanel p = new JPanel();
874        p.setLayout(new GridBagLayout());
875        p.add(anyDrops);
876        p.add(trainDrop);
877        p.add(routeDrop);
878        p.add(excludeTrainDrop);
879        p.add(excludeRouteDrop);
880        GridBagConstraints gc = new GridBagConstraints();
881        gc.gridwidth = numberOfItems + 1;
882        dropPanel.add(p, gc);
883
884        int y = 1; // vertical position in panel
885
886        if (_track != null) {
887            // set radio button
888            anyDrops.setSelected(_track.getDropOption().equals(Track.ANY));
889            trainDrop.setSelected(_track.getDropOption().equals(Track.TRAINS));
890            routeDrop.setSelected(_track.getDropOption().equals(Track.ROUTES));
891            excludeTrainDrop.setSelected(_track.getDropOption().equals(Track.EXCLUDE_TRAINS));
892            excludeRouteDrop.setSelected(_track.getDropOption().equals(Track.EXCLUDE_ROUTES));
893
894            if (!anyDrops.isSelected()) {
895                p = new JPanel();
896                p.setLayout(new FlowLayout());
897                if (trainDrop.isSelected() || excludeTrainDrop.isSelected()) {
898                    p.add(comboBoxDropTrains);
899                } else {
900                    p.add(comboBoxDropRoutes);
901                }
902                p.add(addDropButton);
903                p.add(deleteDropButton);
904                p.add(autoDropCheckBox);
905                gc.gridy = y++;
906                dropPanel.add(p, gc);
907                y++;
908
909                String[] dropIds = _track.getDropIds();
910                int x = 0;
911                for (String id : dropIds) {
912                    JLabel names = new JLabel();
913                    String name = "<deleted>"; // NOI18N
914                    if (trainDrop.isSelected() || excludeTrainDrop.isSelected()) {
915                        Train train = trainManager.getTrainById(id);
916                        if (train != null) {
917                            name = train.getName();
918                        }
919                    } else {
920                        Route route = routeManager.getRouteById(id);
921                        if (route != null) {
922                            name = route.getName();
923                        }
924                    }
925                    if (name.equals("<deleted>")) // NOI18N
926                    {
927                        _track.deleteDropId(id);
928                    }
929                    names.setText(name);
930                    addItem(dropPanel, names, x++, y);
931                    if (x > numberOfItems) {
932                        y++;
933                        x = 0;
934                    }
935                }
936            }
937        } else {
938            anyDrops.setSelected(true);
939        }
940        dropPanel.revalidate();
941        dropPanel.repaint();
942        revalidate();
943    }
944
945    private void updatePickupOptions() {
946        log.debug("update pick up options");
947        pickupPanel.removeAll();
948        int numberOfCheckboxes = getNumberOfCheckboxesPerLine();
949
950        JPanel p = new JPanel();
951        p.setLayout(new GridBagLayout());
952        p.add(anyPickups);
953        p.add(trainPickup);
954        p.add(routePickup);
955        p.add(excludeTrainPickup);
956        p.add(excludeRoutePickup);
957        GridBagConstraints gc = new GridBagConstraints();
958        gc.gridwidth = numberOfCheckboxes + 1;
959        pickupPanel.add(p, gc);
960
961        int y = 1; // vertical position in panel
962
963        if (_track != null) {
964            // set radio button
965            anyPickups.setSelected(_track.getPickupOption().equals(Track.ANY));
966            trainPickup.setSelected(_track.getPickupOption().equals(Track.TRAINS));
967            routePickup.setSelected(_track.getPickupOption().equals(Track.ROUTES));
968            excludeTrainPickup.setSelected(_track.getPickupOption().equals(Track.EXCLUDE_TRAINS));
969            excludeRoutePickup.setSelected(_track.getPickupOption().equals(Track.EXCLUDE_ROUTES));
970
971            if (!anyPickups.isSelected()) {
972                p = new JPanel();
973                p.setLayout(new FlowLayout());
974                if (trainPickup.isSelected() || excludeTrainPickup.isSelected()) {
975                    p.add(comboBoxPickupTrains);
976                } else {
977                    p.add(comboBoxPickupRoutes);
978                }
979                p.add(addPickupButton);
980                p.add(deletePickupButton);
981                p.add(autoPickupCheckBox);
982                gc.gridy = y++;
983                pickupPanel.add(p, gc);
984                y++;
985
986                int x = 0;
987                for (String id : _track.getPickupIds()) {
988                    JLabel names = new JLabel();
989                    String name = "<deleted>"; // NOI18N
990                    if (trainPickup.isSelected() || excludeTrainPickup.isSelected()) {
991                        Train train = trainManager.getTrainById(id);
992                        if (train != null) {
993                            name = train.getName();
994                        }
995                    } else {
996                        Route route = routeManager.getRouteById(id);
997                        if (route != null) {
998                            name = route.getName();
999                        }
1000                    }
1001                    if (name.equals("<deleted>")) // NOI18N
1002                    {
1003                        _track.deletePickupId(id);
1004                    }
1005                    names.setText(name);
1006                    addItem(pickupPanel, names, x++, y);
1007                    if (x > numberOfCheckboxes) {
1008                        y++;
1009                        x = 0;
1010                    }
1011                }
1012            }
1013        } else {
1014            anyPickups.setSelected(true);
1015        }
1016        pickupPanel.revalidate();
1017        pickupPanel.repaint();
1018        revalidate();
1019    }
1020
1021    protected void updateTrainComboBox() {
1022        trainManager.updateTrainComboBox(comboBoxPickupTrains);
1023        if (autoPickupCheckBox.isSelected()) {
1024            autoTrainComboBox(comboBoxPickupTrains);
1025        }
1026        trainManager.updateTrainComboBox(comboBoxDropTrains);
1027        if (autoDropCheckBox.isSelected()) {
1028            autoTrainComboBox(comboBoxDropTrains);
1029        }
1030    }
1031
1032    // filter all trains not serviced by this track
1033    private void autoTrainComboBox(JComboBox<Train> box) {
1034        for (int i = 0; i < box.getItemCount(); i++) {
1035            Train train = box.getItemAt(i);
1036            if (train == null || !checkRoute(train.getRoute())) {
1037                box.removeItemAt(i--);
1038            }
1039        }
1040    }
1041
1042    protected void updateRouteComboBox() {
1043        routeManager.updateComboBox(comboBoxPickupRoutes);
1044        if (autoPickupCheckBox.isSelected()) {
1045            autoRouteComboBox(comboBoxPickupRoutes);
1046        }
1047        routeManager.updateComboBox(comboBoxDropRoutes);
1048        if (autoDropCheckBox.isSelected()) {
1049            autoRouteComboBox(comboBoxDropRoutes);
1050        }
1051    }
1052
1053    // filter out all routes not serviced by this track
1054    private void autoRouteComboBox(JComboBox<Route> box) {
1055        for (int i = 0; i < box.getItemCount(); i++) {
1056            Route route = box.getItemAt(i);
1057            if (!checkRoute(route)) {
1058                box.removeItemAt(i--);
1059            }
1060        }
1061    }
1062
1063    private void enableCheckboxes(boolean enable) {
1064        for (int i = 0; i < checkBoxes.size(); i++) {
1065            checkBoxes.get(i).setEnabled(enable);
1066        }
1067    }
1068
1069    private void selectCheckboxes(boolean enable) {
1070        for (int i = 0; i < checkBoxes.size(); i++) {
1071            JCheckBox checkBox = checkBoxes.get(i);
1072            checkBox.setSelected(enable);
1073            if (_track != null) {
1074                if (enable) {
1075                    _track.addTypeName(checkBox.getText());
1076                } else {
1077                    _track.deleteTypeName(checkBox.getText());
1078                }
1079            }
1080        }
1081    }
1082    
1083    // car and loco types
1084    private void updateCheckboxes() {
1085        // log.debug("Update all checkboxes");
1086        checkBoxes.clear();
1087        panelCheckBoxes.removeAll();
1088        numberOfCheckBoxes = getNumberOfCheckboxesPerLine();
1089        x = 0;
1090        y = 0; // vertical position in panel
1091        loadTypes(InstanceManager.getDefault(CarTypes.class).getNames());
1092
1093        // add space between car and loco types
1094        checkNewLine();
1095
1096        loadTypes(InstanceManager.getDefault(EngineTypes.class).getNames());
1097        enableCheckboxes(_track != null);
1098
1099        JPanel p = new JPanel();
1100        p.add(clearButton);
1101        p.add(setButton);
1102        if (_track != null && _track.isSpur()) {
1103            p.add(autoSelectButton);
1104        }
1105        GridBagConstraints gc = new GridBagConstraints();
1106        gc.gridwidth = getNumberOfCheckboxesPerLine() + 1;
1107        gc.gridy = ++y;
1108        panelCheckBoxes.add(p, gc);
1109
1110        panelCheckBoxes.revalidate();
1111        panelCheckBoxes.repaint();
1112    }
1113
1114    int x = 0;
1115    int y = 0; // vertical position in panel
1116
1117    private void loadTypes(String[] types) {
1118        for (String type : types) {
1119            if (_location.acceptsTypeName(type)) {
1120                JCheckBox checkBox = new JCheckBox();
1121                checkBoxes.add(checkBox);
1122                checkBox.setText(type);
1123                addCheckBoxAction(checkBox);
1124                addItemLeft(panelCheckBoxes, checkBox, x, y);
1125                if (_track != null && _track.isTypeNameAccepted(type)) {
1126                    checkBox.setSelected(true);
1127                }
1128                checkNewLine();
1129            }
1130        }
1131    }
1132
1133    int numberOfCheckBoxes;
1134
1135    private void checkNewLine() {
1136        if (++x > numberOfCheckBoxes) {
1137            y++;
1138            x = 0;
1139        }
1140    }
1141
1142    private void updateRoadOption() {
1143        if (_track != null) {
1144            roadOptionButton.setText(_track.getRoadOptionString());
1145        }
1146    }
1147
1148    private void updateLoadOption() {
1149        if (_track != null) {
1150            loadOptionButton.setText(_track.getLoadOptionString());
1151            shipLoadOptionButton.setText(_track.getShipLoadOptionString());
1152        }
1153    }
1154
1155    private void updateTrainDir() {
1156        northCheckBox.setVisible(((Setup.getTrainDirection() & Setup.NORTH) &
1157                (_location.getTrainDirections() & Location.NORTH)) == Location.NORTH);
1158        southCheckBox.setVisible(((Setup.getTrainDirection() & Setup.SOUTH) &
1159                (_location.getTrainDirections() & Location.SOUTH)) == Location.SOUTH);
1160        eastCheckBox.setVisible(((Setup.getTrainDirection() & Setup.EAST) &
1161                (_location.getTrainDirections() & Location.EAST)) == Location.EAST);
1162        westCheckBox.setVisible(((Setup.getTrainDirection() & Setup.WEST) &
1163                (_location.getTrainDirections() & Location.WEST)) == Location.WEST);
1164
1165        if (_track != null) {
1166            northCheckBox.setSelected((_track.getTrainDirections() & Track.NORTH) == Track.NORTH);
1167            southCheckBox.setSelected((_track.getTrainDirections() & Track.SOUTH) == Track.SOUTH);
1168            eastCheckBox.setSelected((_track.getTrainDirections() & Track.EAST) == Track.EAST);
1169            westCheckBox.setSelected((_track.getTrainDirections() & Track.WEST) == Track.WEST);
1170        }
1171        panelTrainDir.revalidate();
1172        revalidate();
1173    }
1174
1175    @Override
1176    public void checkBoxActionPerformed(java.awt.event.ActionEvent ae) {
1177        if (ae.getSource() == autoDropCheckBox || ae.getSource() == autoPickupCheckBox) {
1178            updateTrainComboBox();
1179            updateRouteComboBox();
1180            return;
1181        }
1182        JCheckBox b = (JCheckBox) ae.getSource();
1183        log.debug("checkbox change {}", b.getText());
1184        if (b.isSelected()) {
1185            _track.addTypeName(b.getText());
1186        } else {
1187            _track.deleteTypeName(b.getText());
1188        }
1189    }
1190
1191    // set the service order
1192    private void updateCarOrder() {
1193        if (_track != null) {
1194            orderNormal.setSelected(_track.getServiceOrder().equals(Track.NORMAL));
1195            orderFIFO.setSelected(_track.getServiceOrder().equals(Track.FIFO));
1196            orderLIFO.setSelected(_track.getServiceOrder().equals(Track.LIFO));
1197        }
1198    }
1199
1200    protected void updateDestinationOption() {
1201        if (_track != null) {
1202            if (_track.getDestinationOption().equals(Track.INCLUDE_DESTINATIONS)) {
1203                pDestinationOption.setVisible(true);
1204                destinationOptionButton.setText(Bundle.getMessage("AcceptOnly") +
1205                        " " +
1206                        _track.getDestinationListSize() +
1207                        " " +
1208                        Bundle.getMessage("Destinations"));
1209            } else if (_track.getDestinationOption().equals(Track.EXCLUDE_DESTINATIONS)) {
1210                pDestinationOption.setVisible(true);
1211                destinationOptionButton.setText(Bundle.getMessage("Exclude") +
1212                        " " +
1213                        (InstanceManager.getDefault(LocationManager.class).getNumberOfLocations() -
1214                                _track.getDestinationListSize()) +
1215                        " " +
1216                        Bundle.getMessage("Destinations"));
1217            } else {
1218                destinationOptionButton.setText(Bundle.getMessage("AcceptAll"));
1219            }
1220        }
1221    }
1222
1223    @Override
1224    public void dispose() {
1225        if (_track != null) {
1226            _track.removePropertyChangeListener(this);
1227        }
1228        if (_location != null) {
1229            _location.removePropertyChangeListener(this);
1230        }
1231        InstanceManager.getDefault(CarRoads.class).removePropertyChangeListener(this);
1232        InstanceManager.getDefault(CarLoads.class).removePropertyChangeListener(this);
1233        InstanceManager.getDefault(CarTypes.class).removePropertyChangeListener(this);
1234        trainManager.removePropertyChangeListener(this);
1235        routeManager.removePropertyChangeListener(this);
1236        super.dispose();
1237    }
1238
1239    @Override
1240    public void propertyChange(java.beans.PropertyChangeEvent e) {
1241        if (Control.SHOW_PROPERTY) {
1242            log.debug("Property change: ({}) old: ({}) new: ({})", e.getPropertyName(), e.getOldValue(),
1243                    e.getNewValue());
1244        }
1245        if (e.getPropertyName().equals(Location.TYPES_CHANGED_PROPERTY) ||
1246                e.getPropertyName().equals(CarTypes.CARTYPES_CHANGED_PROPERTY) ||
1247                e.getPropertyName().equals(Track.TYPES_CHANGED_PROPERTY)) {
1248            updateCheckboxes();
1249        }
1250        if (e.getPropertyName().equals(Location.TRAIN_DIRECTION_CHANGED_PROPERTY) ||
1251                e.getPropertyName().equals(Track.TRAIN_DIRECTION_CHANGED_PROPERTY) ||
1252                e.getPropertyName().equals(Setup.TRAIN_DIRECTION_PROPERTY_CHANGE)) {
1253            updateTrainDir();
1254        }
1255        if (e.getPropertyName().equals(TrainManager.LISTLENGTH_CHANGED_PROPERTY)) {
1256            updateTrainComboBox();
1257            updateDropOptions();
1258            updatePickupOptions();
1259        }
1260        if (e.getPropertyName().equals(RouteManager.LISTLENGTH_CHANGED_PROPERTY)) {
1261            updateRouteComboBox();
1262            updateDropOptions();
1263            updatePickupOptions();
1264        }
1265        if (e.getPropertyName().equals(Track.ROADS_CHANGED_PROPERTY)) {
1266            updateRoadOption();
1267        }
1268        if (e.getPropertyName().equals(Track.LOADS_CHANGED_PROPERTY)) {
1269            updateLoadOption();
1270        }
1271        if (e.getPropertyName().equals(Track.DROP_CHANGED_PROPERTY)) {
1272            updateDropOptions();
1273        }
1274        if (e.getPropertyName().equals(Track.PICKUP_CHANGED_PROPERTY)) {
1275            updatePickupOptions();
1276        }
1277        if (e.getPropertyName().equals(Track.SERVICE_ORDER_CHANGED_PROPERTY)) {
1278            updateCarOrder();
1279        }
1280        if (e.getPropertyName().equals(Track.DESTINATIONS_CHANGED_PROPERTY) ||
1281                e.getPropertyName().equals(Track.DESTINATION_OPTIONS_CHANGED_PROPERTY)) {
1282            updateDestinationOption();
1283        }
1284        if (e.getPropertyName().equals(Track.LENGTH_CHANGED_PROPERTY)) {
1285            trackLengthTextField.setText(Integer.toString(_track.getLength()));
1286        }
1287    }
1288
1289    private static final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(TrackEditFrame.class);
1290}