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