001package jmri.jmrit.operations.rollingstock;
002
003import java.awt.Dimension;
004import java.awt.GridBagLayout;
005import java.text.*;
006import java.util.ResourceBundle;
007
008import javax.swing.*;
009
010import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
011import jmri.*;
012import jmri.jmrit.operations.OperationsFrame;
013import jmri.jmrit.operations.OperationsXml;
014import jmri.jmrit.operations.locations.*;
015import jmri.jmrit.operations.rollingstock.cars.*;
016import jmri.jmrit.operations.rollingstock.engines.Engine;
017import jmri.jmrit.operations.rollingstock.engines.EngineTypes;
018import jmri.jmrit.operations.setup.Control;
019import jmri.jmrit.operations.setup.Setup;
020import jmri.jmrit.operations.trains.TrainCommon;
021import jmri.swing.NamedBeanComboBox;
022import jmri.util.swing.JmriJOptionPane;
023
024/**
025 * Frame for edit of rolling stock. The common elements are: road, road number,
026 * type, blocking, length, location and track, groups (Kernel or Consist)
027 * weight, color, built, owner, comment.
028 * 
029 * The edit engine frame currently doesn't show blocking or color.
030 * 
031 * Engines and cars have different type, length, and group managers.
032 *
033 * @author Dan Boudreau Copyright (C) 2018
034 */
035public abstract class RollingStockEditFrame extends OperationsFrame implements java.beans.PropertyChangeListener {
036
037    protected static final boolean IS_SAVE = true;
038
039    protected RollingStock _rs;
040
041    protected LocationManager locationManager = InstanceManager.getDefault(LocationManager.class);
042
043    JLabel textWeightTons = new JLabel(Bundle.getMessage("WeightTons"));
044    JLabel textRfidSystemName = new JLabel();
045
046    // major buttons
047    public JButton editRoadButton = new JButton(Bundle.getMessage("ButtonEdit"));
048    public JButton clearRoadNumberButton = new JButton(Bundle.getMessage("ButtonClear"));
049    public JButton editTypeButton = new JButton(Bundle.getMessage("ButtonEdit"));
050    public JButton editLengthButton = new JButton(Bundle.getMessage("ButtonEdit"));
051    public JButton editGroupButton = new JButton(Bundle.getMessage("ButtonEdit"));
052    public JButton editOwnerButton = new JButton(Bundle.getMessage("ButtonEdit"));
053
054    public JButton saveButton = new JButton(Bundle.getMessage("ButtonSave"));
055    public JButton deleteButton = new JButton(Bundle.getMessage("ButtonDelete"));
056    public JButton addButton = new JButton(); // add car or locomotive
057
058    // check boxes
059    public JCheckBox autoTrackCheckBox = new JCheckBox(Bundle.getMessage("Auto"));
060
061    // text field
062    public JTextField roadNumberTextField = new JTextField(Control.max_len_string_road_number);
063    public JTextField builtTextField = new JTextField(Control.max_len_string_built_name + 3);
064    public JTextField blockingTextField = new JTextField(4);
065    public JTextField weightTextField = new JTextField(Control.max_len_string_weight_name);
066    public JTextField weightTonsTextField = new JTextField(Control.max_len_string_weight_name);
067    public JTextField commentTextField = new JTextField(35);
068
069    // text area
070    public JTextArea valueTextArea = new JTextArea(3, 35);
071    JScrollPane valueScroller = new JScrollPane(valueTextArea, JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED,
072            JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED);
073
074    // combo boxes
075    public JComboBox<String> roadComboBox = InstanceManager.getDefault(CarRoads.class).getComboBox();
076    public JComboBox<String> typeComboBox = getTypeManager().getComboBox();
077    public JComboBox<String> lengthComboBox = getLengthManager().getComboBox();
078    public JComboBox<String> ownerComboBox = InstanceManager.getDefault(CarOwners.class).getComboBox();
079    public JComboBox<String> groupComboBox;
080    public JComboBox<String> modelComboBox; // for engines
081    public JComboBox<Location> locationBox = locationManager.getComboBox();
082    public JComboBox<Track> trackLocationBox = new JComboBox<>();
083
084    public NamedBeanComboBox<IdTag> rfidComboBox;
085
086    // panels
087    public JPanel pTypeOptions = new JPanel(); // options dependent on car or engine
088    public JPanel pGroup = new JPanel(); // Kernel or Consist
089
090    // panels for car edit
091    public JPanel pBlocking = new JPanel();
092    public JPanel pColor = new JPanel();
093    public JPanel pLoad = new JPanel();
094    public JPanel pWeightOz = new JPanel();
095
096    // panels for engine edit
097    public JPanel pModel = new JPanel();
098    public JPanel pPower = new JPanel();
099
100    public RollingStockEditFrame(String title) {
101        super(title);
102        // InstanceManager = InstanceManger.getInstance();
103    }
104
105    abstract protected RollingStockAttribute getTypeManager();
106
107    abstract protected RollingStockAttribute getLengthManager();
108
109    abstract protected void buttonEditActionPerformed(java.awt.event.ActionEvent ae);
110
111    abstract protected ResourceBundle getRb();
112
113    abstract protected void save(boolean isSave);
114
115    abstract protected void delete();
116
117    @SuppressFBWarnings(value = "NP_NULL_ON_SOME_PATH_FROM_RETURN_VALUE", justification = "Checks for null")
118    @Override
119    public void initComponents() {
120
121        // disable delete and save buttons
122        deleteButton.setEnabled(false);
123        saveButton.setEnabled(false);
124
125        editRoadButton.setToolTipText(Bundle.getMessage("TipAddDeleteReplace",
126                Bundle.getMessage("road"))); // initial caps for some languages i.e. German
127        editTypeButton.setToolTipText(Bundle.getMessage("TipAddDeleteReplace",
128                Bundle.getMessage("type"))); // initial caps for some languages i.e. German
129        editLengthButton.setToolTipText(Bundle.getMessage("TipAddDeleteReplace",
130                Bundle.getMessage("length"))); // initial caps for some languages i.e. German
131        editOwnerButton.setToolTipText(Bundle.getMessage("TipAddDeleteReplace",
132                Bundle.getMessage("Owner").toLowerCase()));
133
134        autoTrackCheckBox.setToolTipText(getRb().getString("rsTipAutoTrack"));
135
136        // create panel
137        JPanel pPanel = new JPanel();
138        pPanel.setLayout(new BoxLayout(pPanel, BoxLayout.Y_AXIS));
139
140        // Layout the panel by rows
141        // row 1
142        JPanel pRoad = new JPanel();
143        pRoad.setLayout(new GridBagLayout());
144        pRoad.setBorder(BorderFactory.createTitledBorder(Bundle.getMessage("Road")));
145        addItem(pRoad, roadComboBox, 1, 0);
146        addItem(pRoad, editRoadButton, 2, 0);
147        pPanel.add(pRoad);
148
149        // row 2
150        JPanel pRoadNumber = new JPanel();
151        pRoadNumber.setLayout(new GridBagLayout());
152        pRoadNumber.setBorder(BorderFactory.createTitledBorder(Bundle.getMessage("RoadNumber")));
153        addItem(pRoadNumber, roadNumberTextField, 1, 0);
154        addItem(pRoadNumber, clearRoadNumberButton, 2, 0);
155        pPanel.add(pRoadNumber);
156
157        // only engines have a model name
158        pPanel.add(pModel);
159        pModel.setVisible(false);
160
161        // row 3
162        JPanel pType = new JPanel();
163        pType.setLayout(new GridBagLayout());
164        pType.setBorder(BorderFactory.createTitledBorder(Bundle.getMessage("Type")));
165        addItem(pType, typeComboBox, 0, 0);
166        addItem(pType, editTypeButton, 1, 0);
167
168        // type options dependent on car or engine rolling stock
169        addItemWidth(pType, pTypeOptions, 3, 0, 1);
170        pPanel.add(pType);
171
172        // row 4
173        pBlocking.setLayout(new GridBagLayout());
174        pBlocking.setBorder(BorderFactory.createTitledBorder(Bundle.getMessage("BorderLayoutBlockingOrder")));
175        addItem(pBlocking, blockingTextField, 0, 0);
176        blockingTextField.setText("0");
177        pPanel.add(pBlocking);
178        pBlocking.setVisible(false); // default is blocking order not shown
179
180        // row 5
181        JPanel pLength = new JPanel();
182        pLength.setLayout(new GridBagLayout());
183        pLength.setBorder(BorderFactory.createTitledBorder(Bundle.getMessage("Length")));
184        addItem(pLength, lengthComboBox, 1, 0);
185        addItem(pLength, editLengthButton, 2, 0);
186        pPanel.add(pLength);
187
188        // row 6
189        JPanel pLocation = new JPanel();
190        pLocation.setLayout(new GridBagLayout());
191        pLocation.setBorder(BorderFactory.createTitledBorder(Bundle.getMessage("LocationAndTrack")));
192        addItem(pLocation, locationBox, 1, 0);
193        addItem(pLocation, trackLocationBox, 2, 0);
194        addItem(pLocation, autoTrackCheckBox, 3, 0);
195        pPanel.add(pLocation);
196
197        // optional panel
198        JPanel pOptional = new JPanel();
199        pOptional.setLayout(new BoxLayout(pOptional, BoxLayout.Y_AXIS));
200        JScrollPane optionPane = new JScrollPane(pOptional);
201        optionPane.setBorder(BorderFactory.createTitledBorder(Bundle.getMessage("BorderLayoutOptional")));
202
203        // row 7
204        JPanel pWeight = new JPanel();
205        pWeight.setLayout(new BoxLayout(pWeight, BoxLayout.Y_AXIS));
206        pWeight.setBorder(BorderFactory.createTitledBorder(Bundle.getMessage("Weight")));
207
208        // weight in oz only shown for cars
209        pWeight.add(pWeightOz);
210
211        JPanel pWeightTons = new JPanel();
212        pWeightTons.setLayout(new GridBagLayout());
213        addItem(pWeightTons, textWeightTons, 0, 0);
214        addItem(pWeightTons, weightTonsTextField, 1, 0);
215        addItem(pWeightTons, new JLabel(), 2, 0);
216        addItem(pWeightTons, new JLabel(), 3, 0);
217        addItem(pWeightTons, new JLabel(), 4, 0);
218        pWeight.add(pWeightTons);
219        pOptional.add(pWeight);
220
221        // row 8 for cars
222        pOptional.add(pColor);
223        pColor.setVisible(false);
224
225        // row 9 for cars
226        pOptional.add(pLoad);
227        pLoad.setVisible(false);
228
229        // for engines
230        pOptional.add(pPower);
231        pPower.setVisible(false);
232
233        // row 10
234        pGroup.setLayout(new GridBagLayout());
235        addItem(pGroup, groupComboBox, 1, 0);
236        addItem(pGroup, editGroupButton, 2, 0);
237        pOptional.add(pGroup);
238
239        // row 11
240        JPanel pBuilt = new JPanel();
241        pBuilt.setLayout(new GridBagLayout());
242        pBuilt.setBorder(BorderFactory.createTitledBorder(Bundle.getMessage("Built")));
243        addItem(pBuilt, builtTextField, 1, 0);
244        pOptional.add(pBuilt);
245
246        // row 12
247        JPanel pOwner = new JPanel();
248        pOwner.setLayout(new GridBagLayout());
249        pOwner.setBorder(BorderFactory.createTitledBorder(Bundle.getMessage("Owner")));
250        addItem(pOwner, ownerComboBox, 1, 0);
251        addItem(pOwner, editOwnerButton, 2, 0);
252        pOptional.add(pOwner);
253
254        // row 13
255        if (Setup.isValueEnabled()) {
256            JPanel pValue = new JPanel();
257            pValue.setLayout(new GridBagLayout());
258            pValue.setBorder(BorderFactory.createTitledBorder(Setup.getValueLabel()));
259            addItem(pValue, valueScroller, 1, 0);
260            pOptional.add(pValue);
261
262            // adjust text area width based on window size
263            adjustTextAreaColumnWidth(valueScroller, valueTextArea);
264        }
265
266        // row 14
267        IdTagManager tagManager = InstanceManager.getNullableDefault(IdTagManager.class);
268        if (Setup.isRfidEnabled() && tagManager != null) {
269            JPanel pRfid = new JPanel();
270            pRfid.setLayout(new GridBagLayout());
271            pRfid.setBorder(BorderFactory.createTitledBorder(Setup.getRfidLabel()));
272            rfidComboBox = new NamedBeanComboBox<IdTag>(tagManager);
273            rfidComboBox.setAllowNull(true);
274            rfidComboBox.setToolTipText(Bundle.getMessage("TipIdTag"));
275            addItem(pRfid, rfidComboBox, 0, 0);
276            addItem(pRfid, textRfidSystemName, 1, 0);
277            pOptional.add(pRfid);
278        }
279
280        // row 15
281        JPanel pComment = new JPanel();
282        pComment.setLayout(new GridBagLayout());
283        pComment.setBorder(BorderFactory.createTitledBorder(Bundle.getMessage("Comment")));
284        addItem(pComment, commentTextField, 1, 0);
285        pOptional.add(pComment);
286
287        // button panel
288        JPanel pButtons = new JPanel();
289        pButtons.setLayout(new GridBagLayout());
290        addItem(pButtons, deleteButton, 0, 25);
291        addItem(pButtons, addButton, 1, 25);
292        addItem(pButtons, saveButton, 3, 25);
293
294        // add panels
295        getContentPane().setLayout(new BoxLayout(getContentPane(), BoxLayout.Y_AXIS));
296        getContentPane().add(pPanel);
297        getContentPane().add(optionPane);
298        getContentPane().add(pButtons);
299
300        // setup buttons
301        addEditButtonAction(editRoadButton);
302        addEditButtonAction(editTypeButton);
303        addEditButtonAction(editLengthButton);
304        addEditButtonAction(editGroupButton);
305        addEditButtonAction(editOwnerButton);
306
307        addButtonAction(clearRoadNumberButton);
308        addButtonAction(deleteButton);
309        addButtonAction(addButton);
310        addButtonAction(saveButton);
311
312        // setup combobox
313        addComboBoxAction(typeComboBox);
314        addComboBoxAction(lengthComboBox);
315        addComboBoxAction(locationBox);
316
317        addCheckBoxAction(autoTrackCheckBox);
318        autoTrackCheckBox.setEnabled(false);
319
320        // get notified if combo box gets modified
321        addPropertyChangeListeners();
322
323        initMinimumSize(new Dimension(Control.panelWidth500, Control.panelHeight500));
324    }
325
326    protected void load(RollingStock rs) {
327        _rs = rs;
328
329        // engines and cars share the same road database
330        if (!InstanceManager.getDefault(CarRoads.class).containsName(rs.getRoadName())) {
331            if (JmriJOptionPane.showConfirmDialog(this,
332                    Bundle.getMessage("roadNameNotExist", rs.getRoadName()),
333                    Bundle.getMessage("addRoad"), JmriJOptionPane.YES_NO_OPTION) == JmriJOptionPane.YES_OPTION) {
334                InstanceManager.getDefault(CarRoads.class).addName(rs.getRoadName());
335            }
336        }
337        roadComboBox.setSelectedItem(rs.getRoadName());
338
339        roadNumberTextField.setText(rs.getNumber());
340
341        if (!getTypeManager().containsName(rs.getTypeName())) {
342            if (JmriJOptionPane.showConfirmDialog(this,
343                    Bundle.getMessage("typeNameNotExist", rs.getTypeName()),
344                    Bundle.getMessage("addType"), JmriJOptionPane.YES_NO_OPTION) == JmriJOptionPane.YES_OPTION) {
345                getTypeManager().addName(rs.getTypeName());
346            }
347        }
348        typeComboBox.setSelectedItem(rs.getTypeName());
349        blockingTextField.setText(Integer.toString(rs.getBlocking()));
350
351        if (!getLengthManager().containsName(rs.getLength())) {
352            if (JmriJOptionPane.showConfirmDialog(this,
353                    Bundle.getMessage("lengthNameNotExist", rs.getLength()),
354                    Bundle.getMessage("addLength"), JmriJOptionPane.YES_NO_OPTION) == JmriJOptionPane.YES_OPTION) {
355                getLengthManager().addName(rs.getLength());
356            }
357        }
358        // }
359        lengthComboBox.setSelectedItem(rs.getLength());
360
361        weightTextField.setText(rs.getWeight());
362        weightTonsTextField.setText(rs.getWeightTons());
363        locationBox.setSelectedItem(rs.getLocation());
364        updateTrackLocationBox();
365
366        builtTextField.setText(rs.getBuilt());
367
368        // Engines and cars share the owner database
369        if (!InstanceManager.getDefault(CarOwners.class).containsName(rs.getOwnerName())) {
370            if (JmriJOptionPane.showConfirmDialog(this,
371                    Bundle.getMessage("ownerNameNotExist", rs.getOwnerName()),
372                    Bundle.getMessage("addOwner"), JmriJOptionPane.YES_NO_OPTION) == JmriJOptionPane.YES_OPTION) {
373                InstanceManager.getDefault(CarOwners.class).addName(rs.getOwnerName());
374            }
375        }
376        ownerComboBox.setSelectedItem(rs.getOwnerName());
377
378        commentTextField.setText(rs.getComment());
379        valueTextArea.setText(rs.getValue());
380        if (rfidComboBox != null) {
381            rfidComboBox.setSelectedItem(rs.getIdTag());
382            textRfidSystemName.setText(rs.getRfid());
383        }
384        // enable delete and save buttons
385        deleteButton.setEnabled(true);
386        saveButton.setEnabled(true);
387        autoTrackCheckBox.setEnabled(true);
388    }
389
390    @Override
391    public void comboBoxActionPerformed(java.awt.event.ActionEvent ae) {
392        if (ae.getSource() == typeComboBox && typeComboBox.getSelectedItem() != null) {
393            // turn off auto for location tracks
394            autoTrackCheckBox.setSelected(false);
395            autoTrackCheckBox.setEnabled(false);
396            updateTrackLocationBox();
397        }
398        if (ae.getSource() == locationBox) {
399            updateTrackLocationBox();
400        }
401    }
402
403    @Override
404    public void checkBoxActionPerformed(java.awt.event.ActionEvent ae) {
405        if (ae.getSource() == autoTrackCheckBox) {
406            updateTrackLocationBox();
407        }
408    }
409
410    // Save, Delete, Add, Clear, Calculate, Edit Load buttons
411    @Override
412    public void buttonActionPerformed(java.awt.event.ActionEvent ae) {
413        if (ae.getSource() == saveButton) {
414            // log.debug("car save button pressed");
415            if (!check(_rs)) {
416                return;
417            }
418            save(IS_SAVE);
419            // save car file
420            OperationsXml.save();
421            if (Setup.isCloseWindowOnSaveEnabled()) {
422                dispose();
423            }
424        }
425        if (ae.getSource() == addButton) {
426            if (!check(null)) {
427                return;
428            }
429
430            // enable delete and save buttons
431            deleteButton.setEnabled(true);
432            saveButton.setEnabled(true);
433
434            save(!IS_SAVE);
435            // save car file
436            OperationsXml.save();
437        }
438        if (ae.getSource() == deleteButton) {
439            log.debug("rolling stock delete button activated");
440            // disable delete and save buttons
441            deleteButton.setEnabled(false);
442            saveButton.setEnabled(false);
443            if (_rs != null) {
444                _rs.removePropertyChangeListener(this);
445            }
446            delete();
447            _rs = null;
448            OperationsXml.save();
449        }
450        if (ae.getSource() == clearRoadNumberButton) {
451            roadNumberTextField.setText("");
452            roadNumberTextField.requestFocus();
453        }
454    }
455
456    protected void updateTrackLocationBox() {
457        if (locationBox.getSelectedItem() == null) {
458            trackLocationBox.removeAllItems();
459        } else {
460            log.debug("Update tracks for location: {}", locationBox.getSelectedItem());
461            Location loc = ((Location) locationBox.getSelectedItem());
462            loc.updateComboBox(trackLocationBox, _rs, autoTrackCheckBox.isSelected(), false);
463            if (_rs != null && _rs.getLocation() == loc) {
464                trackLocationBox.setSelectedItem(_rs.getTrack());
465            }
466        }
467    }
468
469    protected boolean check(RollingStock rs) {
470        String roadNum = roadNumberTextField.getText();
471        // hyphen feature needs at least one character to work properly        
472        if (roadNum.contains(TrainCommon.HYPHEN) && roadNum.split(TrainCommon.HYPHEN).length == 0) {
473            JmriJOptionPane.showMessageDialog(this, Bundle.getMessage("HyphenFeature"), Bundle.getMessage("roadNumNG"),
474                    JmriJOptionPane.ERROR_MESSAGE);
475            return false;
476        }
477        // ignore characters after hyphen for field length
478        String rNum = TrainCommon.splitString(roadNum);
479        if (rNum.length() > Control.max_len_string_road_number) {
480            JmriJOptionPane.showMessageDialog(this,
481                    MessageFormat.format(getRb().getString("RoadNumMustBeLess"),
482                            new Object[] { Control.max_len_string_road_number + 1 }),
483                    getRb().getString("RoadNumTooLong"), JmriJOptionPane.ERROR_MESSAGE);
484            return false;
485        }
486        if (!OperationsXml.checkFileName(roadNum)) {
487            JmriJOptionPane.showMessageDialog(this,
488                    Bundle.getMessage("NameResChar") + NEW_LINE + Bundle.getMessage("ReservedChar"),
489                    Bundle.getMessage("roadNumNG"), JmriJOptionPane.ERROR_MESSAGE);
490            return false;
491        }
492        // check rolling stock's weight in tons has proper format
493        if (!weightTonsTextField.getText().trim().isEmpty()) {
494            try {
495                Integer.parseInt(weightTonsTextField.getText());
496            } catch (Exception e) {
497                JmriJOptionPane.showMessageDialog(this, getRb().getString("WeightFormatTon"),
498                        getRb().getString("WeightTonError"), JmriJOptionPane.ERROR_MESSAGE);
499                return false;
500            }
501        }
502        return true;
503    }
504
505    protected <T extends RollingStock> void save(RollingStockManager<T> manager, boolean isSave) {
506        // if the rolling stock's road or number changes, it needs a new id
507        if (isSave &&
508                _rs != null &&
509                (!_rs.getRoadName().equals(roadComboBox.getSelectedItem()) ||
510                        !_rs.getNumber().equals(roadNumberTextField.getText()))) {
511            String road = (String) roadComboBox.getSelectedItem();
512            String number = roadNumberTextField.getText();
513            _rs.setRoadName(road);
514            _rs.setNumber(number);
515        }
516        if (_rs == null ||
517                !_rs.getRoadName().equals(roadComboBox.getSelectedItem()) ||
518                !_rs.getNumber().equals(roadNumberTextField.getText())) {
519            _rs = manager.newRS((String) roadComboBox.getSelectedItem(), roadNumberTextField.getText());
520            _rs.addPropertyChangeListener(this);
521        }
522        // engine model must be set before type, length, weight and HP
523        if (Engine.class.isInstance(_rs) && modelComboBox.getSelectedItem() != null) {
524            ((Engine) _rs).setModel((String) modelComboBox.getSelectedItem());
525        }
526        if (typeComboBox.getSelectedItem() != null) {
527            _rs.setTypeName((String) typeComboBox.getSelectedItem());
528        }
529
530        int blocking = RollingStock.DEFAULT_BLOCKING_ORDER;
531        try {
532            blocking = Integer.parseInt(blockingTextField.getText());
533            // only allow numbers between -100 and 100
534            if (blocking < -RollingStock.MAX_BLOCKING_ORDER || blocking > RollingStock.MAX_BLOCKING_ORDER) {
535                blocking = RollingStock.DEFAULT_BLOCKING_ORDER;
536            }
537        } catch (Exception e) {
538            log.warn("Blocking must be a number between -{} and {}", RollingStock.MAX_BLOCKING_ORDER,
539                    RollingStock.MAX_BLOCKING_ORDER);
540        }
541        blockingTextField.setText(Integer.toString(blocking));
542
543        if (lengthComboBox.getSelectedItem() != null) {
544            _rs.setLength((String) lengthComboBox.getSelectedItem());
545        }
546        try {
547            _rs.setWeight(NumberFormat.getNumberInstance().parse(weightTextField.getText()).toString());
548        } catch (ParseException e1) {
549            log.debug("Weight not a number");
550        }
551        _rs.setWeightTons(weightTonsTextField.getText());
552        _rs.setBuilt(builtTextField.getText());
553        if (ownerComboBox.getSelectedItem() != null) {
554            _rs.setOwnerName((String) ownerComboBox.getSelectedItem());
555        }
556        _rs.setComment(commentTextField.getText());
557        _rs.setValue(valueTextArea.getText());
558        if (rfidComboBox != null) {
559            // save the IdTag for this rolling stock
560            _rs.setIdTag(rfidComboBox.getSelectedItem());
561            textRfidSystemName.setText(_rs.getRfid());
562        }
563        autoTrackCheckBox.setEnabled(true);
564    }
565    
566    protected void checkAndSetLocationAndTrack(RollingStock rs) {
567        if (locationBox.getSelectedItem() != null && trackLocationBox.getSelectedItem() == null) {
568            JmriJOptionPane.showMessageDialog(this, getRb().getString("rsFullySelect"), getRb().getString("rsCanNotLoc"),
569                    JmriJOptionPane.ERROR_MESSAGE);
570            // update location only if it has changed
571        } else if (rs.getLocation() == null ||
572                !rs.getLocation().equals(locationBox.getSelectedItem()) ||
573                rs.getTrack() == null ||
574                !rs.getTrack().equals(trackLocationBox.getSelectedItem())) {
575            setLocationAndTrack(rs);
576        }
577    }
578
579    protected void setLocationAndTrack(RollingStock rs) {
580        if (locationBox.getSelectedItem() == null) {
581            rs.setLocation(null, null);
582        } else {
583            rs.setLastRouteId(RollingStock.NONE); // clear last route id
584            String status = rs.setLocation((Location) locationBox.getSelectedItem(),
585                    (Track) trackLocationBox.getSelectedItem());
586            if (!status.equals(Track.OKAY)) {
587                log.debug("Can't set rolling stock's location because of {}", status);
588                JmriJOptionPane.showMessageDialog(this,
589                        MessageFormat.format(getRb().getString("rsCanNotLocMsg"),
590                                new Object[] { rs.toString(), status }),
591                        getRb().getString("rsCanNotLoc"), JmriJOptionPane.ERROR_MESSAGE);
592                // does the user want to force the rolling stock to this track?
593                int results = JmriJOptionPane.showOptionDialog(this,
594                        MessageFormat.format(getRb().getString("rsForce"),
595                                new Object[] { rs.toString(), (Track) trackLocationBox.getSelectedItem() }),
596                        MessageFormat.format(getRb().getString("rsOverride"), new Object[] { status }),
597                        JmriJOptionPane.YES_NO_OPTION, JmriJOptionPane.QUESTION_MESSAGE, null, null, null);
598                if (results == JmriJOptionPane.YES_OPTION) {
599                    log.debug("Force rolling stock to track");
600                    rs.setLocation((Location) locationBox.getSelectedItem(), (Track) trackLocationBox.getSelectedItem(),
601                            RollingStock.FORCE);
602                }
603            }
604        }
605    }
606
607    // for the AttributeEditFrame edit buttons
608    protected void addEditButtonAction(JButton b) {
609        b.addActionListener(new java.awt.event.ActionListener() {
610            @Override
611            public void actionPerformed(java.awt.event.ActionEvent e) {
612                buttonEditActionPerformed(e);
613            }
614        });
615    }
616
617    @Override
618    public void dispose() {
619        removePropertyChangeListeners();
620        super.dispose();
621    }
622
623    protected void addPropertyChangeListeners() {
624        InstanceManager.getDefault(CarRoads.class).addPropertyChangeListener(this);
625        getTypeManager().addPropertyChangeListener(this);
626        getLengthManager().addPropertyChangeListener(this);
627        InstanceManager.getDefault(CarOwners.class).addPropertyChangeListener(this);
628        locationManager.addPropertyChangeListener(this);
629    }
630
631    protected void removePropertyChangeListeners() {
632        InstanceManager.getDefault(CarRoads.class).removePropertyChangeListener(this);
633        getTypeManager().removePropertyChangeListener(this);
634        getLengthManager().removePropertyChangeListener(this);
635        InstanceManager.getDefault(CarOwners.class).removePropertyChangeListener(this);
636        locationManager.removePropertyChangeListener(this);
637    }
638
639    @Override
640    public void propertyChange(java.beans.PropertyChangeEvent e) {
641        if (e.getPropertyName().equals(CarRoads.CARROADS_CHANGED_PROPERTY)) {
642            InstanceManager.getDefault(CarRoads.class).updateComboBox(roadComboBox);
643            if (_rs != null) {
644                roadComboBox.setSelectedItem(_rs.getRoadName());
645            }
646        }
647        if (e.getPropertyName().equals(CarTypes.CARTYPES_CHANGED_PROPERTY) ||
648                e.getPropertyName().equals(EngineTypes.ENGINETYPES_CHANGED_PROPERTY)) {
649            getTypeManager().updateComboBox(typeComboBox);
650            if (_rs != null) {
651                typeComboBox.setSelectedItem(_rs.getTypeName());
652            }
653        }
654        if (e.getPropertyName().equals(CarOwners.CAROWNERS_CHANGED_PROPERTY)) {
655            InstanceManager.getDefault(CarOwners.class).updateComboBox(ownerComboBox);
656            if (_rs != null) {
657                ownerComboBox.setSelectedItem(_rs.getOwnerName());
658            }
659        }
660        if (e.getPropertyName().equals(LocationManager.LISTLENGTH_CHANGED_PROPERTY) ||
661                e.getPropertyName().equals(RollingStock.TRACK_CHANGED_PROPERTY)) {
662            InstanceManager.getDefault(LocationManager.class).updateComboBox(locationBox);
663            updateTrackLocationBox();
664            if (_rs != null && _rs.getLocation() != null) {
665                locationBox.setSelectedItem(_rs.getLocation());
666            }
667        }
668    }
669
670    private static final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(RollingStockEditFrame.class);
671}