001package jmri.jmrit.operations.trains;
002
003import java.awt.Dimension;
004import java.awt.FlowLayout;
005import java.awt.GridBagLayout;
006import javax.swing.BorderFactory;
007import javax.swing.BoxLayout;
008import javax.swing.ButtonGroup;
009import javax.swing.JButton;
010import javax.swing.JComboBox;
011import javax.swing.JLabel;
012import javax.swing.JPanel;
013import javax.swing.JRadioButton;
014import javax.swing.JScrollPane;
015import jmri.InstanceManager;
016import jmri.jmrit.operations.OperationsFrame;
017import jmri.jmrit.operations.OperationsXml;
018import jmri.jmrit.operations.rollingstock.cars.CarRoads;
019import jmri.jmrit.operations.rollingstock.cars.CarTypes;
020import jmri.jmrit.operations.setup.Control;
021import jmri.jmrit.operations.setup.Setup;
022import org.slf4j.Logger;
023import org.slf4j.LoggerFactory;
024
025/**
026 * Frame for user edit of a train's road options
027 *
028 * @author Dan Boudreau Copyright (C) 2013, 2022
029 * 
030 */
031public class TrainRoadOptionsFrame extends OperationsFrame implements java.beans.PropertyChangeListener {
032
033    Train _train = null;
034
035    JPanel pCarRoadControls = new JPanel();
036    JPanel panelCarRoads = new JPanel();
037    JScrollPane paneCarRoads = new JScrollPane(panelCarRoads);
038    
039    JPanel pLocoRoadControls = new JPanel();
040    JPanel panelLocoRoads = new JPanel();
041    JScrollPane paneLocoRoads = new JScrollPane(panelLocoRoads);
042
043    // labels
044    JLabel trainName = new JLabel();
045    JLabel trainDescription = new JLabel();
046
047    // major buttons
048    JButton addCarRoadButton = new JButton(Bundle.getMessage("AddRoad"));
049    JButton deleteCarRoadButton = new JButton(Bundle.getMessage("DeleteRoad"));
050    JButton deleteCarAllRoadsButton = new JButton(Bundle.getMessage("DeleteAll"));
051    JButton addLocoRoadButton = new JButton(Bundle.getMessage("AddRoad"));
052    JButton deleteLocoRoadButton = new JButton(Bundle.getMessage("DeleteRoad"));
053    JButton deleteLocoAllRoadsButton = new JButton(Bundle.getMessage("DeleteAll"));
054
055    JButton saveTrainButton = new JButton(Bundle.getMessage("SaveTrain"));
056
057    // radio buttons
058    JRadioButton carRoadNameAll = new JRadioButton(Bundle.getMessage("AcceptAll"));
059    JRadioButton carRoadNameInclude = new JRadioButton(Bundle.getMessage("AcceptOnly"));
060    JRadioButton carRoadNameExclude = new JRadioButton(Bundle.getMessage("Exclude"));
061    JRadioButton locoRoadNameAll = new JRadioButton(Bundle.getMessage("AcceptAll"));
062    JRadioButton locoRoadNameInclude = new JRadioButton(Bundle.getMessage("AcceptOnly"));
063    JRadioButton locoRoadNameExclude = new JRadioButton(Bundle.getMessage("Exclude"));
064
065    // combo boxes
066    JComboBox<String> comboBoxCarRoads = InstanceManager.getDefault(CarRoads.class).getComboBox();
067    JComboBox<String> comboBoxLocoRoads = InstanceManager.getDefault(CarRoads.class).getComboBox();
068
069    public static final String DISPOSE = "dispose"; // NOI18N
070
071    public TrainRoadOptionsFrame() {
072        super(Bundle.getMessage("MenuItemRoadOptions"));
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 Car Roads
104        JPanel pCarRoad = new JPanel();
105        pCarRoad.setLayout(new BoxLayout(pCarRoad, BoxLayout.Y_AXIS));
106        JScrollPane paneCar = new JScrollPane(pCarRoad);
107        paneCar.setBorder(BorderFactory.createTitledBorder(Bundle.getMessage("CarRoadsTrain")));
108        paneCar.setMaximumSize(new Dimension(2000, 400));
109
110        JPanel pCarRoadRadioButtons = new JPanel();
111        pCarRoadRadioButtons.setLayout(new FlowLayout());
112
113        pCarRoadRadioButtons.add(carRoadNameAll);
114        pCarRoadRadioButtons.add(carRoadNameInclude);
115        pCarRoadRadioButtons.add(carRoadNameExclude);
116
117        pCarRoadControls.setLayout(new FlowLayout());
118
119        pCarRoadControls.add(comboBoxCarRoads);
120        pCarRoadControls.add(addCarRoadButton);
121        pCarRoadControls.add(deleteCarRoadButton);
122        pCarRoadControls.add(deleteCarAllRoadsButton);
123
124        pCarRoadControls.setVisible(false);
125
126        pCarRoad.add(pCarRoadRadioButtons);
127        pCarRoad.add(pCarRoadControls);
128
129        // row 4
130        panelCarRoads.setLayout(new GridBagLayout());
131        paneCarRoads.setBorder(BorderFactory.createTitledBorder(Bundle.getMessage("Roads")));
132
133        ButtonGroup carRoadGroup = new ButtonGroup();
134        carRoadGroup.add(carRoadNameAll);
135        carRoadGroup.add(carRoadNameInclude);
136        carRoadGroup.add(carRoadNameExclude);
137        
138        // row 5 Engine Roads
139        JPanel pLocoRoad = new JPanel();
140        pLocoRoad.setLayout(new BoxLayout(pLocoRoad, BoxLayout.Y_AXIS));
141        JScrollPane paneLoco = new JScrollPane(pLocoRoad);
142        paneLoco.setBorder(BorderFactory.createTitledBorder(Bundle.getMessage("LocoRoadsTrain")));
143        paneLoco.setMaximumSize(new Dimension(2000, 400));
144
145        JPanel pLocoRoadRadioButtons = new JPanel();
146        pLocoRoadRadioButtons.setLayout(new FlowLayout());
147
148        pLocoRoadRadioButtons.add(locoRoadNameAll);
149        pLocoRoadRadioButtons.add(locoRoadNameInclude);
150        pLocoRoadRadioButtons.add(locoRoadNameExclude);
151
152        pLocoRoadControls.setLayout(new FlowLayout());
153
154        pLocoRoadControls.add(comboBoxLocoRoads);
155        pLocoRoadControls.add(addLocoRoadButton);
156        pLocoRoadControls.add(deleteLocoRoadButton);
157        pLocoRoadControls.add(deleteLocoAllRoadsButton);
158
159        pLocoRoadControls.setVisible(false);
160
161        pLocoRoad.add(pLocoRoadRadioButtons);
162        pLocoRoad.add(pLocoRoadControls);
163
164        // row 4
165        panelLocoRoads.setLayout(new GridBagLayout());
166        paneLocoRoads.setBorder(BorderFactory.createTitledBorder(Bundle.getMessage("Roads")));
167
168        ButtonGroup locoRoadGroup = new ButtonGroup();
169        locoRoadGroup.add(locoRoadNameAll);
170        locoRoadGroup.add(locoRoadNameInclude);
171        locoRoadGroup.add(locoRoadNameExclude);
172
173        // row 12
174        JPanel panelButtons = new JPanel();
175        panelButtons.setLayout(new GridBagLayout());
176        panelButtons.setBorder(BorderFactory.createTitledBorder(""));
177        panelButtons.setMaximumSize(new Dimension(2000, 200));
178
179        // row 13
180        addItem(panelButtons, saveTrainButton, 0, 0);
181
182        getContentPane().add(p1);
183        getContentPane().add(paneCar);
184        getContentPane().add(paneCarRoads);
185        getContentPane().add(paneLoco);
186        getContentPane().add(paneLocoRoads);
187        getContentPane().add(panelButtons);
188
189        // setup buttons
190        addButtonAction(saveTrainButton);
191
192        addButtonAction(deleteCarRoadButton);
193        addButtonAction(deleteCarAllRoadsButton);
194        addButtonAction(addCarRoadButton);
195
196        addRadioButtonAction(carRoadNameAll);
197        addRadioButtonAction(carRoadNameInclude);
198        addRadioButtonAction(carRoadNameExclude);
199        
200        addButtonAction(deleteLocoRoadButton);
201        addButtonAction(deleteLocoAllRoadsButton);
202        addButtonAction(addLocoRoadButton);
203
204        addRadioButtonAction(locoRoadNameAll);
205        addRadioButtonAction(locoRoadNameInclude);
206        addRadioButtonAction(locoRoadNameExclude);
207
208        if (_train != null) {
209            trainName.setText(_train.getName());
210            trainDescription.setText(_train.getDescription());
211            updateButtons(true);
212            // listen for train changes
213            _train.addPropertyChangeListener(this);
214        } else {
215            updateButtons(false);
216        }
217        addHelpMenu("package.jmri.jmrit.operations.Operations_TrainRoadOptions", true); // NOI18N
218        updateRoadComboBoxes();
219        updateCarRoadNames();
220        updateLocoRoadNames();
221
222        // get notified if car roads, roads, and owners gets modified
223        InstanceManager.getDefault(CarTypes.class).addPropertyChangeListener(this);
224        InstanceManager.getDefault(CarRoads.class).addPropertyChangeListener(this);
225
226        initMinimumSize(new Dimension(Control.panelWidth500, Control.panelHeight500));
227    }
228
229    // Save
230    @Override
231    public void buttonActionPerformed(java.awt.event.ActionEvent ae) {
232        if (_train != null) {
233            if (ae.getSource() == saveTrainButton) {
234                log.debug("train save button activated");
235                saveTrain();
236            }
237            if (ae.getSource() == addCarRoadButton) {
238                String roadName = (String) comboBoxCarRoads.getSelectedItem();
239                if (_train.addCarRoadName(roadName)) {
240                    updateCarRoadNames();
241                }
242                selectNextItemComboBox(comboBoxCarRoads);
243            }
244            if (ae.getSource() == deleteCarRoadButton) {
245                String roadName = (String) comboBoxCarRoads.getSelectedItem();
246                if (_train.deleteCarRoadName(roadName)) {
247                    updateCarRoadNames();
248                }
249                selectNextItemComboBox(comboBoxCarRoads);
250            }
251            if (ae.getSource() == deleteCarAllRoadsButton) {
252                deleteAllCarRoads();
253            }
254            if (ae.getSource() == addLocoRoadButton) {
255                String roadName = (String) comboBoxLocoRoads.getSelectedItem();
256                if (_train.addLocoRoadName(roadName)) {
257                    updateLocoRoadNames();
258                }
259                selectNextItemComboBox(comboBoxLocoRoads);
260            }
261            if (ae.getSource() == deleteLocoRoadButton) {
262                String roadName = (String) comboBoxLocoRoads.getSelectedItem();
263                if (_train.deleteLocoRoadName(roadName)) {
264                    updateLocoRoadNames();
265                }
266                selectNextItemComboBox(comboBoxLocoRoads);
267            }
268            if (ae.getSource() == deleteLocoAllRoadsButton) {
269                deleteAllLocoRoads();
270            }
271        }
272    }
273
274    @Override
275    public void radioButtonActionPerformed(java.awt.event.ActionEvent ae) {
276        log.debug("radio button activated");
277        if (_train != null) {
278            if (ae.getSource() == carRoadNameAll) {
279                _train.setCarRoadOption(Train.ALL_LOADS);
280                updateCarRoadNames();
281            }
282            if (ae.getSource() == carRoadNameInclude) {
283                _train.setCarRoadOption(Train.INCLUDE_LOADS);
284                updateCarRoadNames();
285            }
286            if (ae.getSource() == carRoadNameExclude) {
287                _train.setCarRoadOption(Train.EXCLUDE_LOADS);
288                updateCarRoadNames();
289            }
290            if (ae.getSource() == locoRoadNameAll) {
291                _train.setLocoRoadOption(Train.ALL_LOADS);
292                updateLocoRoadNames();
293            }
294            if (ae.getSource() == locoRoadNameInclude) {
295                _train.setLocoRoadOption(Train.INCLUDE_LOADS);
296                updateLocoRoadNames();
297            }
298            if (ae.getSource() == locoRoadNameExclude) {
299                _train.setLocoRoadOption(Train.EXCLUDE_LOADS);
300                updateLocoRoadNames();
301            }
302        }
303    }
304
305    protected void updateButtons(boolean enabled) {
306        saveTrainButton.setEnabled(enabled);
307
308        carRoadNameAll.setEnabled(enabled);
309        carRoadNameInclude.setEnabled(enabled);
310        carRoadNameExclude.setEnabled(enabled);
311        
312        locoRoadNameAll.setEnabled(enabled);
313        locoRoadNameInclude.setEnabled(enabled);
314        locoRoadNameExclude.setEnabled(enabled);
315    }
316
317    private static final int NUMBER_ROADS_PER_LINE = 6;
318
319    private void updateCarRoadNames() {
320        log.debug("Update car road names");
321        panelCarRoads.removeAll();
322        if (_train != null) {
323            // set radio button
324            carRoadNameAll.setSelected(_train.getCarRoadOption().equals(Train.ALL_LOADS));
325            carRoadNameInclude.setSelected(_train.getCarRoadOption().equals(Train.INCLUDE_ROADS));
326            carRoadNameExclude.setSelected(_train.getCarRoadOption().equals(Train.EXCLUDE_ROADS));
327
328            pCarRoadControls.setVisible(!carRoadNameAll.isSelected());
329
330            if (!carRoadNameAll.isSelected()) {
331                int x = 0;
332                int y = 0; // vertical position in panel
333
334                for (String roadName : _train.getCarRoadNames()) {
335                    JLabel road = new JLabel();
336                    road.setText(roadName);
337                    addItemTop(panelCarRoads, road, x++, y);
338                    // limit the number of roads per line
339                    if (x > NUMBER_ROADS_PER_LINE) {
340                        y++;
341                        x = 0;
342                    }
343                }
344                revalidate();
345            }
346        } else {
347            carRoadNameAll.setSelected(true);
348        }
349        panelCarRoads.repaint();
350        panelCarRoads.revalidate();
351    }
352    
353    private void updateLocoRoadNames() {
354        log.debug("Update loco road names");
355        panelLocoRoads.removeAll();
356        if (_train != null) {
357            // set radio button
358            locoRoadNameAll.setSelected(_train.getLocoRoadOption().equals(Train.ALL_LOADS));
359            locoRoadNameInclude.setSelected(_train.getLocoRoadOption().equals(Train.INCLUDE_ROADS));
360            locoRoadNameExclude.setSelected(_train.getLocoRoadOption().equals(Train.EXCLUDE_ROADS));
361
362            pLocoRoadControls.setVisible(!locoRoadNameAll.isSelected());
363
364            if (!locoRoadNameAll.isSelected()) {
365                int x = 0;
366                int y = 0; // vertical position in panel
367
368                for (String roadName : _train.getLocoRoadNames()) {
369                    JLabel road = new JLabel();
370                    road.setText(roadName);
371                    addItemTop(panelLocoRoads, road, x++, y);
372                    // limit the number of roads per line
373                    if (x > NUMBER_ROADS_PER_LINE) {
374                        y++;
375                        x = 0;
376                    }
377                }
378                revalidate();
379            }
380        } else {
381            locoRoadNameAll.setSelected(true);
382        }
383        panelLocoRoads.repaint();
384        panelLocoRoads.revalidate();
385    }
386
387    private void deleteAllCarRoads() {
388        if (_train != null) {
389            for (String road : _train.getCarRoadNames()) {
390                _train.deleteCarRoadName(road);
391            }
392        }
393        updateCarRoadNames();
394    }
395    
396    private void deleteAllLocoRoads() {
397        if (_train != null) {
398            for (String road : _train.getLocoRoadNames()) {
399                _train.deleteLocoRoadName(road);
400            }
401        }
402        updateLocoRoadNames();
403    }
404
405    private void saveTrain() {
406        OperationsXml.save();
407        if (Setup.isCloseWindowOnSaveEnabled()) {
408            dispose();
409        }
410    }
411
412    private void updateRoadComboBoxes() {
413        InstanceManager.getDefault(CarRoads.class).updateComboBox(comboBoxCarRoads);
414        InstanceManager.getDefault(CarRoads.class).updateComboBox(comboBoxLocoRoads);
415    }
416
417    @Override
418    public void dispose() {
419        InstanceManager.getDefault(CarTypes.class).removePropertyChangeListener(this);
420        InstanceManager.getDefault(CarRoads.class).removePropertyChangeListener(this);
421        if (_train != null) {
422            _train.removePropertyChangeListener(this);
423        }
424        super.dispose();
425    }
426
427    @Override
428    public void propertyChange(java.beans.PropertyChangeEvent e) {
429        if (Control.SHOW_PROPERTY) {
430            log.debug("Property change: ({}) old: ({}) new: ({})", e.getPropertyName(), e.getOldValue(), e
431                    .getNewValue());
432        }
433        if (e.getPropertyName().equals(CarRoads.CARROADS_CHANGED_PROPERTY)) {
434            updateRoadComboBoxes();
435            updateCarRoadNames();
436        }
437    }
438
439    private final static Logger log = LoggerFactory.getLogger(TrainRoadOptionsFrame.class);
440}