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