001package jmri.jmrit.operations.trains.tools;
002
003import java.awt.Dimension;
004import java.awt.GridBagLayout;
005import java.util.ArrayList;
006import java.util.List;
007
008import javax.swing.*;
009
010import jmri.InstanceManager;
011import jmri.jmrit.operations.OperationsFrame;
012import jmri.jmrit.operations.OperationsXml;
013import jmri.jmrit.operations.rollingstock.cars.CarTypes;
014import jmri.jmrit.operations.setup.Control;
015import jmri.jmrit.operations.setup.Setup;
016import jmri.jmrit.operations.trains.Train;
017import jmri.jmrit.operations.trains.TrainManager;
018import jmri.util.swing.JmriJOptionPane;
019
020/**
021 * Frame to display which trains service certain car types
022 *
023 * @author Dan Boudreau Copyright (C) 2009, 2022
024 */
025public class TrainsByCarTypeFrame extends OperationsFrame implements java.beans.PropertyChangeListener {
026
027    TrainManager trainManager = InstanceManager.getDefault(TrainManager.class);
028
029    ArrayList<JCheckBox> trainList = new ArrayList<>();
030    JPanel trainCheckBoxes = new JPanel();
031
032    // panels
033    JPanel pTrains;
034
035    // major buttons
036    JButton clearButton = new JButton(Bundle.getMessage("ClearAll"));
037    JButton setButton = new JButton(Bundle.getMessage("SelectAll"));
038    JButton saveButton = new JButton(Bundle.getMessage("ButtonSave"));
039
040    // check boxes
041    JCheckBox copyCheckBox = new JCheckBox(Bundle.getMessage("ButtonCopy"));
042
043    // combo boxes
044    JComboBox<String> typeComboBox = InstanceManager.getDefault(CarTypes.class).getComboBox();
045    JComboBox<String> copyComboBox = InstanceManager.getDefault(CarTypes.class).getComboBox();
046
047    public TrainsByCarTypeFrame() {
048        super(Bundle.getMessage("TitleModifyTrains"));
049    }
050
051    public void initComponents(String carType) {
052
053        // general GUI config
054        getContentPane().setLayout(new BoxLayout(getContentPane(), BoxLayout.Y_AXIS));
055
056        // Set up the panels
057        JPanel pCarType = new JPanel();
058        pCarType.setLayout(new GridBagLayout());
059        pCarType.setBorder(BorderFactory.createTitledBorder(Bundle.getMessage("Type")));
060        
061        JPanel pCarCopy = new JPanel();
062        pCarCopy.setLayout(new GridBagLayout());
063        addItem(pCarCopy, copyCheckBox, 0, 0);
064        addItem(pCarCopy, new JLabel("  "), 1, 0); // some space
065        addItem(pCarCopy, copyComboBox, 2, 0);
066        pCarCopy.setBorder(BorderFactory.createTitledBorder(Bundle.getMessage("CopyType")));
067
068        addItem(pCarType, typeComboBox, 0, 0);
069        addItem(pCarType, new JLabel("  "), 1, 0); // some space
070        addItem(pCarType, pCarCopy, 2, 0);
071        
072        typeComboBox.setSelectedItem(carType);
073        copyCheckBox.setToolTipText(Bundle.getMessage("TipCopyCarType"));
074
075        pTrains = new JPanel();
076        pTrains.setLayout(new GridBagLayout());
077        JScrollPane trainPane = new JScrollPane(pTrains);
078        trainPane.setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED);
079        trainPane.setBorder(BorderFactory.createTitledBorder(Bundle.getMessage("Trains")));
080        updateTrains();
081
082        JPanel pButtons = new JPanel();
083        pButtons.setLayout(new GridBagLayout());
084        pButtons.setBorder(BorderFactory.createEtchedBorder());
085
086        addItem(pButtons, clearButton, 0, 0);
087        addItem(pButtons, setButton, 1, 0);
088        addItem(pButtons, saveButton, 2, 0);
089
090        getContentPane().add(pCarType);
091        getContentPane().add(trainPane);
092        getContentPane().add(pButtons);
093
094        // setup combo box
095        addComboBoxAction(typeComboBox);
096        addComboBoxAction(copyComboBox);
097
098        // setup buttons
099        addButtonAction(setButton);
100        addButtonAction(clearButton);
101        addButtonAction(saveButton);
102
103        // setup checkbox
104        addCheckBoxAction(copyCheckBox);
105
106        trainManager.addPropertyChangeListener(this);
107        InstanceManager.getDefault(CarTypes.class).addPropertyChangeListener(this);
108
109        // build menu
110        JMenuBar menuBar = new JMenuBar();
111        JMenu toolMenu = new JMenu(Bundle.getMessage("MenuTools"));
112        toolMenu.add(new PrintTrainsByCarTypesAction(false));
113        toolMenu.add(new PrintTrainsByCarTypesAction(true));
114        menuBar.add(toolMenu);
115        setJMenuBar(menuBar);
116        addHelpMenu("package.jmri.jmrit.operations.Operations_ModifyTrainsByCarType", true); // NOI18N
117
118        setPreferredSize(null);
119        initMinimumSize(new Dimension(Control.panelWidth300, Control.panelHeight250));
120    }
121
122    @Override
123    public void comboBoxActionPerformed(java.awt.event.ActionEvent ae) {
124        log.debug("combo box action");
125        updateTrains();
126    }
127
128    // Save, Delete, Add
129    @Override
130    public void buttonActionPerformed(java.awt.event.ActionEvent ae) {
131        if (ae.getSource() == saveButton) {
132            save();
133        }
134        if (ae.getSource() == setButton) {
135            selectCheckboxes(true);
136        }
137        if (ae.getSource() == clearButton) {
138            selectCheckboxes(false);
139        }
140    }
141
142    /**
143     * Update the car types that trains and tracks service. Note that the
144     * checkbox name is the id of the train or track.
145     */
146    private void save() {
147        if (copyCheckBox.isSelected() &&
148                JmriJOptionPane.showConfirmDialog(this, Bundle.getMessage("CopyCarType",
149                        typeComboBox.getSelectedItem(), copyComboBox.getSelectedItem()),
150                        Bundle.getMessage("CopyCarTypeTitle"),
151                        JmriJOptionPane.YES_NO_OPTION) != JmriJOptionPane.YES_OPTION) {
152            return;
153        }
154        log.debug("Save {} trains", trainList.size());
155        removePropertyChangeTrains();
156        // protected against concurrent operation by making a copy
157        for (JCheckBox cb : new ArrayList<>(trainList)) {
158            Train train = trainManager.getTrainById(cb.getName());
159            if (cb.isSelected()) {
160                train.addTypeName((String) typeComboBox.getSelectedItem());
161            } else {
162                train.deleteTypeName((String) typeComboBox.getSelectedItem());
163            }
164        }
165        OperationsXml.save(); // save files
166        updateTrains();
167        if (Setup.isCloseWindowOnSaveEnabled()) {
168            dispose();
169        }
170    }
171
172    private void updateTrains() {
173        log.debug("update trains");
174        removePropertyChangeTrains();
175        trainList.clear();
176        int x = 0;
177        pTrains.removeAll();
178        String carType = (String) typeComboBox.getSelectedItem();
179        if (copyCheckBox.isSelected()) {
180            carType = (String) copyComboBox.getSelectedItem();
181        }
182        List<Train> trains = trainManager.getTrainsByNameList();
183        for (Train train : trains) {
184            train.addPropertyChangeListener(this);
185            JCheckBox cb = new JCheckBox(train.getName());
186            cb.setName(train.getId());
187            cb.setToolTipText(Bundle.getMessage("TipTrainCarType", carType));
188            addCheckBoxAction(cb);
189            trainList.add(cb);
190            cb.setSelected(train.isTypeNameAccepted(carType));
191            addItemLeft(pTrains, cb, 0, x);
192            JLabel description = new JLabel(train.getDescription());
193            addItemLeft(pTrains, description, 1, x++);
194        }
195        pTrains.revalidate();
196        repaint();
197    }
198
199    private void updateComboBox() {
200        log.debug("update combobox");
201        InstanceManager.getDefault(CarTypes.class).updateComboBox(typeComboBox);
202        InstanceManager.getDefault(CarTypes.class).updateComboBox(copyComboBox);
203    }
204
205    private void selectCheckboxes(boolean b) {
206        for (JCheckBox checkBox : new ArrayList<>(trainList)) {
207            checkBox.setSelected(b);
208        }
209    }
210
211    @Override
212    public void checkBoxActionPerformed(java.awt.event.ActionEvent ae) {
213        // copy checkbox?
214        if (ae.getSource() == copyCheckBox) {
215            updateTrains();
216        } else {
217            JCheckBox cb = (JCheckBox) ae.getSource();
218            log.debug("Checkbox {} text: {}", cb.getName(), cb.getText());
219            if (trainList.contains(cb)) {
220                log.debug("Checkbox train {}", cb.getText());
221            } else {
222                log.error("Error checkbox not found");
223            }
224        }
225    }
226
227    private void removePropertyChangeTrains() {
228        for (JCheckBox checkBox : new ArrayList<>(trainList)) {
229            // if object has been deleted, it's not here; ignore it
230            Train train = trainManager.getTrainById(checkBox.getName());
231            if (train != null) {
232                train.removePropertyChangeListener(this);
233            }
234        }
235    }
236
237    @Override
238    public void dispose() {
239        trainManager.removePropertyChangeListener(this);
240        InstanceManager.getDefault(CarTypes.class).removePropertyChangeListener(this);
241        removePropertyChangeTrains();
242        super.dispose();
243    }
244
245    @Override
246    public void propertyChange(java.beans.PropertyChangeEvent e) {
247        log.debug("Property change {} old: {} new: {}", e.getPropertyName(), e.getOldValue(), e.getNewValue());
248        if (e.getPropertyName().equals(TrainManager.LISTLENGTH_CHANGED_PROPERTY) ||
249                e.getPropertyName().equals(Train.TYPES_CHANGED_PROPERTY) ||
250                e.getPropertyName().equals(Train.NAME_CHANGED_PROPERTY) ||
251                e.getPropertyName().equals(Train.DESCRIPTION_CHANGED_PROPERTY)) {
252            updateTrains();
253        }
254        if (e.getPropertyName().equals(CarTypes.CARTYPES_CHANGED_PROPERTY) ||
255                e.getPropertyName().equals(CarTypes.CARTYPES_NAME_CHANGED_PROPERTY)) {
256            updateComboBox();
257        }
258    }
259
260    private static final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(TrainsByCarTypeFrame.class);
261}