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