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