001package jmri.jmrit.operations.locations.tools;
002
003import java.awt.*;
004import java.awt.event.ActionEvent;
005
006import javax.swing.*;
007
008import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
009import jmri.InstanceManager;
010import jmri.jmrit.operations.OperationsFrame;
011import jmri.jmrit.operations.OperationsXml;
012import jmri.jmrit.operations.locations.Location;
013import jmri.jmrit.operations.locations.Track;
014import jmri.jmrit.operations.rollingstock.cars.CarLoads;
015import jmri.jmrit.operations.rollingstock.cars.CarRoads;
016import jmri.jmrit.operations.setup.Control;
017import jmri.jmrit.operations.setup.Setup;
018import jmri.util.swing.JmriJOptionPane;
019
020/**
021 * Frame for user edit of track roads
022 *
023 * @author Dan Boudreau Copyright (C) 2013, 2014, 2026
024 */
025public class TrackRoadEditFrame extends OperationsFrame implements java.beans.PropertyChangeListener {
026
027    Location _location = null;
028    Track _track = null;
029    private static boolean roadAndLoadType = false;
030
031    // panels
032    JPanel pRoadControls = new JPanel();
033    JPanel panelRoads = new JPanel();
034    JScrollPane paneRoads = new JScrollPane(panelRoads);
035
036    // major buttons
037    JButton saveButton = new JButton(Bundle.getMessage("ButtonSave"));
038    JButton addRoadButton = new JButton(Bundle.getMessage("AddRoad"));
039    JButton deleteRoadButton = new JButton(Bundle.getMessage("DeleteRoad"));
040    JButton deleteAllRoadsButton = new JButton(Bundle.getMessage("DeleteAll"));
041
042    // radio buttons
043    JRadioButton roadNameAll = new JRadioButton(Bundle.getMessage("AcceptAll"));
044    JRadioButton roadNameInclude = new JRadioButton(Bundle.getMessage("AcceptOnly"));
045    JRadioButton roadNameExclude = new JRadioButton(Bundle.getMessage("Exclude"));
046
047    // combo box
048    JComboBox<String> comboBoxRoads = InstanceManager.getDefault(CarRoads.class).getComboBox();
049    JComboBox<String> comboBoxLoadTypes = InstanceManager.getDefault(CarLoads.class).getLoadTypesComboBox();
050
051    // check boxes
052    JCheckBox roadAndLoadTypeCheckBox = new JCheckBox(Bundle.getMessage("RoadAndLoadType"));
053
054    // labels
055    JLabel trackName = new JLabel();
056
057    public static final String DISPOSE = "dispose"; // NOI18N
058    public static final int MAX_NAME_LENGTH = Control.max_len_string_track_name;
059
060    public TrackRoadEditFrame() {
061        super(Bundle.getMessage("TitleEditTrackRoads"));
062    }
063
064    public void initComponents(Location location, Track track) {
065        _location = location;
066        _track = track;
067
068        // property changes
069        // listen for car road name changes
070        InstanceManager.getDefault(CarRoads.class).addPropertyChangeListener(this);
071
072        // the following code sets the frame's initial state
073        getContentPane().setLayout(new BoxLayout(getContentPane(), BoxLayout.Y_AXIS));
074
075        // Set up the panels
076        // Layout the panel by rows
077        // row 1
078        JPanel p1 = new JPanel();
079        p1.setLayout(new BoxLayout(p1, BoxLayout.X_AXIS));
080        p1.setMaximumSize(new Dimension(2000, 250));
081
082        // row 1a
083        JPanel pTrackName = new JPanel();
084        pTrackName.setLayout(new GridBagLayout());
085        pTrackName.setBorder(BorderFactory.createTitledBorder(Bundle.getMessage("Track")));
086        addItem(pTrackName, trackName, 0, 0);
087
088        // row 1b
089        JPanel pLocationName = new JPanel();
090        pLocationName.setLayout(new GridBagLayout());
091        pLocationName.setBorder(BorderFactory.createTitledBorder(Bundle.getMessage("Location")));
092        addItem(pLocationName, new JLabel(_location.getName()), 0, 0);
093
094        p1.add(pTrackName);
095        p1.add(pLocationName);
096
097        // row 3
098        JPanel p3 = new JPanel();
099        p3.setLayout(new BoxLayout(p3, BoxLayout.Y_AXIS));
100        JScrollPane pane3 = new JScrollPane(p3);
101        pane3.setBorder(BorderFactory.createTitledBorder(Bundle.getMessage("RoadsTrack")));
102        pane3.setMaximumSize(new Dimension(2000, 400));
103
104        JPanel pRoadRadioButtons = new JPanel();
105        pRoadRadioButtons.setLayout(new FlowLayout());
106
107        pRoadRadioButtons.add(roadNameAll);
108        pRoadRadioButtons.add(roadNameInclude);
109        pRoadRadioButtons.add(roadNameExclude);
110        pRoadRadioButtons.add(roadAndLoadTypeCheckBox);
111
112        pRoadControls.setLayout(new FlowLayout());
113
114        pRoadControls.add(comboBoxRoads);
115        pRoadControls.add(comboBoxLoadTypes);
116        pRoadControls.add(addRoadButton);
117        pRoadControls.add(deleteRoadButton);
118        pRoadControls.add(deleteAllRoadsButton);
119
120        pRoadControls.setVisible(false);
121        comboBoxLoadTypes.setVisible(false);
122        roadAndLoadTypeCheckBox.setSelected(roadAndLoadType);
123
124        p3.add(pRoadRadioButtons);
125        p3.add(pRoadControls);
126
127        // row 4
128        panelRoads.setLayout(new GridBagLayout());
129        paneRoads.setBorder(BorderFactory.createTitledBorder(Bundle.getMessage("Roads")));
130
131        ButtonGroup roadGroup = new ButtonGroup();
132        roadGroup.add(roadNameAll);
133        roadGroup.add(roadNameInclude);
134        roadGroup.add(roadNameExclude);
135
136        // row 12
137        JPanel panelButtons = new JPanel();
138        panelButtons.setLayout(new GridBagLayout());
139        panelButtons.setBorder(BorderFactory.createTitledBorder(""));
140        panelButtons.setMaximumSize(new Dimension(2000, 200));
141
142        // row 13
143        addItem(panelButtons, saveButton, 0, 0);
144
145        getContentPane().add(p1);
146        getContentPane().add(pane3);
147        getContentPane().add(paneRoads);
148        getContentPane().add(panelButtons);
149
150        // setup buttons
151        addButtonAction(saveButton);
152
153        addButtonAction(deleteRoadButton);
154        addButtonAction(deleteAllRoadsButton);
155        addButtonAction(addRoadButton);
156
157        addRadioButtonAction(roadNameAll);
158        addRadioButtonAction(roadNameInclude);
159        addRadioButtonAction(roadNameExclude);
160
161        addCheckBoxAction(roadAndLoadTypeCheckBox);
162
163        // road fields and enable buttons
164        if (_track != null) {
165            _track.addPropertyChangeListener(this);
166            trackName.setText(_track.getName());
167            enableButtons(true);
168        } else {
169            enableButtons(false);
170        }
171
172        updateRoadComboBox();
173        updateRoadNames();
174
175        // add help menu to window
176        addHelpMenu("package.jmri.jmrit.operations.Operations_RoadOptions", true); // NOI18N
177
178        initMinimumSize(new Dimension(Control.panelWidth600, Control.panelHeight400));
179    }
180
181    // Save, Delete, Add
182    @SuppressFBWarnings(value = "ST_WRITE_TO_STATIC_FROM_INSTANCE_METHOD", justification = "GUI ease of use")
183    @Override
184    public void buttonActionPerformed(ActionEvent ae) {
185        if (_track == null) {
186            return;
187        }
188        if (ae.getSource() == saveButton) {
189            log.debug("track save button activated");
190            if (!checkForErrors()) {
191                roadAndLoadType = roadAndLoadTypeCheckBox.isSelected();
192                OperationsXml.save();
193                if (Setup.isCloseWindowOnSaveEnabled()) {
194                    dispose();
195                }
196            }
197        }
198        if (ae.getSource() == addRoadButton) {
199            String roadName = (String) comboBoxRoads.getSelectedItem();
200            if (roadAndLoadTypeCheckBox.isSelected()) {
201                roadName = roadName + CarRoads.SPLIT_CHAR + comboBoxLoadTypes.getSelectedItem();
202            }
203            _track.addRoadName(roadName);
204            selectNextItemComboBox(comboBoxRoads);
205        }
206        if (ae.getSource() == deleteRoadButton) {
207            String roadName = (String) comboBoxRoads.getSelectedItem();
208            if (roadAndLoadTypeCheckBox.isSelected()) {
209                roadName = roadName + CarRoads.SPLIT_CHAR + comboBoxLoadTypes.getSelectedItem();
210            }
211            _track.deleteRoadName(roadName);
212            selectNextItemComboBox(comboBoxRoads);
213        }
214        if (ae.getSource() == deleteAllRoadsButton) {
215            deleteAllRoads();
216        }
217    }
218
219    protected void enableButtons(boolean enabled) {
220        saveButton.setEnabled(enabled);
221        roadNameAll.setEnabled(enabled);
222        roadNameInclude.setEnabled(enabled);
223        roadNameExclude.setEnabled(enabled);
224    }
225
226    @Override
227    public void radioButtonActionPerformed(ActionEvent ae) {
228        log.debug("radio button activated");
229        if (ae.getSource() == roadNameAll) {
230            _track.setRoadOption(Track.ALL_ROADS);
231        }
232        if (ae.getSource() == roadNameInclude) {
233            _track.setRoadOption(Track.INCLUDE_ROADS);
234        }
235        if (ae.getSource() == roadNameExclude) {
236            _track.setRoadOption(Track.EXCLUDE_ROADS);
237        }
238    }
239
240    private void updateRoadComboBox() {
241        InstanceManager.getDefault(CarRoads.class).updateComboBox(comboBoxRoads);
242    }
243
244    private void updateRoadNames() {
245        log.debug("Update road names");
246        panelRoads.removeAll();
247        if (_track != null) {
248            // set radio button
249            roadNameAll.setSelected(_track.getRoadOption().equals(Track.ALL_ROADS));
250            roadNameInclude.setSelected(_track.getRoadOption().equals(Track.INCLUDE_ROADS));
251            roadNameExclude.setSelected(_track.getRoadOption().equals(Track.EXCLUDE_ROADS));
252
253            pRoadControls.setVisible(!roadNameAll.isSelected());
254
255            if (!roadNameAll.isSelected()) {
256                int x = 0;
257                int y = 0; // vertical position in panel
258
259                int numberOfRoads = getNumberOfCheckboxesPerLine();
260                for (String roadName : _track.getRoadNames()) {
261                    JLabel road = new JLabel();
262                    road.setText(roadName);
263                    addItemTop(panelRoads, road, x++, y);
264                    // limit the number of roads per line
265                    if (x > numberOfRoads) {
266                        y++;
267                        x = 0;
268                    }
269                }
270                revalidate();
271            }
272        } else {
273            roadNameAll.setSelected(true);
274        }
275        panelRoads.repaint();
276        panelRoads.revalidate();
277    }
278
279    private void deleteAllRoads() {
280        if (_track != null) {
281            for (String roadName : _track.getRoadNames()) {
282                _track.deleteRoadName(roadName);
283            }
284        }
285    }
286
287    @Override
288    public void checkBoxActionPerformed(ActionEvent ae) {
289        JCheckBox b = (JCheckBox) ae.getSource();
290        comboBoxLoadTypes.setVisible(b.isSelected());
291    }
292
293    private boolean checkForErrors() {
294        if (_track.getRoadOption().equals(Track.INCLUDE_ROADS) && _track.getRoadNames().length == 0) {
295            JmriJOptionPane.showMessageDialog(this, Bundle.getMessage("ErrorNeedRoads"),
296                    Bundle.getMessage("ErrorNoRoads"),
297                    JmriJOptionPane.ERROR_MESSAGE);
298            return true;
299        }
300        return false;
301    }
302
303    @Override
304    public void dispose() {
305        if (_track != null) {
306            _track.removePropertyChangeListener(this);
307        }
308        InstanceManager.getDefault(CarRoads.class).removePropertyChangeListener(this);
309        super.dispose();
310    }
311
312    @Override
313    public void propertyChange(java.beans.PropertyChangeEvent e) {
314        if (Control.SHOW_PROPERTY) {
315            log.debug("Property change: ({}) old: ({}) new: ({})", e.getPropertyName(), e.getOldValue(), e
316                    .getNewValue());
317        }
318        if (e.getPropertyName().equals(CarRoads.CARROADS_CHANGED_PROPERTY)) {
319            updateRoadComboBox();
320            updateRoadNames();
321        }
322        if (e.getPropertyName().equals(Track.ROADS_CHANGED_PROPERTY)) {
323            updateRoadNames();
324        }
325    }
326
327    private static final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(TrackRoadEditFrame.class);
328}