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