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