001package jmri.jmrit.operations.locations.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.locations.*;
014import jmri.jmrit.operations.setup.Control;
015import jmri.jmrit.operations.setup.Setup;
016
017/**
018 * Frame to display and modify which locations have quick service tracks
019 *
020 * @author Dan Boudreau Copyright (C) 2026
021 */
022public class LocationsByQuickServiceFrame extends OperationsFrame implements java.beans.PropertyChangeListener {
023
024    LocationManager locationManager = InstanceManager.getDefault(LocationManager.class);
025
026    // checkboxes have the location id or track id as the checkbox name
027    ArrayList<JCheckBox> locationCheckBoxList = new ArrayList<>();
028    ArrayList<JCheckBox> trackCheckBoxList = new ArrayList<>();
029    JPanel locationCheckBoxes = new JPanel();
030
031    // panels
032    JPanel pLocations;
033
034    // major buttons
035    JButton clearButton = new JButton(Bundle.getMessage("ClearAll"));
036    JButton setButton = new JButton(Bundle.getMessage("SelectAll"));
037    JButton saveButton = new JButton(Bundle.getMessage("ButtonSave"));
038
039    // selected location
040    Location _location;
041
042    public LocationsByQuickServiceFrame() {
043        super();
044    }
045
046    public void initComponents(Location location) {
047        this._location = location;
048        initComponents();
049    }
050
051    @Override
052    public void initComponents() {
053
054        // general GUI config
055        getContentPane().setLayout(new BoxLayout(getContentPane(), BoxLayout.Y_AXIS));
056
057        // Set up the panels
058        JPanel pCarType = new JPanel();
059        pCarType.setLayout(new GridBagLayout());
060        pCarType.setBorder(BorderFactory.createTitledBorder(Bundle.getMessage("Type")));
061
062        pLocations = new JPanel();
063        pLocations.setLayout(new GridBagLayout());
064        JScrollPane locationPane = new JScrollPane(pLocations);
065        locationPane.setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED);
066        locationPane.setBorder(BorderFactory.createTitledBorder(Bundle.getMessage("Locations")));
067        updateLocations();
068
069        JPanel pButtons = new JPanel();
070        pButtons.setLayout(new GridBagLayout());
071        pButtons.setBorder(BorderFactory.createTitledBorder(""));
072
073        addItem(pButtons, clearButton, 0, 0);
074        addItem(pButtons, setButton, 1, 0);
075        addItem(pButtons, saveButton, 2, 0);
076
077        getContentPane().add(pCarType);
078        getContentPane().add(locationPane);
079        getContentPane().add(pButtons);
080
081        // setup buttons
082        addButtonAction(setButton);
083        addButtonAction(clearButton);
084        addButtonAction(saveButton);
085
086        locationManager.addPropertyChangeListener(this);
087
088        // build menu
089        addHelpMenu("package.jmri.jmrit.operations.Operations_ModifyLocationsByQuickService", true); // NOI18N
090
091        if (_location != null) {
092            setTitle(Bundle.getMessage("TitleModifyLocQuickService"));
093        } else {
094            setTitle(Bundle.getMessage("TitleModifyLocsQuickService"));
095        }
096        
097        setPreferredSize(null); // we need to resize this frame
098        initMinimumSize(new Dimension(Control.panelWidth400, Control.panelHeight250));
099        setSize(getWidth() + 25, getHeight()); // make a bit wider to eliminate scroll bar
100    }
101    
102    @Override
103    public void checkBoxActionPerformed(java.awt.event.ActionEvent ae) {
104        JCheckBox cb = (JCheckBox) ae.getSource();
105        log.debug("Checkbox {} text: {}", cb.getName(), cb.getText());
106        if (locationCheckBoxList.contains(cb)) {
107            log.debug("Checkbox location {}", cb.getText());
108            // update all tracks at location{
109                String locId = cb.getName();
110                for (JCheckBox cbt : new ArrayList<>(trackCheckBoxList)) {
111                    String[] id = cbt.getName().split(Location.LOC_TRACK_REGIX);
112                    if (locId.equals(id[0])) {
113                        cbt.setSelected(cb.isSelected());
114                }
115            }
116        }
117    }
118
119    // Save, Delete, Add
120    @Override
121    public void buttonActionPerformed(java.awt.event.ActionEvent ae) {
122        if (ae.getSource() == saveButton) {
123            save();
124        }
125        if (ae.getSource() == setButton) {
126            selectCheckboxes(true);
127        }
128        if (ae.getSource() == clearButton) {
129            selectCheckboxes(false);
130        }
131    }
132
133    /**
134     * Update the car types that locations and tracks service. Note that the
135     * checkbox name is the id of the location or track.
136     */
137    private void save() {
138        log.debug("save {} locations", locationCheckBoxList.size());
139        removePropertyChangeLocations();
140        for (JCheckBox cb : new ArrayList<>(locationCheckBoxList)) {
141            Location loc = locationManager.getLocationById(cb.getName());
142            // save tracks that have the same id as the location
143            for (JCheckBox cbt : new ArrayList<>(trackCheckBoxList)) {
144                String[] id = cbt.getName().split(Location.LOC_TRACK_REGIX);
145                if (loc.getId().equals(id[0])) {
146                    Track track = loc.getTrackById(cbt.getName());
147                    track.setQuickServiceEnabled(cb.isSelected() && cbt.isSelected());
148                }
149            }
150        }
151        OperationsXml.save();
152        updateLocations();
153        if (Setup.isCloseWindowOnSaveEnabled()) {
154            dispose();
155        }
156    }
157
158    private void updateLocations() {
159        log.debug("update checkboxes");
160        removePropertyChangeLocations();
161        locationCheckBoxList.clear();
162        trackCheckBoxList.clear();
163        int x = 0;
164        pLocations.removeAll();
165        // did the location get deleted?
166        if (_location != null && locationManager.getLocationByName(_location.getName()) == null) {
167            _location = null;
168        }
169        List<Location> locations = locationManager.getLocationsByNameList();
170        for (Location loc : locations) {
171            // show only one location?
172            if (_location != null && _location != loc) {
173                continue;
174            }
175            loc.addPropertyChangeListener(this);
176            JCheckBox cb = new JCheckBox(loc.getName());
177            cb.setName(loc.getId());
178            addCheckBoxAction(cb);
179            locationCheckBoxList.add(cb);
180            addItemLeft(pLocations, cb, 0, x++);
181            cb.setSelected(loc.hasQuickService());
182            List<Track> tracks = loc.getTracksByNameList(null);
183            for (Track track : tracks) {
184                track.addPropertyChangeListener(this);
185                JCheckBox cbt = new JCheckBox(track.getName());
186                cbt.setName(track.getId());
187                trackCheckBoxList.add(cbt);
188                cbt.setSelected(track.isQuickServiceEnabled());
189                addItemLeft(pLocations, cbt, 1, x++);
190            }
191        }
192        pLocations.revalidate();
193        repaint();
194    }
195
196    private void selectCheckboxes(boolean select) {
197        for (JCheckBox cb : new ArrayList<>(locationCheckBoxList)) {
198            cb.setSelected(select);
199        }
200        for (JCheckBox cb : new ArrayList<>(trackCheckBoxList)) {
201            cb.setSelected(select);
202        }
203    }
204
205    private void removePropertyChangeLocations() {
206        for (JCheckBox cb : new ArrayList<>(locationCheckBoxList)) {
207            // checkbox name is the location id
208            Location loc = locationManager.getLocationById(cb.getName());
209            if (loc != null) {
210                loc.removePropertyChangeListener(this);
211                List<Track> tracks = loc.getTracksList();
212                for (Track track : tracks) {
213                    track.removePropertyChangeListener(this);
214                }
215            }
216        }
217    }
218
219    @Override
220    public void dispose() {
221        locationManager.removePropertyChangeListener(this);
222        removePropertyChangeLocations();
223        super.dispose();
224    }
225
226    @Override
227    public void propertyChange(java.beans.PropertyChangeEvent e) {
228        log.debug("Property change: ({}) old: ({}) new: ({})", e.getPropertyName(), e.getOldValue(), e
229                .getNewValue());
230        if (e.getPropertyName().equals(LocationManager.LISTLENGTH_CHANGED_PROPERTY) ||
231                e.getPropertyName().equals(Location.NAME_CHANGED_PROPERTY) ||
232                e.getPropertyName().equals(Location.TRACK_LISTLENGTH_CHANGED_PROPERTY) ||
233                e.getPropertyName().equals(Track.LOAD_OPTIONS_CHANGED_PROPERTY) ||
234                e.getPropertyName().equals(Track.NAME_CHANGED_PROPERTY)) {
235            updateLocations();
236        }
237    }
238
239    private static final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(LocationsByQuickServiceFrame.class);
240}