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