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