001package jmri.jmrit.operations.rollingstock.cars.tools;
002
003import java.awt.Dimension;
004import java.awt.GridBagLayout;
005
006import javax.swing.*;
007
008import jmri.InstanceManager;
009import jmri.jmrit.operations.OperationsFrame;
010import jmri.jmrit.operations.OperationsXml;
011import jmri.jmrit.operations.locations.LocationManager;
012import jmri.jmrit.operations.locations.schedules.ScheduleManager;
013import jmri.jmrit.operations.rollingstock.cars.*;
014import jmri.jmrit.operations.setup.Control;
015import jmri.jmrit.operations.setup.Setup;
016import jmri.jmrit.operations.trains.TrainCommon;
017import jmri.jmrit.operations.trains.TrainManager;
018import jmri.util.swing.JmriJOptionPane;
019
020/**
021 * Frame for adding and editing the car load attribute for operations.
022 *
023 * @author Daniel Boudreau Copyright (C) 2009, 2010, 2011, 2023
024 */
025public class CarLoadEditFrame extends OperationsFrame implements java.beans.PropertyChangeListener {
026
027    CarLoads carLoads = InstanceManager.getDefault(CarLoads.class);
028    CarTypes carTypes = InstanceManager.getDefault(CarTypes.class);
029
030    // labels
031    JLabel textSep = new JLabel();
032    JLabel quanity = new JLabel("0");
033
034    // major buttons
035    JButton addButton = new JButton(Bundle.getMessage("Add"));
036    JButton deleteButton = new JButton(Bundle.getMessage("ButtonDelete"));
037    JButton replaceButton = new JButton(Bundle.getMessage("Replace"));
038    JButton saveButton = new JButton(Bundle.getMessage("ButtonSave"));
039
040    // combo boxes
041    JComboBox<String> typeComboBox = carTypes.getComboBox();
042    JComboBox<String> loadComboBox;
043    JComboBox<String> priorityComboBox = carLoads.getPriorityComboBox();
044    JComboBox<String> hazardousComboBox = carLoads.getHazardousComboBox();
045    JComboBox<String> loadTypeComboBox = carLoads.getLoadTypesComboBox();
046
047    // check boxes
048    JCheckBox allTypesCheckBox = new JCheckBox(Bundle.getMessage("All"));
049
050    // text boxes
051    JTextField addTextBox = new JTextField(Control.max_len_string_attibute);
052    JTextField pickupCommentTextField = new JTextField(35);
053    JTextField dropCommentTextField = new JTextField(35);
054
055    public CarLoadEditFrame() {
056        super(Bundle.getMessage("TitleCarEditLoad"));
057    }
058
059    String _type; // car type name
060    boolean menuActive = false;
061
062    public void initComponents(String type, String selectedItem) {
063
064        getContentPane().removeAll();
065
066        _type = type;
067        typeComboBox.setSelectedItem(_type);
068
069        loadComboBox = carLoads.getComboBox(_type);
070        carLoads.addPropertyChangeListener(this);
071        loadComboBox.setSelectedItem(selectedItem);
072        updateLoadType();
073        updatePriority();
074        updateHazardous();
075
076        // general GUI config
077        quanity.setVisible(showQuanity);
078
079        // car type panel
080        JPanel pType = new JPanel();
081        pType.setLayout(new GridBagLayout());
082        pType.setBorder(BorderFactory.createTitledBorder(Bundle.getMessage("Type")));
083        addItem(pType, typeComboBox, 0, 0);
084        addItem(pType, allTypesCheckBox, 1, 0);
085
086        allTypesCheckBox.setToolTipText(Bundle.getMessage("TipCarLoadAll"));
087
088        // load panel
089        JPanel pLoad = new JPanel();
090        pLoad.setLayout(new GridBagLayout());
091        pLoad.setBorder(BorderFactory.createTitledBorder(Bundle.getMessage("Load")));
092
093        // row 2
094        addItem(pLoad, addTextBox, 2, 2);
095        addItem(pLoad, addButton, 3, 2);
096
097        // row 3
098        addItem(pLoad, quanity, 1, 3);
099        addItem(pLoad, loadComboBox, 2, 3);
100        addItem(pLoad, deleteButton, 3, 3);
101
102        // row 4
103        addItem(pLoad, replaceButton, 3, 4);
104
105        deleteButton.setToolTipText(Bundle.getMessage("TipDeleteAttributeName",
106                Bundle.getMessage("Load")));
107        addButton.setToolTipText(Bundle.getMessage("TipAddAttributeName",
108                Bundle.getMessage("Load")));
109        replaceButton.setToolTipText(Bundle.getMessage("TipReplaceAttributeName",
110                Bundle.getMessage("Load")));
111
112        // row 6
113        JPanel pLoadType = new JPanel();
114        pLoadType.setLayout(new BoxLayout(pLoadType, BoxLayout.Y_AXIS));
115        pLoadType.setBorder(BorderFactory.createTitledBorder(Bundle.getMessage("BorderLayoutLoadType")));
116        addItem(pLoadType, loadTypeComboBox, 0, 0);
117
118        // row 8
119        JPanel pPriority = new JPanel();
120        pPriority.setLayout(new BoxLayout(pPriority, BoxLayout.Y_AXIS));
121        pPriority.setBorder(BorderFactory.createTitledBorder(Bundle.getMessage("BorderLayoutPriority")));
122        addItem(pPriority, priorityComboBox, 0, 0);
123
124        // row 9
125        JPanel pHazardous = new JPanel();
126        pHazardous.setLayout(new BoxLayout(pHazardous, BoxLayout.Y_AXIS));
127        pHazardous.setBorder(BorderFactory.createTitledBorder(Bundle.getMessage("Hazardous")));
128        addItem(pHazardous, hazardousComboBox, 0, 0);
129
130        // row 10
131        // optional panel
132        JPanel pOptionalPickup = new JPanel();
133        pOptionalPickup.setBorder(BorderFactory.createTitledBorder(Bundle.getMessage("BorderLayoutOptionalPickup")));
134        addItem(pOptionalPickup, pickupCommentTextField, 0, 0);
135
136        // row 12
137        JPanel pOptionalDrop = new JPanel();
138        pOptionalDrop.setBorder(BorderFactory.createTitledBorder(Bundle.getMessage("BorderLayoutOptionalDrop")));
139        addItem(pOptionalDrop, dropCommentTextField, 0, 0);
140
141        // row 14
142        JPanel pControl = new JPanel();
143        pControl.setLayout(new BoxLayout(pControl, BoxLayout.Y_AXIS));
144        addItem(pControl, saveButton, 0, 0);
145
146        // add panels
147        getContentPane().setLayout(new BoxLayout(getContentPane(), BoxLayout.Y_AXIS));
148        getContentPane().add(pType);
149        getContentPane().add(pLoad);
150        getContentPane().add(pLoadType);
151        getContentPane().add(pPriority);
152        getContentPane().add(pHazardous);
153        getContentPane().add(pOptionalPickup);
154        getContentPane().add(pOptionalDrop);
155        getContentPane().add(pControl);
156
157        addButtonAction(addButton);
158        addButtonAction(deleteButton);
159        addButtonAction(replaceButton);
160        addButtonAction(saveButton);
161
162        addComboBoxAction(typeComboBox);
163        addComboBoxAction(loadComboBox);
164
165        addCheckBoxAction(allTypesCheckBox);
166
167        updateCarCommentFields();
168
169        enableButtons();
170
171        // build menu
172        JMenuBar menuBar = new JMenuBar();
173        JMenu toolMenu = new JMenu(Bundle.getMessage("MenuTools"));
174        toolMenu.add(new CarLoadAttributeAction(this));
175        toolMenu.add(new PrintCarLoadsAction(true));
176        toolMenu.add(new PrintCarLoadsAction(false));
177        menuBar.add(toolMenu);
178        setJMenuBar(menuBar);
179        // add help menu to window
180        addHelpMenu("package.jmri.jmrit.operations.Operations_EditCarLoads", true); // NOI18N
181
182        initMinimumSize(new Dimension(Control.panelWidth400, Control.panelHeight500));
183    }
184
185    // add, delete, replace, and save buttons
186    @Override
187    public void buttonActionPerformed(java.awt.event.ActionEvent ae) {
188        String loadName = addTextBox.getText().trim();
189        if (ae.getSource() == addButton || ae.getSource() == replaceButton) {
190            if (!checkLoadName(loadName)) {
191                return;
192            }
193        }
194        if (ae.getSource() == addButton) {
195            addLoadName(loadName);
196        }
197        if (ae.getSource() == deleteButton) {
198            deleteLoadName();
199        }
200        if (ae.getSource() == replaceButton) {
201            replaceLoadName(loadName);
202        }
203        if (ae.getSource() == saveButton) {
204            saveLoadName();
205            OperationsXml.save(); // save all files that have been modified;
206            if (Setup.isCloseWindowOnSaveEnabled()) {
207                dispose();
208            }
209        }
210    }
211
212    private boolean checkLoadName(String loadName) {
213        if (loadName.equals(NONE)) {
214            return false;
215        }
216        String[] splitLoadName = loadName.split(TrainCommon.HYPHEN);
217        // hyphen feature needs at least one character to work properly
218        if (loadName.contains(TrainCommon.HYPHEN)) {
219            if (splitLoadName.length == 0) {
220                JmriJOptionPane.showMessageDialog(this, Bundle.getMessage("HyphenFeature"),
221                        Bundle.getMessage("canNotAdd", Bundle.getMessage("load")),
222                        JmriJOptionPane.ERROR_MESSAGE);
223                return false;
224            }
225        }
226        if (splitLoadName[0].length() > Control.max_len_string_attibute) {
227            JmriJOptionPane.showMessageDialog(this, Bundle.getMessage("carAttribute",
228                    Control.max_len_string_attibute), Bundle.getMessage("canNotUseLoadName"),
229                    JmriJOptionPane.ERROR_MESSAGE);
230            return false;
231        }
232        // can't have the " & " as part of the load name
233        if (loadName.contains(CarLoad.SPLIT_CHAR)) {
234            JmriJOptionPane.showMessageDialog(this, Bundle.getMessage("carNameNoAndChar",
235                    CarLoad.SPLIT_CHAR), Bundle.getMessage("canNotUseLoadName"),
236                    JmriJOptionPane.ERROR_MESSAGE);
237            return false;
238        }
239        return true;
240    }
241
242    @Override
243    protected void comboBoxActionPerformed(java.awt.event.ActionEvent ae) {
244        log.debug("Combo box action");
245        if (ae.getSource() == typeComboBox) {
246            _type = (String) typeComboBox.getSelectedItem();
247            updateLoadComboBox();
248            enableButtons();
249        }
250        updateCarQuanity();
251        updateLoadType();
252        updatePriority();
253        updateHazardous();
254        updateCarCommentFields();
255    }
256
257    @Override
258    protected void checkBoxActionPerformed(java.awt.event.ActionEvent ae) {
259        typeComboBox.setEnabled(!allTypesCheckBox.isSelected());
260    }
261
262    private void addLoadName(String loadName) {
263        if (allTypesCheckBox.isSelected()) {
264            for (String type : carTypes.getNames()) {
265                carLoads.addName(type, loadName);
266            }
267        } else {
268            carLoads.addName(_type, loadName);
269        }
270    }
271
272    private void deleteLoadName() {
273        String deleteLoad = (String) loadComboBox.getSelectedItem();
274        if (deleteLoad.equals(carLoads.getDefaultEmptyName()) || deleteLoad.equals(carLoads.getDefaultLoadName())) {
275            JmriJOptionPane.showMessageDialog(this, Bundle.getMessage("carLoadDefault"), Bundle
276                    .getMessage("canNotDelete", Bundle.getMessage("Load")),
277                    JmriJOptionPane.ERROR_MESSAGE);
278            return;
279        }
280        if (allTypesCheckBox.isSelected()) {
281            for (String type : carTypes.getNames()) {
282                replaceLoad(type, deleteLoad, null);
283                carLoads.deleteName(type, deleteLoad);
284            }
285        } else {
286            replaceLoad(_type, deleteLoad, null);
287            carLoads.deleteName(_type, deleteLoad);
288        }
289    }
290
291    private void replaceLoadName(String loadName) {
292        String oldLoadName = (String) loadComboBox.getSelectedItem();
293        if (oldLoadName.equals(carLoads.getDefaultEmptyName())) {
294            if (JmriJOptionPane.showConfirmDialog(this,
295                    Bundle.getMessage("replaceDefaultEmpty",
296                            oldLoadName, loadName),
297                    Bundle.getMessage("replaceAll"),
298                    JmriJOptionPane.YES_NO_OPTION) != JmriJOptionPane.YES_OPTION) {
299                return;
300            }
301            // don't allow the default names for load and empty to be the
302            // same
303            if (loadName.equals(carLoads.getDefaultEmptyName()) || loadName.equals(carLoads.getDefaultLoadName())) {
304                JmriJOptionPane.showMessageDialog(this, Bundle.getMessage("carDefault"), Bundle
305                        .getMessage("canNotReplace", Bundle.getMessage("Load")),
306                        JmriJOptionPane.ERROR_MESSAGE);
307                return;
308            }
309            carLoads.setDefaultEmptyName(loadName);
310            replaceAllLoads(oldLoadName, loadName);
311            return;
312        }
313        if (oldLoadName.equals(carLoads.getDefaultLoadName())) {
314            if (JmriJOptionPane.showConfirmDialog(this,
315                    Bundle.getMessage("replaceDefaultLoad",
316                            oldLoadName, loadName),
317                    Bundle.getMessage("replaceAll"),
318                    JmriJOptionPane.YES_NO_OPTION) != JmriJOptionPane.YES_OPTION) {
319                return;
320            }
321            // don't allow the default names for load and empty to be the
322            // same
323            if (loadName.equals(carLoads.getDefaultEmptyName()) || loadName.equals(carLoads.getDefaultLoadName())) {
324                JmriJOptionPane.showMessageDialog(this, Bundle.getMessage("carDefault"), Bundle
325                        .getMessage("canNotReplace", Bundle.getMessage("Load")),
326                        JmriJOptionPane.ERROR_MESSAGE);
327                return;
328            }
329            carLoads.setDefaultLoadName(loadName);
330            replaceAllLoads(oldLoadName, loadName);
331            return;
332        }
333        if (JmriJOptionPane.showConfirmDialog(this,
334                Bundle.getMessage("replaceMsg",
335                        oldLoadName, loadName),
336                Bundle.getMessage("replaceAll"),
337                JmriJOptionPane.YES_NO_OPTION) != JmriJOptionPane.YES_OPTION) {
338            return;
339        }
340        if (oldLoadName.equals(loadName)) {
341            return; // do nothing
342        }
343        // ComboBoxes get deselected during the addName operation
344        String loadType = carLoads.getLoadType(_type, oldLoadName);
345        String loadPriority = carLoads.getPriority(_type, oldLoadName);
346        boolean isHazardous = carLoads.isHazardous(_type, oldLoadName);
347        String pickupComment = carLoads.getPickupComment(_type, oldLoadName);
348        String dropComment = carLoads.getDropComment(_type, oldLoadName);
349
350        if (allTypesCheckBox.isSelected()) {
351            for (String type : carTypes.getNames()) {
352                carLoads.addName(type, loadName);
353                carLoads.setLoadType(type, loadName, loadType);
354                carLoads.setPriority(type, loadName, loadPriority);
355                carLoads.setHazardous(type, loadName, isHazardous);
356                carLoads.setPickupComment(type, loadName, pickupComment);
357                carLoads.setDropComment(type, loadName, dropComment);
358                replaceLoad(type, oldLoadName, loadName);
359                carLoads.deleteName(type, oldLoadName);
360            }
361        } else {
362            carLoads.addName(_type, loadName);
363            carLoads.setLoadType(_type, loadName, loadType);
364            carLoads.setPriority(_type, loadName, loadPriority);
365            carLoads.setHazardous(_type, loadName, isHazardous);
366            carLoads.setPickupComment(_type, loadName, pickupComment);
367            carLoads.setDropComment(_type, loadName, dropComment);
368            replaceLoad(_type, oldLoadName, loadName);
369            carLoads.deleteName(_type, oldLoadName);
370        }
371    }
372
373    private void saveLoadName() {
374        if (allTypesCheckBox.isSelected()) {
375            for (String type : carTypes.getNames()) {
376                saveLoadName(type);
377            }
378        } else {
379            saveLoadName(_type);
380        }
381    }
382
383    private void saveLoadName(String type) {
384        carLoads.setLoadType(type, (String) loadComboBox.getSelectedItem(), (String) loadTypeComboBox
385                .getSelectedItem());
386        carLoads.setPriority(type, (String) loadComboBox.getSelectedItem(),
387                (String) priorityComboBox.getSelectedItem());
388        carLoads.setHazardous(type, (String) loadComboBox.getSelectedItem(),
389                hazardousComboBox.getSelectedItem().equals(Bundle.getMessage("ButtonYes")));
390        carLoads.setPickupComment(type, (String) loadComboBox.getSelectedItem(), pickupCommentTextField.getText());
391        carLoads.setDropComment(type, (String) loadComboBox.getSelectedItem(), dropCommentTextField.getText());
392    }
393
394    // replace load name for all car types
395    private void replaceAllLoads(String oldLoad, String newLoad) {
396        for (String type : carTypes.getNames()) {
397            carLoads.addName(type, newLoad);
398            replaceLoad(type, oldLoad, newLoad);
399            carLoads.deleteName(type, oldLoad);
400        }
401    }
402
403    private void replaceLoad(String type, String oldLoad, String newLoad) {
404        // adjust all cars
405        InstanceManager.getDefault(CarManager.class).replaceLoad(type, oldLoad, newLoad);
406        // now adjust schedules
407        InstanceManager.getDefault(ScheduleManager.class).replaceLoad(type, oldLoad, newLoad);
408        // now adjust trains
409        InstanceManager.getDefault(TrainManager.class).replaceLoad(type, oldLoad, newLoad);
410        // now adjust tracks
411        InstanceManager.getDefault(LocationManager.class).replaceLoad(type, oldLoad, newLoad);
412    }
413
414    boolean showQuanity = false;
415
416    public void toggleShowQuanity() {
417        if (showQuanity) {
418            showQuanity = false;
419        } else {
420            showQuanity = true;
421        }
422        quanity.setVisible(showQuanity);
423        updateCarQuanity();
424    }
425
426    private void updateCarQuanity() {
427        if (!showQuanity) {
428            return;
429        }
430        int number = 0;
431        String item = (String) loadComboBox.getSelectedItem();
432        for (Car car : InstanceManager.getDefault(CarManager.class).getList()) {
433            if (car.getLoadName().equals(item)) {
434                number++;
435            }
436        }
437        quanity.setText(Integer.toString(number));
438    }
439
440    private void updateLoadComboBox() {
441        carLoads.updateComboBox(_type, loadComboBox);
442        loadComboBox.setSelectedItem(addTextBox.getText().trim());
443    }
444
445    private void updateLoadType() {
446        String loadName = (String) loadComboBox.getSelectedItem();
447        loadTypeComboBox.setSelectedItem(carLoads.getLoadType(_type, loadName));
448        if (loadName != null &&
449                (loadName.equals(InstanceManager.getDefault(CarLoads.class).getDefaultEmptyName()) ||
450                        loadName.equals(InstanceManager.getDefault(CarLoads.class)
451                                .getDefaultLoadName()))) {
452            loadTypeComboBox.setEnabled(false);
453        } else {
454            loadTypeComboBox.setEnabled(true);
455        }
456    }
457
458    private void updatePriority() {
459        priorityComboBox.setSelectedItem(carLoads.getPriority(_type, (String) loadComboBox.getSelectedItem()));
460    }
461
462    private void updateHazardous() {
463        hazardousComboBox.setSelectedItem(carLoads.isHazardous(_type, (String) loadComboBox.getSelectedItem())
464                ? Bundle.getMessage("ButtonYes") : Bundle.getMessage("ButtonNo"));
465    }
466
467    private void updateCarCommentFields() {
468        pickupCommentTextField.setText(carLoads.getPickupComment(_type, (String) loadComboBox.getSelectedItem()));
469        dropCommentTextField.setText(carLoads.getDropComment(_type, (String) loadComboBox.getSelectedItem()));
470    }
471
472    private void enableButtons() {
473        addButton.setEnabled(_type != null);
474        deleteButton.setEnabled(_type != null);
475        replaceButton.setEnabled(_type != null);
476        saveButton.setEnabled(_type != null);
477    }
478
479    @Override
480    public void dispose() {
481        carLoads.removePropertyChangeListener(this);
482        super.dispose();
483    }
484
485    @Override
486    public void propertyChange(java.beans.PropertyChangeEvent e) {
487        if (Control.SHOW_PROPERTY) {
488            log.debug("Property change: ({}) old: ({}) new: ({})", e.getPropertyName(), e.getOldValue(), e
489                    .getNewValue());
490        }
491        if (e.getPropertyName().equals(CarLoads.LOAD_CHANGED_PROPERTY)) {
492            updateLoadComboBox();
493        }
494    }
495
496    private static final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(CarLoadEditFrame.class);
497}