001package jmri.jmrit.operations.trains.gui;
002
003import java.awt.*;
004
005import javax.swing.*;
006
007import org.slf4j.Logger;
008import org.slf4j.LoggerFactory;
009
010import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
011import jmri.InstanceManager;
012import jmri.jmrit.operations.OperationsFrame;
013import jmri.jmrit.operations.OperationsXml;
014import jmri.jmrit.operations.rollingstock.cars.*;
015import jmri.jmrit.operations.setup.Control;
016import jmri.jmrit.operations.setup.Setup;
017import jmri.jmrit.operations.trains.Train;
018
019/**
020 * Frame for user edit of a train's load options
021 *
022 * @author Dan Boudreau Copyright (C) 2013
023 * 
024 */
025public class TrainLoadOptionsFrame extends OperationsFrame implements java.beans.PropertyChangeListener {
026
027    private static boolean loadAndType = false;
028
029    Train _train = null;
030
031    JPanel pLoadControls = new JPanel();
032    JPanel panelLoads = new JPanel();
033    JScrollPane paneLoads = new JScrollPane(panelLoads);
034
035    // labels
036    JLabel trainName = new JLabel();
037    JLabel trainDescription = new JLabel();
038
039    // major buttons
040    JButton addLoadButton = new JButton(Bundle.getMessage("AddLoad"));
041    JButton deleteLoadButton = new JButton(Bundle.getMessage("DeleteLoad"));
042    JButton deleteAllLoadsButton = new JButton(Bundle.getMessage("DeleteAll"));
043    JButton saveTrainButton = new JButton(Bundle.getMessage("SaveTrain"));
044
045    // radio buttons
046    JRadioButton loadNameAll = new JRadioButton(Bundle.getMessage("AcceptAll"));
047    JRadioButton loadNameInclude = new JRadioButton(Bundle.getMessage("AcceptOnly"));
048    JRadioButton loadNameExclude = new JRadioButton(Bundle.getMessage("Exclude"));
049
050    ButtonGroup loadGroup = new ButtonGroup();
051
052    // check boxes
053    JCheckBox loadAndTypeCheckBox = new JCheckBox(Bundle.getMessage("TypeAndLoad"));
054
055    // text field
056    // combo boxes
057    JComboBox<String> comboBoxTypes = InstanceManager.getDefault(CarTypes.class).getComboBox();
058    JComboBox<String> comboBoxLoads = InstanceManager.getDefault(CarLoads.class).getComboBox(null);
059
060    public static final String DISPOSE = "dispose"; // NOI18N
061
062    public TrainLoadOptionsFrame() {
063        super(Bundle.getMessage("MenuItemLoadOptions"));
064    }
065
066    public void initComponents(TrainEditFrame parent) {
067
068        parent.setChildFrame(this);
069        _train = parent._train;
070
071        getContentPane().setLayout(new BoxLayout(getContentPane(), BoxLayout.Y_AXIS));
072
073        // Layout the panel by rows
074        JPanel p1 = new JPanel();
075        p1.setLayout(new BoxLayout(p1, BoxLayout.X_AXIS));
076        p1.setMaximumSize(new Dimension(2000, 250));
077
078        // Layout the panel by rows
079        // row 1a
080        JPanel pName = new JPanel();
081        pName.setLayout(new GridBagLayout());
082        pName.setBorder(BorderFactory.createTitledBorder(Bundle.getMessage("Name")));
083        addItem(pName, trainName, 0, 0);
084
085        // row 1b
086        JPanel pDesc = new JPanel();
087        pDesc.setLayout(new GridBagLayout());
088        pDesc.setBorder(BorderFactory.createTitledBorder(Bundle.getMessage("Description")));
089        addItem(pDesc, trainDescription, 0, 0);
090
091        p1.add(pName);
092        p1.add(pDesc);
093
094        // row 3
095        JPanel p3 = new JPanel();
096        p3.setLayout(new BoxLayout(p3, BoxLayout.Y_AXIS));
097        JScrollPane pane3 = new JScrollPane(p3);
098        pane3.setBorder(BorderFactory.createTitledBorder(Bundle.getMessage("LoadsTrain")));
099        pane3.setMaximumSize(new Dimension(2000, 400));
100
101        JPanel pLoadRadioButtons = new JPanel();
102        pLoadRadioButtons.setLayout(new FlowLayout());
103
104        pLoadRadioButtons.add(loadNameAll);
105        pLoadRadioButtons.add(loadNameInclude);
106        pLoadRadioButtons.add(loadNameExclude);
107        pLoadRadioButtons.add(loadAndTypeCheckBox);
108
109        pLoadControls.setLayout(new FlowLayout());
110
111        pLoadControls.add(comboBoxTypes);
112        pLoadControls.add(comboBoxLoads);
113        pLoadControls.add(addLoadButton);
114        pLoadControls.add(deleteLoadButton);
115        pLoadControls.add(deleteAllLoadsButton);
116
117        pLoadControls.setVisible(false);
118
119        p3.add(pLoadRadioButtons);
120        p3.add(pLoadControls);
121
122        // row 4
123        panelLoads.setLayout(new GridBagLayout());
124        paneLoads.setBorder(BorderFactory.createTitledBorder(Bundle.getMessage("Loads")));
125
126        ButtonGroup loadGroup = new ButtonGroup();
127        loadGroup.add(loadNameAll);
128        loadGroup.add(loadNameInclude);
129        loadGroup.add(loadNameExclude);
130
131        // row 12
132        JPanel panelButtons = new JPanel();
133        panelButtons.setLayout(new GridBagLayout());
134        panelButtons.setBorder(BorderFactory.createTitledBorder(""));
135        panelButtons.setMaximumSize(new Dimension(2000, 200));
136
137        // row 13
138        addItem(panelButtons, saveTrainButton, 0, 0);
139
140        getContentPane().add(p1);
141        getContentPane().add(pane3);
142        getContentPane().add(paneLoads);
143        getContentPane().add(panelButtons);
144
145        // setup buttons
146        addButtonAction(saveTrainButton);
147
148        addButtonAction(deleteLoadButton);
149        addButtonAction(deleteAllLoadsButton);
150        addButtonAction(addLoadButton);
151
152        addRadioButtonAction(loadNameAll);
153        addRadioButtonAction(loadNameInclude);
154        addRadioButtonAction(loadNameExclude);
155
156        addComboBoxAction(comboBoxTypes);
157
158        if (_train != null) {
159            trainName.setText(_train.getName());
160            trainDescription.setText(_train.getDescription());
161            updateButtons(true);
162            // listen for train changes
163            _train.addPropertyChangeListener(this);
164        } else {
165            updateButtons(false);
166        }
167        addHelpMenu("package.jmri.jmrit.operations.Operations_TrainLoadOptions", true); // NOI18N
168        updateTypeComboBoxes();
169        updateLoadComboBoxes();
170        updateLoadNames();
171
172        // get notified if car roads, loads, and owners gets modified
173        InstanceManager.getDefault(CarTypes.class).addPropertyChangeListener(this);
174        InstanceManager.getDefault(CarLoads.class).addPropertyChangeListener(this);
175        loadAndTypeCheckBox.setSelected(loadAndType);
176
177        initMinimumSize(new Dimension(Control.panelWidth600, Control.panelHeight400));
178    }
179
180    // Save
181    @Override
182    public void buttonActionPerformed(java.awt.event.ActionEvent ae) {
183        if (_train != null) {
184            if (ae.getSource() == saveTrainButton) {
185                log.debug("train save button activated");
186                saveTrain();
187            }
188            if (ae.getSource() == addLoadButton) {
189                String loadName = (String) comboBoxLoads.getSelectedItem();
190                if (loadAndTypeCheckBox.isSelected()) {
191                    loadName = comboBoxTypes.getSelectedItem() + CarLoad.SPLIT_CHAR + loadName;
192                }
193                if (_train.addLoadName(loadName)) {
194                    updateLoadNames();
195                }
196                selectNextItemComboBox(comboBoxLoads);
197            }
198            if (ae.getSource() == deleteLoadButton) {
199                String loadName = (String) comboBoxLoads.getSelectedItem();
200                if (loadAndTypeCheckBox.isSelected()) {
201                    loadName = comboBoxTypes.getSelectedItem() + CarLoad.SPLIT_CHAR + loadName;
202                }
203                if (_train.deleteLoadName(loadName)) {
204                    updateLoadNames();
205                }
206                selectNextItemComboBox(comboBoxLoads);
207            }
208            if (ae.getSource() == deleteAllLoadsButton) {
209                deleteAllLoads();
210            }
211        }
212    }
213
214    @Override
215    public void radioButtonActionPerformed(java.awt.event.ActionEvent ae) {
216        log.debug("radio button activated");
217        if (_train != null) {
218            if (ae.getSource() == loadNameAll) {
219                _train.setLoadOption(Train.ALL_LOADS);
220                updateLoadNames();
221            }
222            if (ae.getSource() == loadNameInclude) {
223                _train.setLoadOption(Train.INCLUDE_LOADS);
224                updateLoadNames();
225            }
226            if (ae.getSource() == loadNameExclude) {
227                _train.setLoadOption(Train.EXCLUDE_LOADS);
228                updateLoadNames();
229            }
230        }
231    }
232
233    // Car type combo box has been changed, show loads associated with this car type
234    @Override
235    public void comboBoxActionPerformed(java.awt.event.ActionEvent ae) {
236        if (ae.getSource() == comboBoxTypes) {
237            updateLoadComboBoxes();
238        }
239    }
240
241    protected void updateButtons(boolean enabled) {
242        saveTrainButton.setEnabled(enabled);
243
244        loadNameAll.setEnabled(enabled);
245        loadNameInclude.setEnabled(enabled);
246        loadNameExclude.setEnabled(enabled);
247        loadAndTypeCheckBox.setEnabled(enabled);
248    }
249
250    private void updateLoadNames() {
251        log.debug("Update load names");
252        panelLoads.removeAll();
253        if (_train != null) {
254            // set radio button
255            loadNameAll.setSelected(_train.getLoadOption().equals(Train.ALL_LOADS));
256            loadNameInclude.setSelected(_train.getLoadOption().equals(Train.INCLUDE_ROADS));
257            loadNameExclude.setSelected(_train.getLoadOption().equals(Train.EXCLUDE_ROADS));
258
259            pLoadControls.setVisible(!loadNameAll.isSelected());
260
261            if (!loadNameAll.isSelected()) {
262                int x = 0;
263                int y = 0; // vertical position in panel
264
265                int numberOfLoads = getNumberOfCheckboxesPerLine() / 2 + 1;
266                for (String loadName : _train.getLoadNames()) {
267                    JLabel load = new JLabel();
268                    load.setText(loadName);
269                    addItemTop(panelLoads, load, x++, y);
270                    // limit the number of loads per line
271                    if (x > numberOfLoads) {
272                        y++;
273                        x = 0;
274                    }
275                }
276                revalidate();
277            }
278        } else {
279            loadNameAll.setSelected(true);
280        }
281        panelLoads.repaint();
282        panelLoads.revalidate();
283    }
284
285    private void deleteAllLoads() {
286        if (_train != null) {
287            for (String load : _train.getLoadNames()) {
288                _train.deleteLoadName(load);
289            }
290        }
291        updateLoadNames();
292    }
293
294    @SuppressFBWarnings(value = "ST_WRITE_TO_STATIC_FROM_INSTANCE_METHOD", justification = "GUI ease of use")
295    private void saveTrain() {
296        // save the last state of the "Use car type and load" checkbox
297        loadAndType = loadAndTypeCheckBox.isSelected();
298        OperationsXml.save();
299        if (Setup.isCloseWindowOnSaveEnabled()) {
300            dispose();
301        }
302    }
303
304    private void updateTypeComboBoxes() {
305        InstanceManager.getDefault(CarTypes.class).updateComboBox(comboBoxTypes);
306        // remove types not serviced by this train
307        for (int i = comboBoxTypes.getItemCount() - 1; i >= 0; i--) {
308            String type = comboBoxTypes.getItemAt(i);
309            if (_train != null && !_train.isTypeNameAccepted(type)) {
310                comboBoxTypes.removeItem(type);
311            }
312        }
313    }
314
315    private void updateLoadComboBoxes() {
316        String carType = (String) comboBoxTypes.getSelectedItem();
317        InstanceManager.getDefault(CarLoads.class).updateComboBox(carType, comboBoxLoads);
318    }
319
320    @Override
321    public void dispose() {
322        InstanceManager.getDefault(CarTypes.class).removePropertyChangeListener(this);
323        InstanceManager.getDefault(CarLoads.class).removePropertyChangeListener(this);
324        if (_train != null) {
325            _train.removePropertyChangeListener(this);
326        }
327        super.dispose();
328    }
329
330    @Override
331    public void propertyChange(java.beans.PropertyChangeEvent e) {
332        if (Control.SHOW_PROPERTY) {
333            log.debug("Property change: ({}) old: ({}) new: ({})", e.getPropertyName(), e.getOldValue(), e
334                    .getNewValue());
335        }
336        if (e.getPropertyName().equals(CarLoads.LOAD_NAME_CHANGED_PROPERTY)
337                || e.getPropertyName().equals(CarLoads.LOAD_CHANGED_PROPERTY)) {
338            updateLoadComboBoxes();
339            updateLoadNames();
340        }
341        if (e.getPropertyName().equals(CarTypes.CARTYPES_CHANGED_PROPERTY)
342                || e.getPropertyName().equals(Train.TYPES_CHANGED_PROPERTY)) {
343            updateTypeComboBoxes();
344        }
345    }
346
347    private final static Logger log = LoggerFactory.getLogger(TrainLoadOptionsFrame.class);
348}