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