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