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