001package jmri.jmrit.operations.rollingstock.engines;
002
003import java.awt.GridBagLayout;
004import java.util.List;
005import java.util.ResourceBundle;
006
007import javax.swing.*;
008
009import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
010import jmri.InstanceManager;
011import jmri.jmrit.operations.rollingstock.*;
012import jmri.jmrit.operations.rollingstock.engines.tools.EngineAttributeEditFrame;
013import jmri.jmrit.operations.setup.Control;
014import jmri.util.swing.JmriJOptionPane;
015
016/**
017 * Frame for user edit of engine
018 *
019 * @author Dan Boudreau Copyright (C) 2008, 2011, 2018
020 */
021public class EngineEditFrame extends RollingStockEditFrame {
022
023    protected static final ResourceBundle rb = ResourceBundle
024            .getBundle("jmri.jmrit.operations.rollingstock.engines.JmritOperationsEnginesBundle");
025
026    EngineManager engineManager = InstanceManager.getDefault(EngineManager.class);
027    EngineManagerXml managerXml = InstanceManager.getDefault(EngineManagerXml.class);
028    EngineModels engineModels = InstanceManager.getDefault(EngineModels.class);
029
030    JButton editModelButton = new JButton(Bundle.getMessage("ButtonEdit"));
031
032    JCheckBox bUnitCheckBox = new JCheckBox(Bundle.getMessage("BUnit"));
033
034    JTextField hpTextField = new JTextField(8);
035    JTextField teTextField = new JTextField(8);
036
037    private static final String SPEED = "25"; // MPH for tractive effort to HP conversion
038
039    EngineAttributeEditFrame engineAttributeEditFrame;
040
041    public EngineEditFrame() {
042        super(Bundle.getMessage("TitleEngineAdd"));
043    }
044
045    @SuppressFBWarnings(value = "NP_NULL_ON_SOME_PATH_FROM_RETURN_VALUE", justification = "Checks for null")
046    @Override
047    public void initComponents() {
048
049        groupComboBox = InstanceManager.getDefault(ConsistManager.class).getComboBox();
050        modelComboBox = engineModels.getComboBox();
051
052        super.initComponents();
053
054        addButton.setText(Bundle.getMessage("TitleEngineAdd"));
055
056        // type options for engines
057        addItem(pTypeOptions, bUnitCheckBox, 0, 1);
058
059        // default check box selections
060        bUnitCheckBox.setSelected(false);
061
062        // load tool tips
063        builtTextField.setToolTipText(Bundle.getMessage("TipBuildDate"));
064        editModelButton.setToolTipText(Bundle.getMessage("TipAddDeleteReplace",
065                Bundle.getMessage("Model").toLowerCase()));
066        editGroupButton.setToolTipText(Bundle.getMessage("TipAddDeleteReplace",
067                Bundle.getMessage("Consist").toLowerCase()));
068        bUnitCheckBox.setToolTipText(Bundle.getMessage("TipBoosterUnit"));
069
070        deleteButton.setToolTipText(Bundle.getMessage("TipDeleteButton"));
071        addButton.setToolTipText(Bundle.getMessage("TipAddButton"));
072        saveButton.setToolTipText(Bundle.getMessage("TipSaveButton"));
073
074        // row 3
075        pModel.setLayout(new GridBagLayout());
076        pModel.setBorder(BorderFactory.createTitledBorder(Bundle.getMessage("Model")));
077        addItem(pModel, modelComboBox, 1, 0);
078        addItem(pModel, editModelButton, 2, 0);
079        pModel.setVisible(true);
080
081        // row 12
082        pPower.setLayout(new BoxLayout(pPower, BoxLayout.X_AXIS));
083        JPanel pHp = new JPanel();
084        pHp.setLayout(new GridBagLayout());
085        pHp.setBorder(BorderFactory.createTitledBorder(Bundle.getMessage("Hp")));
086        addItem(pHp, hpTextField, 0, 0);
087        JPanel pTe = new JPanel();
088        pTe.setLayout(new GridBagLayout());
089        pTe.setBorder(BorderFactory.createTitledBorder(Bundle.getMessage("TractiveEffort")));
090        addItem(pTe, teTextField, 0, 0);
091        pPower.add(pHp);
092        pPower.add(pTe);
093        pPower.setVisible(true);
094
095        teTextField.setToolTipText(Bundle.getMessage("TipConvertTE-HP", SPEED));
096
097        pGroup.setBorder(BorderFactory.createTitledBorder(Bundle.getMessage("Consist")));
098
099        addEditButtonAction(editModelButton);
100
101        addComboBoxAction(modelComboBox);
102        modelComboBox.setSelectedIndex(0);
103
104        addHelpMenu("package.jmri.jmrit.operations.Operations_LocomotivesAdd", true); // NOI18N
105    }
106
107    @Override
108    protected ResourceBundle getRb() {
109        return rb;
110    }
111
112    @Override
113    protected RollingStockAttribute getTypeManager() {
114        return InstanceManager.getDefault(EngineTypes.class);
115    }
116
117    @Override
118    protected RollingStockAttribute getLengthManager() {
119        return InstanceManager.getDefault(EngineLengths.class);
120    }
121
122    public void load(Engine engine) {
123        setTitle(Bundle.getMessage("TitleEngineEdit"));
124        
125        if (!engineModels.containsName(engine.getModel())) {
126            String msg = Bundle.getMessage("modelNameNotExist",
127                    engine.getModel());
128            if (JmriJOptionPane.showConfirmDialog(this, msg, Bundle.getMessage("engineAddModel"),
129                    JmriJOptionPane.YES_NO_OPTION) == JmriJOptionPane.YES_OPTION) {
130                engineModels.addName(engine.getModel());
131            }
132        }
133        modelComboBox.setSelectedItem(engine.getModel());
134
135        super.load(engine);
136
137        pBlocking.setVisible(engine.getConsist() != null);
138        blockingTextField.setEnabled(false); // don't allow user to modify, only see
139        bUnitCheckBox.setSelected(engine.isBunit());
140        hpTextField.setText(engine.getHp());
141        groupComboBox.setSelectedItem(engine.getConsistName());
142    }
143
144    // combo boxes
145    @Override
146    public void comboBoxActionPerformed(java.awt.event.ActionEvent ae) {
147        if (ae.getSource() == modelComboBox) {
148            if (modelComboBox.getSelectedItem() != null) {
149                String model = (String) modelComboBox.getSelectedItem();
150                // load the default hp and length for the model selected
151                hpTextField.setText(engineModels.getModelHorsepower(model));
152                weightTonsTextField.setText(engineModels.getModelWeight(model));
153                if (engineModels.getModelLength(model) != null && !engineModels.getModelLength(model).isEmpty()) {
154                    lengthComboBox.setSelectedItem(engineModels.getModelLength(model));
155                }
156                if (engineModels.getModelType(model) != null && !engineModels.getModelType(model).isEmpty()) {
157                    typeComboBox.setSelectedItem(engineModels.getModelType(model));
158                }
159            }
160        }
161        super.comboBoxActionPerformed(ae);
162    }
163
164    @Override
165    protected boolean check(RollingStock engine) {
166        // check to see if engine with road and number already exists
167        Engine existingEngine = engineManager.getByRoadAndNumber((String) roadComboBox.getSelectedItem(),
168                roadNumberTextField.getText());
169        if (existingEngine != null) {
170            if (engine == null || !existingEngine.getId().equals(engine.getId())) {
171                JmriJOptionPane.showMessageDialog(this, Bundle.getMessage("engineExists"),
172                        Bundle.getMessage("engineCanNotUpdate"), JmriJOptionPane.ERROR_MESSAGE);
173                return false;
174            }
175        }
176        return super.check(engine);
177    }
178
179    @Override
180    protected void save(boolean isSave) {
181        super.save(engineManager, isSave);
182        Engine engine = (Engine) _rs;
183        
184        checkAndSetLocationAndTrack(engine);
185
186        engine.setBunit(bUnitCheckBox.isSelected());
187
188        if (groupComboBox.getSelectedItem() != null) {
189            if (groupComboBox.getSelectedItem().equals(EngineManager.NONE)) {
190                engine.setConsist(null);
191                engine.setBlocking(Engine.DEFAULT_BLOCKING_ORDER);
192            } else if (!engine.getConsistName().equals(groupComboBox.getSelectedItem())) {
193                engine.setConsist(InstanceManager.getDefault(ConsistManager.class).getConsistByName((String) groupComboBox.getSelectedItem()));
194                if (engine.getConsist() != null) {
195                    engine.setBlocking(engine.getConsist().getSize());
196                    blockingTextField.setText(Integer.toString(engine.getBlocking()));
197                }
198            }
199        }
200        pBlocking.setVisible(engine.getConsist() != null);
201
202        convertTractiveEffortToHp();
203        // confirm that horsepower is a number
204        if (!hpTextField.getText().trim().isEmpty()) {
205            try {
206                Integer.parseInt(hpTextField.getText());
207                engine.setHp(hpTextField.getText());
208            } catch (Exception e) {
209                JmriJOptionPane.showMessageDialog(this, Bundle.getMessage("engineHorsepower"),
210                        Bundle.getMessage("engineCanNotHp"), JmriJOptionPane.ERROR_MESSAGE);
211            }
212        }
213        
214        // is this engine part of a consist? Ask if all engines should have the same location and track
215        if (engine.getConsist() != null) {
216            List<Engine> engines = engine.getConsist().getEngines();
217            for (Engine cEngine : engines) {
218                if (cEngine != engine) {
219                    if (cEngine.getLocation() != engine.getLocation() || cEngine.getTrack() != engine.getTrack()) {
220                        int results = JmriJOptionPane.showConfirmDialog(this, Bundle
221                                .getMessage("engineInConsistLocation",
222                                engine.toString(), engine.getLocationName(), engine.getTrackName()),
223                                Bundle.getMessage("enginePartConsist"),
224                                JmriJOptionPane.YES_NO_OPTION);
225                        if (results == JmriJOptionPane.YES_OPTION) {
226                            // change the location for all engines in consist
227                            for (Engine cEngine2 : engines) {
228                                if (cEngine2 != engine) {
229                                    setLocationAndTrack(cEngine2);
230                                }
231                            }
232                        }
233                        break; // done
234                    }
235                }
236            }
237        }
238    }
239
240    @Override
241    protected void delete() {
242        Engine engine = engineManager.getByRoadAndNumber((String) roadComboBox.getSelectedItem(),
243                roadNumberTextField.getText());
244        if (engine != null) {
245            engineManager.deregister(engine);
246        }
247    }
248
249    // edit buttons only one frame active at a time
250    @Override
251    public void buttonEditActionPerformed(java.awt.event.ActionEvent ae) {
252        if (engineAttributeEditFrame != null) {
253            engineAttributeEditFrame.dispose();
254        }
255        engineAttributeEditFrame = new EngineAttributeEditFrame();
256        engineAttributeEditFrame.setLocationRelativeTo(this);
257        engineAttributeEditFrame.addPropertyChangeListener(this);
258
259        if (ae.getSource() == editRoadButton) {
260            engineAttributeEditFrame.initComponents(EngineAttributeEditFrame.ROAD,
261                    (String) roadComboBox.getSelectedItem());
262        }
263        if (ae.getSource() == editModelButton) {
264            engineAttributeEditFrame.initComponents(EngineAttributeEditFrame.MODEL,
265                    (String) modelComboBox.getSelectedItem());
266        }
267        if (ae.getSource() == editTypeButton) {
268            engineAttributeEditFrame.initComponents(EngineAttributeEditFrame.TYPE,
269                    (String) typeComboBox.getSelectedItem());
270        }
271        if (ae.getSource() == editLengthButton) {
272            engineAttributeEditFrame.initComponents(EngineAttributeEditFrame.LENGTH,
273                    (String) lengthComboBox.getSelectedItem());
274        }
275        if (ae.getSource() == editOwnerButton) {
276            engineAttributeEditFrame.initComponents(EngineAttributeEditFrame.OWNER,
277                    (String) ownerComboBox.getSelectedItem());
278        }
279        if (ae.getSource() == editGroupButton) {
280            engineAttributeEditFrame.initComponents(EngineAttributeEditFrame.CONSIST,
281                    (String) groupComboBox.getSelectedItem());
282        }
283    }
284
285    /**
286     * Converts tractive effort to HP using the formula: HP = TE * MPH / 375. MPH
287     * set at 25, see SPEED. 60% conversion efficiency to produce reasonable HP values.
288     */
289    private void convertTractiveEffortToHp() {
290        String TE = teTextField.getText().trim();
291        if (!TE.isEmpty()) {
292            TE = TE.replace(",", "");
293            int te = 0;
294            try {
295                te = Integer.parseInt(TE);
296            } catch (Exception e) {
297                log.error("Not able to convert TE {} to HP", teTextField.getText());
298            }
299            if (te > 0) {
300                int hp = te * Integer.parseInt(SPEED) / 625;
301                hpTextField.setText(Integer.toString(hp));
302            }
303        }
304    }
305
306    @Override
307    protected void addPropertyChangeListeners() {
308        InstanceManager.getDefault(ConsistManager.class).addPropertyChangeListener(this);
309        engineModels.addPropertyChangeListener(this);
310        engineManager.addPropertyChangeListener(this);
311        super.addPropertyChangeListeners();
312    }
313
314    @Override
315    protected void removePropertyChangeListeners() {
316        InstanceManager.getDefault(ConsistManager.class).removePropertyChangeListener(this);
317        engineModels.removePropertyChangeListener(this);
318        engineManager.removePropertyChangeListener(this);
319        if (_rs != null) {
320            _rs.removePropertyChangeListener(this);
321        }
322        super.removePropertyChangeListeners();
323    }
324
325    @Override
326    public void propertyChange(java.beans.PropertyChangeEvent e) {
327        if (Control.SHOW_PROPERTY) {
328            log.debug("Property change: ({}) old: ({}) new: ({})", e.getPropertyName(), e.getOldValue(),
329                    e.getNewValue());
330        }
331        super.propertyChange(e);
332
333        if (e.getPropertyName().equals(EngineLengths.ENGINELENGTHS_CHANGED_PROPERTY)) {
334            InstanceManager.getDefault(EngineLengths.class).updateComboBox(lengthComboBox);
335            if (_rs != null) {
336                lengthComboBox.setSelectedItem(_rs.getLength());
337            }
338        }
339        if (e.getPropertyName().equals(EngineModels.ENGINEMODELS_CHANGED_PROPERTY)) {
340            engineModels.updateComboBox(modelComboBox);
341            if (_rs != null) {
342                modelComboBox.setSelectedItem(((Engine) _rs).getModel());
343            }
344        }
345        if (e.getPropertyName().equals(ConsistManager.LISTLENGTH_CHANGED_PROPERTY)) {
346            InstanceManager.getDefault(ConsistManager.class).updateComboBox(groupComboBox);
347            if (_rs != null) {
348                groupComboBox.setSelectedItem(((Engine) _rs).getConsistName());
349            }
350        }
351        if (e.getPropertyName().equals(EngineAttributeEditFrame.DISPOSE)) {
352            engineAttributeEditFrame = null;
353        }
354    }
355
356    private static final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(EngineEditFrame.class);
357
358}