001package jmri.jmrit.operations.locations;
002
003import java.awt.Dimension;
004import java.awt.GridBagConstraints;
005import java.awt.GridBagLayout;
006import java.awt.event.ActionEvent;
007import java.text.MessageFormat;
008import java.util.ArrayList;
009import java.util.List;
010
011import javax.swing.*;
012
013import org.slf4j.Logger;
014import org.slf4j.LoggerFactory;
015
016import jmri.InstanceManager;
017import jmri.Reporter;
018import jmri.ReporterManager;
019import jmri.jmrit.operations.OperationsFrame;
020import jmri.jmrit.operations.OperationsXml;
021import jmri.jmrit.operations.locations.divisions.Division;
022import jmri.jmrit.operations.locations.divisions.DivisionEditFrame;
023import jmri.jmrit.operations.locations.divisions.DivisionManager;
024import jmri.jmrit.operations.locations.tools.*;
025import jmri.jmrit.operations.rollingstock.cars.CarTypes;
026import jmri.jmrit.operations.rollingstock.engines.EngineTypes;
027import jmri.jmrit.operations.setup.Control;
028import jmri.jmrit.operations.setup.Setup;
029import jmri.jmrit.operations.trains.TrainCommon;
030import jmri.swing.NamedBeanComboBox;
031
032/**
033 * Frame for user edit of location
034 *
035 * @author Dan Boudreau Copyright (C) 2008, 2010, 2011, 2012, 2013
036 */
037public class LocationEditFrame extends OperationsFrame implements java.beans.PropertyChangeListener {
038
039    YardTableModel yardModel = new YardTableModel();
040    JTable yardTable = new JTable(yardModel);
041    JScrollPane yardPane;
042    SpurTableModel spurModel = new SpurTableModel();
043    JTable spurTable = new JTable(spurModel);
044    JScrollPane spurPane;
045    InterchangeTableModel interchangeModel = new InterchangeTableModel();
046    JTable interchangeTable = new JTable(interchangeModel);
047    JScrollPane interchangePane;
048    StagingTableModel stagingModel = new StagingTableModel();
049    JTable stagingTable = new JTable(stagingModel);
050    JScrollPane stagingPane;
051
052    LocationManager locationManager = InstanceManager.getDefault(LocationManager.class);
053
054    public Location _location = null;
055    ArrayList<JCheckBox> checkBoxes = new ArrayList<>();
056    JPanel panelCheckBoxes = new JPanel();
057    JScrollPane typePane;
058    JPanel directionPanel = new JPanel();
059
060    // major buttons
061    JButton clearButton = new JButton(Bundle.getMessage("ClearAll"));
062    JButton setButton = new JButton(Bundle.getMessage("SelectAll"));
063    JButton autoSelectButton = new JButton(Bundle.getMessage("AutoSelect"));
064    JButton editDivisionButton = new JButton(Bundle.getMessage("ButtonEdit"));
065    JButton saveLocationButton = new JButton(Bundle.getMessage("SaveLocation"));
066    JButton deleteLocationButton = new JButton(Bundle.getMessage("DeleteLocation"));
067    JButton addLocationButton = new JButton(Bundle.getMessage("AddLocation"));
068    JButton addYardButton = new JButton(Bundle.getMessage("AddYard"));
069    JButton addSpurButton = new JButton(Bundle.getMessage("AddSpur"));
070    JButton addInterchangeButton = new JButton(Bundle.getMessage("AddInterchange"));
071    JButton addStagingButton = new JButton(Bundle.getMessage("AddStaging"));
072
073    // check boxes
074    JCheckBox northCheckBox = new JCheckBox(Bundle.getMessage("North"));
075    JCheckBox southCheckBox = new JCheckBox(Bundle.getMessage("South"));
076    JCheckBox eastCheckBox = new JCheckBox(Bundle.getMessage("East"));
077    JCheckBox westCheckBox = new JCheckBox(Bundle.getMessage("West"));
078
079    // radio buttons
080    JRadioButton stagingRadioButton = new JRadioButton(Bundle.getMessage("StagingOnly"));
081    JRadioButton interchangeRadioButton = new JRadioButton(Bundle.getMessage("Interchange"));
082    JRadioButton yardRadioButton = new JRadioButton(Bundle.getMessage("Yards"));
083    JRadioButton spurRadioButton = new JRadioButton(Bundle.getMessage("Spurs"));
084
085    // text field
086    JTextField locationNameTextField = new JTextField(Control.max_len_string_location_name);
087
088    // text area
089    JTextArea commentTextArea = new JTextArea(2, 60);
090    JScrollPane commentScroller = new JScrollPane(commentTextArea, JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED,
091            JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED);
092    
093    // combo boxes
094    protected JComboBox<Division> divisionComboBox = InstanceManager.getDefault(DivisionManager.class).getComboBox();
095
096    // Reader selection dropdown.
097    NamedBeanComboBox<Reporter> readerSelector;
098
099    JMenu toolMenu = new JMenu(Bundle.getMessage("MenuTools"));
100
101    public static final String NAME = Bundle.getMessage("Name");
102    public static final int MAX_NAME_LENGTH = Control.max_len_string_location_name;
103    public static final String DISPOSE = "dispose"; // NOI18N
104
105    public LocationEditFrame(Location location) {
106        super(Bundle.getMessage("TitleLocationEdit"));
107
108        _location = location;
109
110        // Set up the jtable in a Scroll Pane..
111        typePane = new JScrollPane(panelCheckBoxes);
112        typePane.setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED);
113        typePane.setBorder(BorderFactory.createTitledBorder(Bundle.getMessage("TypesLocation")));
114
115        yardPane = new JScrollPane(yardTable);
116        yardPane.setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED);
117        yardPane.setBorder(BorderFactory.createTitledBorder(""));
118
119        spurPane = new JScrollPane(spurTable);
120        spurPane.setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED);
121        spurPane.setBorder(BorderFactory.createTitledBorder(""));
122
123        interchangePane = new JScrollPane(interchangeTable);
124        interchangePane.setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED);
125        interchangePane.setBorder(BorderFactory.createTitledBorder(""));
126
127        stagingPane = new JScrollPane(stagingTable);
128        stagingPane.setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED);
129        stagingPane.setBorder(BorderFactory.createTitledBorder(""));
130
131        // button group
132        ButtonGroup opsGroup = new ButtonGroup();
133        opsGroup.add(spurRadioButton);
134        opsGroup.add(yardRadioButton);
135        opsGroup.add(interchangeRadioButton);
136        opsGroup.add(stagingRadioButton);
137
138        if (_location != null) {
139            enableButtons(true);
140            locationNameTextField.setText(_location.getName());
141            commentTextArea.setText(_location.getComment());
142            divisionComboBox.setSelectedItem(_location.getDivision());
143            yardModel.initTable(yardTable, location);
144            spurModel.initTable(spurTable, location);
145            interchangeModel.initTable(interchangeTable, location);
146            stagingModel.initTable(stagingTable, location);
147            _location.addPropertyChangeListener(this);
148            if (!_location.isStaging()) {
149                if (spurModel.getRowCount() > 0) {
150                    spurRadioButton.setSelected(true);
151                } else if (yardModel.getRowCount() > 0) {
152                    yardRadioButton.setSelected(true);
153                } else if (interchangeModel.getRowCount() > 0) {
154                    interchangeRadioButton.setSelected(true);
155                } else if (stagingModel.getRowCount() > 0) {
156                    stagingRadioButton.setSelected(true);
157                } else {
158                    spurRadioButton.setSelected(true);
159                }
160            } else {
161                stagingRadioButton.setSelected(true);
162            }
163            setTrainDirectionBoxes();
164        } else {
165            enableButtons(false);
166            spurRadioButton.setSelected(true);
167        }
168
169        setVisibleTracks();
170
171        getContentPane().setLayout(new BoxLayout(getContentPane(), BoxLayout.Y_AXIS));
172
173        // Layout the panel by rows
174        // row 1
175        JPanel p1 = new JPanel();
176        p1.setLayout(new BoxLayout(p1, BoxLayout.X_AXIS));
177        JScrollPane p1Pane = new JScrollPane(p1);
178        p1Pane.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_NEVER);
179        p1Pane.setMinimumSize(new Dimension(300, 3 * locationNameTextField.getPreferredSize().height));
180        p1Pane.setBorder(BorderFactory.createTitledBorder(""));
181
182        // row 1a
183        JPanel pName = new JPanel();
184        pName.setLayout(new GridBagLayout());
185        pName.setBorder(BorderFactory.createTitledBorder(Bundle.getMessage("Name")));
186
187        addItem(pName, locationNameTextField, 0, 0);
188
189        // row 1b
190        directionPanel.setLayout(new GridBagLayout());
191        directionPanel.setBorder(BorderFactory.createTitledBorder(Bundle.getMessage("TrainLocation")));
192        addItem(directionPanel, northCheckBox, 1, 0);
193        addItem(directionPanel, southCheckBox, 2, 0);
194        addItem(directionPanel, eastCheckBox, 3, 0);
195        addItem(directionPanel, westCheckBox, 4, 0);
196
197        p1.add(pName);
198        p1.add(directionPanel);
199        
200        // division field
201        JPanel pDivision = new JPanel();
202        pDivision.setLayout(new GridBagLayout());
203        pDivision.setBorder(BorderFactory.createTitledBorder(Bundle.getMessage("Division")));
204        addItem(pDivision, divisionComboBox, 2, 0);
205        addItem(pDivision, editDivisionButton, 3, 0);
206        setDivisionButtonText();
207
208        // row 5
209        panelCheckBoxes.setLayout(new GridBagLayout());
210        updateCheckboxes();
211
212        // row 9
213        JPanel pOp = new JPanel();
214        pOp.setLayout(new GridBagLayout());
215        pOp.setBorder(BorderFactory.createTitledBorder(Bundle.getMessage("TracksAtLocation")));
216        pOp.add(spurRadioButton);
217        pOp.add(yardRadioButton);
218        pOp.add(interchangeRadioButton);
219        pOp.add(stagingRadioButton);
220
221        // row 11
222        JPanel pC = new JPanel();
223        pC.setLayout(new GridBagLayout());
224        pC.setBorder(BorderFactory.createTitledBorder(Bundle.getMessage("Comment")));
225        addItem(pC, commentScroller, 0, 0);
226
227        // adjust text area width based on window size
228        adjustTextAreaColumnWidth(commentScroller, commentTextArea);
229
230        JPanel readerPanel = new JPanel();
231        readerPanel.setVisible(false);
232        // reader row
233        if (Setup.isRfidEnabled()) {
234            ReporterManager reporterManager = InstanceManager.getDefault(ReporterManager.class);
235            readerSelector = new NamedBeanComboBox<Reporter>(reporterManager);
236            readerSelector.setAllowNull(true);
237            readerPanel.setLayout(new GridBagLayout());
238            readerPanel.setBorder(BorderFactory.createTitledBorder(Bundle.getMessage("idReporter")));
239            addItem(readerPanel, readerSelector, 0, 0);
240            readerPanel.setVisible(true);
241            if (_location != null) {
242                readerSelector.setSelectedItem(_location.getReporter());
243            }
244        }
245
246        // row 12
247        JPanel pB = new JPanel();
248        pB.setLayout(new GridBagLayout());
249        addItem(pB, deleteLocationButton, 0, 0);
250        addItem(pB, addLocationButton, 1, 0);
251        addItem(pB, saveLocationButton, 3, 0);
252
253        getContentPane().add(p1Pane);
254        getContentPane().add(pDivision);
255        getContentPane().add(typePane);
256        getContentPane().add(pOp);
257        getContentPane().add(yardPane);
258        getContentPane().add(addYardButton);
259        getContentPane().add(spurPane);
260        getContentPane().add(addSpurButton);
261        getContentPane().add(interchangePane);
262        getContentPane().add(addInterchangeButton);
263        getContentPane().add(stagingPane);
264        getContentPane().add(addStagingButton);
265        getContentPane().add(pC);
266        getContentPane().add(readerPanel);
267        getContentPane().add(pB);
268
269        // setup buttons
270        addButtonAction(setButton);
271        addButtonAction(clearButton);
272        addButtonAction(autoSelectButton);
273        addButtonAction(editDivisionButton);
274        addButtonAction(deleteLocationButton);
275        addButtonAction(addLocationButton);
276        addButtonAction(saveLocationButton);
277        addButtonAction(addYardButton);
278        addButtonAction(addSpurButton);
279        addButtonAction(addInterchangeButton);
280        addButtonAction(addStagingButton);
281
282        // add tool tips
283        autoSelectButton.setToolTipText(Bundle.getMessage("TipAutoSelect"));
284
285        addRadioButtonAction(spurRadioButton);
286        addRadioButtonAction(yardRadioButton);
287        addRadioButtonAction(interchangeRadioButton);
288        addRadioButtonAction(stagingRadioButton);
289
290        addCheckBoxTrainAction(northCheckBox);
291        addCheckBoxTrainAction(southCheckBox);
292        addCheckBoxTrainAction(eastCheckBox);
293        addCheckBoxTrainAction(westCheckBox);
294        
295        addComboBoxAction(divisionComboBox);
296
297        // add property listeners
298        InstanceManager.getDefault(CarTypes.class).addPropertyChangeListener(this);
299        InstanceManager.getDefault(EngineTypes.class).addPropertyChangeListener(this);
300        InstanceManager.getDefault(DivisionManager.class).addPropertyChangeListener(this);
301
302        // build menu
303        JMenuBar menuBar = new JMenuBar();
304
305        loadToolMenu();
306        menuBar.add(toolMenu);
307        setJMenuBar(menuBar);
308        addHelpMenu("package.jmri.jmrit.operations.Operations_AddLocation", true); // NOI18N
309
310        pack();
311        setMinimumSize(new Dimension(Control.panelWidth600, Control.panelHeight500));
312        setVisible(true);
313    }
314
315    private void loadToolMenu() {
316        toolMenu.removeAll();
317        toolMenu.add(new TrackCopyAction(this));
318        toolMenu.add(new ChangeTracksTypeAction(this));
319        toolMenu.add(new ShowTrackMovesAction());
320        toolMenu.add(new ModifyLocationsAction(_location));
321        toolMenu.add(new ModifyLocationsCarLoadsAction(_location));
322        if (_location != null && !_location.isStaging()) {
323            toolMenu.add(new LocationTrackBlockingOrderAction(_location));
324        }
325        toolMenu.add(new ShowTrainsServingLocationAction(_location, null));
326        toolMenu.add(new EditCarTypeAction());
327        toolMenu.add(new ShowCarsByLocationAction(false, _location, null));
328        toolMenu.addSeparator();
329        toolMenu.add(new PrintLocationsAction(false, _location));
330        toolMenu.add(new PrintLocationsAction(true, _location));
331        if (Setup.isVsdPhysicalLocationEnabled()) {
332            toolMenu.add(new SetPhysicalLocationAction(_location));
333        }
334    }
335
336    // frames
337    DivisionEditFrame def = null;
338    YardEditFrame yef = null;
339    SpurEditFrame sef = null;
340    InterchangeEditFrame ief = null;
341    StagingEditFrame stef = null;
342
343    // Save, Delete, Add
344    @Override
345    public void buttonActionPerformed(java.awt.event.ActionEvent ae) {
346        if (ae.getSource() == editDivisionButton) {
347            if (def != null) {
348                def.dispose();
349            }
350            def = new DivisionEditFrame((Division) divisionComboBox.getSelectedItem());
351        }
352        if (ae.getSource() == addYardButton) {
353            yef = new YardEditFrame();
354            yef.initComponents(_location, null);
355        }
356        if (ae.getSource() == addSpurButton) {
357            sef = new SpurEditFrame();
358            sef.initComponents(_location, null);
359        }
360        if (ae.getSource() == addInterchangeButton) {
361            ief = new InterchangeEditFrame();
362            ief.initComponents(_location, null);
363        }
364        if (ae.getSource() == addStagingButton) {
365            stef = new StagingEditFrame();
366            stef.initComponents(_location, null);
367        }
368
369        if (ae.getSource() == saveLocationButton) {
370            log.debug("location save button activated");
371            Location l = locationManager.getLocationByName(locationNameTextField.getText());
372            if (_location == null && l == null) {
373                saveNewLocation();
374            } else {
375                if (l != null && l != _location) {
376                    reportLocationExists(Bundle.getMessage("save"));
377                    return;
378                }
379                saveLocation();
380                if (Setup.isCloseWindowOnSaveEnabled()) {
381                    dispose();
382                }
383            }
384        }
385        if (ae.getSource() == deleteLocationButton) {
386            log.debug("location delete button activated");
387            Location l = locationManager.getLocationByName(locationNameTextField.getText());
388            if (l == null) {
389                return;
390            }
391            int rs = l.getNumberRS();
392            if (rs > 0) {
393                if (JOptionPane.showConfirmDialog(this, MessageFormat.format(Bundle.getMessage("ThereAreCars"),
394                        new Object[]{Integer.toString(rs)}), Bundle.getMessage("deletelocation?"),
395                        JOptionPane.YES_NO_OPTION) != JOptionPane.YES_OPTION) {
396                    return;
397                }
398            } else {
399                if (JOptionPane.showConfirmDialog(this, MessageFormat.format(Bundle
400                        .getMessage("DoYouWantToDeleteLocation"), new Object[]{locationNameTextField.getText()}),
401                        Bundle.getMessage("deletelocation?"), JOptionPane.YES_NO_OPTION) != JOptionPane.YES_OPTION) {
402                    return;
403                }
404            }
405
406            yardModel.dispose();
407            spurModel.dispose();
408            interchangeModel.dispose();
409            stagingModel.dispose();
410
411            if (yef != null) {
412                yef.dispose();
413            }
414            if (sef != null) {
415                sef.dispose();
416            }
417            if (ief != null) {
418                ief.dispose();
419            }
420            if (stef != null) {
421                stef.dispose();
422            }
423
424            locationManager.deregister(l);
425            _location = null;
426            selectCheckboxes(false);
427            enableCheckboxes(false);
428            enableButtons(false);
429            // save location file
430            OperationsXml.save();
431        }
432        if (ae.getSource() == addLocationButton) {
433            Location l = locationManager.getLocationByName(locationNameTextField.getText());
434            if (l != null) {
435                reportLocationExists(Bundle.getMessage("add"));
436                return;
437            }
438            saveNewLocation();
439        }
440        if (ae.getSource() == setButton) {
441            selectCheckboxes(true);
442        }
443        if (ae.getSource() == clearButton) {
444            selectCheckboxes(false);
445        }
446        if (ae.getSource() == autoSelectButton) {
447            log.debug("auto select button pressed");
448            if (JOptionPane.showConfirmDialog(this, Bundle.getMessage("autoSelectCarTypes?"), Bundle
449                    .getMessage("autoSelectLocations?"), JOptionPane.YES_NO_OPTION) != JOptionPane.YES_OPTION) {
450                return;
451            }
452            autoSelectCheckboxes();
453        }
454    }
455
456    private void saveNewLocation() {
457        if (!checkName(Bundle.getMessage("add"))) {
458            return;
459        }
460        Location location = locationManager.newLocation(locationNameTextField.getText());
461        yardModel.initTable(yardTable, location);
462        spurModel.initTable(spurTable, location);
463        interchangeModel.initTable(interchangeTable, location);
464        stagingModel.initTable(stagingTable, location);
465        _location = location;
466        _location.addPropertyChangeListener(this);
467
468        updateCheckboxes();
469        enableButtons(true);
470        setTrainDirectionBoxes();
471        saveLocation();
472        loadToolMenu();
473    }
474
475    private void saveLocation() {
476        if (!checkName(Bundle.getMessage("save"))) {
477            return;
478        }
479        // stop table editing so "Moves" are properly saved
480        if (spurTable.isEditing()) {
481            spurTable.getCellEditor().stopCellEditing();
482        }
483        if (yardTable.isEditing()) {
484            yardTable.getCellEditor().stopCellEditing();
485        }
486        if (interchangeTable.isEditing()) {
487            interchangeTable.getCellEditor().stopCellEditing();
488        }
489        if (stagingTable.isEditing()) {
490            stagingTable.getCellEditor().stopCellEditing();
491        }
492        _location.setName(locationNameTextField.getText());
493        _location.setComment(commentTextArea.getText());
494        _location.setDivision((Division) divisionComboBox.getSelectedItem());
495        if (Setup.isRfidEnabled() && readerSelector != null) {
496            _location.setReporter(readerSelector.getSelectedItem());
497        }
498        // save location file
499        OperationsXml.save();
500    }
501
502    /**
503     * @return true if name OK and is less than the maximum allowed length
504     */
505    private boolean checkName(String s) {
506        if (locationNameTextField.getText().trim().isEmpty()) {
507            JOptionPane.showMessageDialog(this, Bundle.getMessage("MustEnterName"), MessageFormat.format(Bundle
508                    .getMessage("CanNotLocation"), new Object[]{s}), JOptionPane.ERROR_MESSAGE);
509            return false;
510        }
511        if (TrainCommon.splitString(locationNameTextField.getText()).length() > MAX_NAME_LENGTH) {
512            // log.error("Location name must be less than "+
513            // Integer.toString(MAX_NAME_LENGTH+1) +" characters");
514            JOptionPane.showMessageDialog(this, MessageFormat.format(Bundle.getMessage("LocationNameLengthMax"),
515                    new Object[]{Integer.toString(MAX_NAME_LENGTH + 1)}),
516                    MessageFormat.format(Bundle
517                            .getMessage("CanNotLocation"), new Object[]{s}),
518                    JOptionPane.ERROR_MESSAGE);
519            return false;
520        }
521        if (!OperationsXml.checkFileName(locationNameTextField.getText())) { // NOI18N
522            JOptionPane.showMessageDialog(this,
523                    Bundle.getMessage("NameResChar") + NEW_LINE + Bundle.getMessage("ReservedChar"),
524                    MessageFormat.format(Bundle.getMessage("CanNotLocation"), new Object[]{s}),
525                    JOptionPane.ERROR_MESSAGE);
526            return false;
527        }
528        return true;
529    }
530
531    private void reportLocationExists(String s) {
532        // log.info("Can not " + s + ", location already exists");
533        JOptionPane.showMessageDialog(this, Bundle.getMessage("LocationAlreadyExists"), MessageFormat.format(Bundle
534                .getMessage("CanNotLocation"), new Object[]{s}), JOptionPane.ERROR_MESSAGE);
535    }
536
537    private void enableButtons(boolean enabled) {
538        toolMenu.setEnabled(enabled);
539        northCheckBox.setEnabled(enabled);
540        southCheckBox.setEnabled(enabled);
541        eastCheckBox.setEnabled(enabled);
542        westCheckBox.setEnabled(enabled);
543        divisionComboBox.setEnabled(enabled);
544        editDivisionButton.setEnabled(enabled);
545        clearButton.setEnabled(enabled);
546        setButton.setEnabled(enabled);
547        autoSelectButton.setEnabled(enabled);
548        addYardButton.setEnabled(enabled);
549        addSpurButton.setEnabled(enabled);
550        addInterchangeButton.setEnabled(enabled);
551        addStagingButton.setEnabled(enabled);
552        saveLocationButton.setEnabled(enabled);
553        deleteLocationButton.setEnabled(enabled);
554        // the inverse!
555        addLocationButton.setEnabled(!enabled);
556        // enable radio buttons
557        spurRadioButton.setEnabled(enabled);
558        yardRadioButton.setEnabled(enabled);
559        interchangeRadioButton.setEnabled(enabled);
560        stagingRadioButton.setEnabled(enabled);
561        if (readerSelector != null) {
562            // enable readerSelect.
563            readerSelector.setEnabled(enabled && Setup.isRfidEnabled());
564        }
565    }
566
567    @Override
568    public void radioButtonActionPerformed(java.awt.event.ActionEvent ae) {
569        setVisibleTracks();
570    }
571
572    private void setVisibleTracks() {
573        setEnabledTracks();
574        interchangePane.setVisible(interchangeRadioButton.isSelected());
575        addInterchangeButton.setVisible(interchangeRadioButton.isSelected());
576        stagingPane.setVisible(stagingRadioButton.isSelected());
577        addStagingButton.setVisible(stagingRadioButton.isSelected());
578        yardPane.setVisible(yardRadioButton.isSelected());
579        addYardButton.setVisible(yardRadioButton.isSelected());
580        spurPane.setVisible(spurRadioButton.isSelected());
581        addSpurButton.setVisible(spurRadioButton.isSelected());
582    }
583
584    private void setEnabledTracks() {
585        if (spurModel.getRowCount() > 0 || yardModel.getRowCount() > 0 || interchangeModel.getRowCount() > 0) {
586            if (stagingRadioButton.isSelected()) {
587                spurRadioButton.setSelected(true);
588            }
589            stagingRadioButton.setEnabled(false);
590        } else if (stagingModel.getRowCount() > 0) {
591            stagingRadioButton.setSelected(true);
592            spurRadioButton.setEnabled(false);
593            yardRadioButton.setEnabled(false);
594            interchangeRadioButton.setEnabled(false);
595        } else if (_location != null) {
596            spurRadioButton.setEnabled(true);
597            yardRadioButton.setEnabled(true);
598            interchangeRadioButton.setEnabled(true);
599            stagingRadioButton.setEnabled(true);
600        }
601    }
602
603    private void enableCheckboxes(boolean enable) {
604        for (int i = 0; i < checkBoxes.size(); i++) {
605            checkBoxes.get(i).setEnabled(enable);
606        }
607    }
608
609    private void selectCheckboxes(boolean select) {
610        for (int i = 0; i < checkBoxes.size(); i++) {
611            checkBoxes.get(i).setSelected(select);
612            if (_location != null) {
613                if (select) {
614                    _location.addTypeName(checkBoxes.get(i).getText());
615                } else {
616                    _location.deleteTypeName(checkBoxes.get(i).getText());
617                }
618            }
619        }
620    }
621
622    private void updateCheckboxes() {
623        x = 0;
624        y = 0;
625        checkBoxes.clear();
626        panelCheckBoxes.removeAll();
627        loadTypes(InstanceManager.getDefault(CarTypes.class).getNames());
628        loadTypes(InstanceManager.getDefault(EngineTypes.class).getNames());
629        JPanel p = new JPanel();
630        p.add(clearButton);
631        p.add(setButton);
632        p.add(autoSelectButton);
633        GridBagConstraints gc = new GridBagConstraints();
634        gc.gridwidth = getNumberOfCheckboxesPerLine() + 1;
635        gc.gridy = ++y;
636        panelCheckBoxes.add(p, gc);
637        panelCheckBoxes.revalidate();
638        repaint();
639    }
640    
641    protected void updateDivisionComboBox() {
642        InstanceManager.getDefault(DivisionManager.class).updateComboBox(divisionComboBox);
643        if (_location != null) {
644            divisionComboBox.setSelectedItem(_location.getDivision());
645        }
646    }
647
648    int x = 0;
649    int y = 0; // vertical position in panel
650
651    private void loadTypes(String[] types) {
652        int numberOfCheckBoxes = getNumberOfCheckboxesPerLine();
653        for (String type : types) {
654            JCheckBox checkBox = new JCheckBox();
655            checkBoxes.add(checkBox);
656            checkBox.setText(type);
657            addCheckBoxAction(checkBox);
658            addItemLeft(panelCheckBoxes, checkBox, x++, y);
659            if (_location != null) {
660                if (_location.acceptsTypeName(type)) {
661                    checkBox.setSelected(true);
662                }
663            } else {
664                checkBox.setEnabled(false);
665            }
666            // default is seven types per row
667            if (x > numberOfCheckBoxes) {
668                y++;
669                x = 0;
670            }
671        }
672    }
673
674    /**
675     * Adjust the location's car service types to only reflect the car types
676     * serviced by the location's tracks.
677     */
678    private void autoSelectCheckboxes() {
679        for (int i = 0; i < checkBoxes.size(); i++) {
680            checkBoxes.get(i).setSelected(false);
681            // check each track to determine which car types are serviced by
682            // this location
683            List<Track> tracks = _location.getTracksList();
684            for (Track track : tracks) {
685                if (track.isTypeNameAccepted(checkBoxes.get(i).getText())) {
686                    checkBoxes.get(i).setSelected(true);
687                }
688            }
689            // this type of car isn't serviced by any of the tracks, so delete
690            if (!checkBoxes.get(i).isSelected()) {
691                _location.deleteTypeName(checkBoxes.get(i).getText());
692            }
693        }
694    }
695
696    LocationsByCarTypeFrame lctf = null;
697
698    @Override
699    public void checkBoxActionPerformed(java.awt.event.ActionEvent ae) {
700        JCheckBox b = (JCheckBox) ae.getSource();
701        log.debug("checkbox change {}", b.getText());
702        if (_location == null) {
703            return;
704        }
705        _location.removePropertyChangeListener(this);
706        if (b.isSelected()) {
707            _location.addTypeName(b.getText());
708            // show which tracks will service this car type
709            if (InstanceManager.getDefault(CarTypes.class).containsName(b.getText())) {
710                if (lctf != null) {
711                    lctf.dispose();
712                }
713                lctf = new LocationsByCarTypeFrame();
714                lctf.initComponents(_location, b.getText());
715            }
716        } else {
717            _location.deleteTypeName(b.getText());
718        }
719        _location.addPropertyChangeListener(this);
720    }
721
722    private void addCheckBoxTrainAction(JCheckBox b) {
723        b.addActionListener(new java.awt.event.ActionListener() {
724            @Override
725            public void actionPerformed(java.awt.event.ActionEvent e) {
726                checkBoxActionTrainPerformed(e);
727            }
728        });
729    }
730
731    private void checkBoxActionTrainPerformed(java.awt.event.ActionEvent ae) {
732        // save train directions serviced by this location
733        if (_location == null) {
734            return;
735        }
736        int direction = 0;
737        if (northCheckBox.isSelected()) {
738            direction += Location.NORTH;
739        }
740        if (southCheckBox.isSelected()) {
741            direction += Location.SOUTH;
742        }
743        if (eastCheckBox.isSelected()) {
744            direction += Location.EAST;
745        }
746        if (westCheckBox.isSelected()) {
747            direction += Location.WEST;
748        }
749        _location.setTrainDirections(direction);
750
751    }
752
753    private void setTrainDirectionBoxes() {
754        northCheckBox.setVisible((Setup.getTrainDirection() & Setup.NORTH) == Setup.NORTH);
755        southCheckBox.setVisible((Setup.getTrainDirection() & Setup.SOUTH) == Setup.SOUTH);
756        eastCheckBox.setVisible((Setup.getTrainDirection() & Setup.EAST) == Setup.EAST);
757        westCheckBox.setVisible((Setup.getTrainDirection() & Setup.WEST) == Setup.WEST);
758
759        northCheckBox.setSelected((_location.getTrainDirections() & Location.NORTH) == Location.NORTH);
760        southCheckBox.setSelected((_location.getTrainDirections() & Location.SOUTH) == Location.SOUTH);
761        eastCheckBox.setSelected((_location.getTrainDirections() & Location.EAST) == Location.EAST);
762        westCheckBox.setSelected((_location.getTrainDirections() & Location.WEST) == Location.WEST);
763    }
764    
765    @Override
766    protected void comboBoxActionPerformed(ActionEvent ae) {
767        setDivisionButtonText();
768    }
769    
770    private void setDivisionButtonText() {
771        if (divisionComboBox.getSelectedItem() == null) {
772            editDivisionButton.setText(Bundle.getMessage("Add"));
773        } else {
774            editDivisionButton.setText(Bundle.getMessage("ButtonEdit"));
775        }
776    }
777
778    @Override
779    public void dispose() {
780        if (_location != null) {
781            _location.removePropertyChangeListener(this);
782        }
783        InstanceManager.getDefault(CarTypes.class).removePropertyChangeListener(this);
784        InstanceManager.getDefault(EngineTypes.class).removePropertyChangeListener(this);
785        yardModel.dispose();
786        spurModel.dispose();
787        interchangeModel.dispose();
788        stagingModel.dispose();
789        if (lctf != null) {
790            lctf.dispose();
791        }
792        super.dispose();
793    }
794
795    @Override
796    public void propertyChange(java.beans.PropertyChangeEvent e) {
797        if (Control.SHOW_PROPERTY) {
798            log.debug("Property change: ({}) old: ({}) new: ({})", e.getPropertyName(), e.getOldValue(), e
799                    .getNewValue());
800        }
801        if (e.getPropertyName().equals(CarTypes.CARTYPES_CHANGED_PROPERTY) ||
802                e.getPropertyName().equals(EngineTypes.ENGINETYPES_CHANGED_PROPERTY) ||
803                e.getPropertyName().equals(Location.TYPES_CHANGED_PROPERTY)) {
804            updateCheckboxes();
805        }
806        if (e.getPropertyName().equals(DivisionManager.LISTLENGTH_CHANGED_PROPERTY)) {
807            updateDivisionComboBox();
808        }
809    }
810
811    private final static Logger log = LoggerFactory.getLogger(LocationEditFrame.class);
812}