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