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