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.rollingstock.cars.CarTypes; 015import jmri.jmrit.operations.setup.Control; 016import jmri.jmrit.operations.setup.Setup; 017import jmri.util.swing.JmriJOptionPane; 018 019/** 020 * Frame to display which locations service certain car types 021 * 022 * @author Dan Boudreau Copyright (C) 2009, 2011, 2022 023 */ 024public class LocationsByCarTypeFrame extends OperationsFrame implements java.beans.PropertyChangeListener { 025 026 LocationManager locationManager = InstanceManager.getDefault(LocationManager.class); 027 028 // checkboxes have the location id or track id as the checkbox name 029 ArrayList<JCheckBox> locationCheckBoxList = new ArrayList<>(); 030 ArrayList<JCheckBox> trackCheckBoxList = new ArrayList<>(); 031 JPanel locationCheckBoxes = new JPanel(); 032 033 // panels 034 JPanel pLocations; 035 036 // major buttons 037 JButton clearButton = new JButton(Bundle.getMessage("ClearAll")); 038 JButton setButton = new JButton(Bundle.getMessage("SelectAll")); 039 JButton saveButton = new JButton(Bundle.getMessage("ButtonSave")); 040 041 // check boxes 042 JCheckBox copyCheckBox = new JCheckBox(Bundle.getMessage("ButtonCopy")); 043 044 // combo boxes 045 JComboBox<String> typeComboBox = InstanceManager.getDefault(CarTypes.class).getComboBox(); 046 JComboBox<String> copyComboBox = InstanceManager.getDefault(CarTypes.class).getComboBox(); 047 048 // selected location 049 Location _location; 050 051 public LocationsByCarTypeFrame() { 052 super(); 053 } 054 055 @Override 056 public void initComponents() { 057 initComponents(NONE); 058 } 059 060 public void initComponents(Location location) { 061 this._location = location; 062 initComponents(NONE); 063 } 064 065 public void initComponents(Location location, String carType) { 066 this._location = location; 067 initComponents(carType); 068 } 069 070 public void initComponents(String carType) { 071 072 // load managers 073 locationManager = InstanceManager.getDefault(LocationManager.class); 074 075 // general GUI config 076 getContentPane().setLayout(new BoxLayout(getContentPane(), BoxLayout.Y_AXIS)); 077 078 // Set up the panels 079 JPanel pCarType = new JPanel(); 080 pCarType.setLayout(new GridBagLayout()); 081 pCarType.setBorder(BorderFactory.createTitledBorder(Bundle.getMessage("Type"))); 082 083 JPanel pCarCopy = new JPanel(); 084 pCarCopy.setLayout(new GridBagLayout()); 085 addItem(pCarCopy, copyComboBox, 0, 0); 086 pCarCopy.setBorder(BorderFactory.createTitledBorder(Bundle.getMessage("CopyType"))); 087 088 addItem(pCarType, typeComboBox, 0, 0); 089 addItem(pCarType, copyCheckBox, 1, 0); 090 addItem(pCarType, pCarCopy, 2, 0); 091 092 typeComboBox.setSelectedItem(carType); 093 copyCheckBox.setToolTipText(Bundle.getMessage("TipCopyCarType")); 094 095 pLocations = new JPanel(); 096 pLocations.setLayout(new GridBagLayout()); 097 JScrollPane locationPane = new JScrollPane(pLocations); 098 locationPane.setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED); 099 locationPane.setBorder(BorderFactory.createTitledBorder(Bundle.getMessage("Locations"))); 100 updateLocations(); 101 102 JPanel pButtons = new JPanel(); 103 pButtons.setLayout(new GridBagLayout()); 104 pButtons.setBorder(BorderFactory.createTitledBorder("")); 105 106 addItem(pButtons, clearButton, 0, 0); 107 addItem(pButtons, setButton, 1, 0); 108 addItem(pButtons, saveButton, 2, 0); 109 110 getContentPane().add(pCarType); 111 getContentPane().add(locationPane); 112 getContentPane().add(pButtons); 113 114 // setup combo box 115 addComboBoxAction(typeComboBox); 116 addComboBoxAction(copyComboBox); 117 118 // setup buttons 119 addButtonAction(setButton); 120 addButtonAction(clearButton); 121 addButtonAction(saveButton); 122 123 // setup checkbox 124 addCheckBoxAction(copyCheckBox); 125 126 locationManager.addPropertyChangeListener(this); 127 InstanceManager.getDefault(CarTypes.class).addPropertyChangeListener(this); 128 129 // build menu 130 JMenuBar menuBar = new JMenuBar(); 131 JMenu toolMenu = new JMenu(Bundle.getMessage("MenuTools")); 132 toolMenu.add(new PrintLocationsByCarTypesAction(false)); 133 toolMenu.add(new PrintLocationsByCarTypesAction(true)); 134 menuBar.add(toolMenu); 135 setJMenuBar(menuBar); 136 addHelpMenu("package.jmri.jmrit.operations.Operations_ModifyLocationsByCarType", true); // NOI18N 137 138 if (_location != null) { 139 setTitle(Bundle.getMessage("TitleModifyLocation")); 140 } else { 141 setTitle(Bundle.getMessage("TitleModifyLocations")); 142 } 143 144 setPreferredSize(null); // we need to resize this frame 145 initMinimumSize(new Dimension(Control.panelWidth300, Control.panelHeight250)); 146 setSize(getWidth() + 25, getHeight()); // make a bit wider to eliminate scroll bar 147 } 148 149 @Override 150 public void comboBoxActionPerformed(java.awt.event.ActionEvent ae) { 151 log.debug("combo box action"); 152 updateLocations(); 153 } 154 155 // Save, Delete, Add 156 @Override 157 public void buttonActionPerformed(java.awt.event.ActionEvent ae) { 158 if (ae.getSource() == saveButton) { 159 save(); 160 } 161 if (ae.getSource() == setButton) { 162 selectCheckboxes(true); 163 } 164 if (ae.getSource() == clearButton) { 165 selectCheckboxes(false); 166 } 167 } 168 169 /** 170 * Update the car types that locations and tracks service. Note that the 171 * checkbox name is the id of the location or track. 172 */ 173 private void save() { 174 if (copyCheckBox.isSelected() && 175 JmriJOptionPane.showConfirmDialog(this, Bundle.getMessage("CopyCarType", 176 typeComboBox.getSelectedItem(), copyComboBox.getSelectedItem()), 177 Bundle.getMessage("CopyCarTypeTitle"), 178 JmriJOptionPane.YES_NO_OPTION) != JmriJOptionPane.YES_OPTION) { 179 return; 180 } 181 log.debug("save {} locations", locationCheckBoxList.size()); 182 removePropertyChangeLocations(); 183 for (JCheckBox cb : new ArrayList<>(locationCheckBoxList)) { 184 Location loc = locationManager.getLocationById(cb.getName()); 185 if (cb.isSelected()) { 186 loc.addTypeName((String) typeComboBox.getSelectedItem()); 187 // save tracks that have the same id as the location 188 for (JCheckBox cbt : new ArrayList<>(trackCheckBoxList)) { 189 String[] id = cbt.getName().split(Location.LOC_TRACK_REGIX); 190 if (loc.getId().equals(id[0])) { 191 Track track = loc.getTrackById(cbt.getName()); 192 if (cbt.isSelected()) { 193 track.addTypeName((String) typeComboBox.getSelectedItem()); 194 } else { 195 track.deleteTypeName((String) typeComboBox.getSelectedItem()); 196 } 197 } 198 } 199 } else { 200 loc.deleteTypeName((String) typeComboBox.getSelectedItem()); 201 } 202 } 203 OperationsXml.save(); 204 updateLocations(); 205 if (Setup.isCloseWindowOnSaveEnabled()) { 206 dispose(); 207 } 208 } 209 210 private void updateLocations() { 211 log.debug("update checkboxes"); 212 removePropertyChangeLocations(); 213 locationCheckBoxList.clear(); 214 trackCheckBoxList.clear(); 215 int x = 0; 216 pLocations.removeAll(); 217 String carType = (String) typeComboBox.getSelectedItem(); 218 if (copyCheckBox.isSelected()) { 219 carType = (String) copyComboBox.getSelectedItem(); 220 } 221 // did the location get deleted? 222 if (_location != null && locationManager.getLocationByName(_location.getName()) == null) { 223 _location = null; 224 } 225 List<Location> locations = locationManager.getLocationsByNameList(); 226 for (Location loc : locations) { 227 // show only one location? 228 if (_location != null && _location != loc) { 229 continue; 230 } 231 loc.addPropertyChangeListener(this); 232 JCheckBox cb = new JCheckBox(loc.getName()); 233 cb.setName(loc.getId()); 234 cb.setToolTipText(Bundle.getMessage("TipLocCarType", carType)); 235 addCheckBoxAction(cb); 236 locationCheckBoxList.add(cb); 237 boolean locAcceptsType = loc.acceptsTypeName(carType); 238 cb.setSelected(locAcceptsType); 239 addItemLeft(pLocations, cb, 0, x++); 240 List<Track> tracks = loc.getTracksByNameList(null); 241 for (Track track : tracks) { 242 track.addPropertyChangeListener(this); 243 cb = new JCheckBox(track.getName()); 244 cb.setName(track.getId()); 245 cb.setToolTipText(Bundle.getMessage("TipTrackCarType", carType)); 246 addCheckBoxAction(cb); 247 trackCheckBoxList.add(cb); 248 cb.setSelected(track.isTypeNameAccepted(carType)); 249 addItemLeft(pLocations, cb, 1, x++); 250 } 251 } 252 pLocations.revalidate(); 253 repaint(); 254 } 255 256 private void updateComboBox() { 257 log.debug("update combobox"); 258 InstanceManager.getDefault(CarTypes.class).updateComboBox(typeComboBox); 259 InstanceManager.getDefault(CarTypes.class).updateComboBox(copyComboBox); 260 } 261 262 private void selectCheckboxes(boolean select) { 263 for (JCheckBox cb : new ArrayList<>(locationCheckBoxList)) { 264 cb.setSelected(select); 265 } 266 for (JCheckBox cb : new ArrayList<>(trackCheckBoxList)) { 267 cb.setSelected(select); 268 } 269 } 270 271 @Override 272 public void checkBoxActionPerformed(java.awt.event.ActionEvent ae) { 273 // copy checkbox? 274 if (ae.getSource() == copyCheckBox) { 275 updateLocations(); 276 } else { 277 JCheckBox cb = (JCheckBox) ae.getSource(); 278 log.debug("Checkbox {} text: {}", cb.getName(), cb.getText()); 279 if (locationCheckBoxList.contains(cb)) { 280 log.debug("Checkbox location {}", cb.getText()); 281 // must deselect tracks if location is deselect 282 if (!cb.isSelected()) { 283 String locId = cb.getName(); 284 for (JCheckBox tcb : new ArrayList<>(trackCheckBoxList)) { 285 String[] id = tcb.getName().split(Location.LOC_TRACK_REGIX); 286 if (locId.equals(id[0])) { 287 tcb.setSelected(false); 288 } 289 } 290 } 291 292 } else if (trackCheckBoxList.contains(cb)) { 293 log.debug("Checkbox track {}", cb.getText()); 294 // Must select location if track is selected 295 if (cb.isSelected()) { 296 String[] loc = cb.getName().split(Location.LOC_TRACK_REGIX); 297 for (JCheckBox lcb : new ArrayList<>(locationCheckBoxList)) { 298 if (lcb.getName().equals(loc[0])) { 299 lcb.setSelected(true); 300 break; 301 } 302 } 303 } 304 } else { 305 log.error("Error checkbox not found"); 306 } 307 } 308 } 309 310 private void removePropertyChangeLocations() { 311 for (JCheckBox cb : new ArrayList<>(locationCheckBoxList)) { 312 // checkbox name is the location id 313 Location loc = locationManager.getLocationById(cb.getName()); 314 if (loc != null) { 315 loc.removePropertyChangeListener(this); 316 List<Track> tracks = loc.getTracksList(); 317 for (Track track : tracks) { 318 track.removePropertyChangeListener(this); 319 } 320 } 321 } 322 } 323 324 @Override 325 public void dispose() { 326 locationManager.removePropertyChangeListener(this); 327 InstanceManager.getDefault(CarTypes.class).removePropertyChangeListener(this); 328 removePropertyChangeLocations(); 329 super.dispose(); 330 } 331 332 @Override 333 public void propertyChange(java.beans.PropertyChangeEvent e) { 334 log.debug("Property change: ({}) old: ({}) new: ({})", e.getPropertyName(), e.getOldValue(), e 335 .getNewValue()); 336 if (e.getPropertyName().equals(LocationManager.LISTLENGTH_CHANGED_PROPERTY) || 337 e.getPropertyName().equals(Location.TYPES_CHANGED_PROPERTY) || 338 e.getPropertyName().equals(Location.NAME_CHANGED_PROPERTY) || 339 e.getPropertyName().equals(Location.TRACK_LISTLENGTH_CHANGED_PROPERTY) || 340 e.getPropertyName().equals(Track.TYPES_CHANGED_PROPERTY) || 341 e.getPropertyName().equals(Track.NAME_CHANGED_PROPERTY)) { 342 updateLocations(); 343 } 344 if (e.getPropertyName().equals(CarTypes.CARTYPES_CHANGED_PROPERTY) || 345 e.getPropertyName().equals(CarTypes.CARTYPES_NAME_CHANGED_PROPERTY)) { 346 updateComboBox(); 347 } 348 } 349 350 private static final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(LocationsByCarTypeFrame.class); 351}