001package jmri.jmrit.operations.locations.schedules.tools; 002 003import java.awt.Dimension; 004import java.awt.GridBagLayout; 005 006import javax.swing.*; 007 008import org.slf4j.Logger; 009import org.slf4j.LoggerFactory; 010 011import jmri.InstanceManager; 012import jmri.jmrit.operations.OperationsFrame; 013import jmri.jmrit.operations.locations.*; 014import jmri.jmrit.operations.locations.schedules.Schedule; 015import jmri.jmrit.operations.locations.schedules.ScheduleItem; 016import jmri.jmrit.operations.rollingstock.cars.CarLoads; 017import jmri.jmrit.operations.rollingstock.cars.CarTypes; 018import jmri.jmrit.operations.rollingstock.cars.tools.CarLoadEditFrameAction; 019import jmri.jmrit.operations.rollingstock.cars.tools.PrintCarLoadsAction; 020import jmri.jmrit.operations.setup.Control; 021 022/** 023 * Frame to display the staging tracks and spurs with schedules. Lists staging 024 * tracks that will service the car type and the spurs that will accept the 025 * selected load name. 026 * 027 * @author Dan Boudreau Copyright (C) 2023 028 */ 029public class SchedulesAndStagingFrame extends OperationsFrame implements java.beans.PropertyChangeListener { 030 031 // managers' 032 LocationManager locationManager = InstanceManager.getDefault(LocationManager.class); 033 CarLoads carLoads = InstanceManager.getDefault(CarLoads.class); 034 CarTypes carTypes = InstanceManager.getDefault(CarTypes.class); 035 036 // combo box 037 JComboBox<String> typesComboBox = carTypes.getComboBox(); 038 JComboBox<String> loadsComboBox = new JComboBox<>(); 039 040 // panels 041 JPanel locationsPanel; 042 043 // checkbox 044 JCheckBox generatedLoadsCheckBox = new JCheckBox(Bundle.getMessage("generatedLoads")); 045 JCheckBox allLoadsCheckBox = new JCheckBox(Bundle.getMessage("allLoads")); 046 047 public SchedulesAndStagingFrame() { 048 super(Bundle.getMessage("MenuItemStagingSchedules")); 049 050 // the following code sets the frame's initial state 051 getContentPane().setLayout(new BoxLayout(getContentPane(), BoxLayout.Y_AXIS)); 052 053 // load the panel 054 JPanel p1 = new JPanel(); 055 p1.setMaximumSize(new Dimension(2000, 200)); 056 p1.setLayout(new BoxLayout(p1, BoxLayout.X_AXIS)); 057 058 JPanel type = new JPanel(); 059 type.setLayout(new GridBagLayout()); 060 type.setBorder(BorderFactory.createTitledBorder(Bundle.getMessage("Type"))); 061 addItem(type, typesComboBox, 0, 0); 062 063 JPanel load = new JPanel(); 064 load.setLayout(new GridBagLayout()); 065 load.setBorder(BorderFactory.createTitledBorder(Bundle.getMessage("Load"))); 066 addItem(load, loadsComboBox, 0, 0); 067 addItem(load, generatedLoadsCheckBox, 1, 0); 068 addItem(load, allLoadsCheckBox, 2, 0); 069 070 p1.add(type); 071 p1.add(load); 072 073 locationsPanel = new JPanel(); 074 locationsPanel.setLayout(new GridBagLayout()); 075 JScrollPane locationsPane = new JScrollPane(locationsPanel); 076 locationsPane.setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED); 077 locationsPane.setBorder(BorderFactory.createTitledBorder(Bundle.getMessage("Staging"))); 078 079 getContentPane().add(p1); 080 getContentPane().add(locationsPane); 081 082 addComboBoxAction(typesComboBox); 083 addComboBoxAction(loadsComboBox); 084 085 generatedLoadsCheckBox.setSelected(true); 086 generatedLoadsCheckBox.setToolTipText(Bundle.getMessage("generatedLoadsTip")); 087 088 addCheckBoxAction(generatedLoadsCheckBox); 089 addCheckBoxAction(allLoadsCheckBox); 090 091 // property changes 092 locationManager.addPropertyChangeListener(this); 093 carTypes.addPropertyChangeListener(this); 094 carLoads.addPropertyChangeListener(this); 095 096 // build menu 097 JMenuBar menuBar = new JMenuBar(); 098 JMenu toolMenu = new JMenu(Bundle.getMessage("MenuTools")); 099 toolMenu.add(new CarLoadEditFrameAction()); 100 toolMenu.add(new PrintCarLoadsAction(true)); 101 toolMenu.add(new PrintCarLoadsAction(false)); 102 menuBar.add(toolMenu); 103 setJMenuBar(menuBar); 104 addHelpMenu("package.jmri.jmrit.operations.Operations_ShowStagingAndSchedulesByCarTypeAndLoad", true); // NOI18N 105 106 // select first item to load contents 107 typesComboBox.setSelectedIndex(0); 108 109 initMinimumSize(new Dimension(Control.panelWidth700, Control.panelHeight250)); 110 } 111 112 @Override 113 public void comboBoxActionPerformed(java.awt.event.ActionEvent ae) { 114 if (ae.getSource() == typesComboBox) { 115 updateLoadComboBox(); 116 } 117 if (ae.getSource() == loadsComboBox) { 118 updateLocations(); 119 } 120 121 } 122 123 @Override 124 public void checkBoxActionPerformed(java.awt.event.ActionEvent ae) { 125 loadsComboBox.setEnabled(!allLoadsCheckBox.isSelected()); 126 updateLocations(); 127 } 128 129 private void updateLoadComboBox() { 130 String type = (String) typesComboBox.getSelectedItem(); 131 carLoads.updateComboBox(type, loadsComboBox); 132 } 133 134 int x; 135 136 private void updateLocations() { 137 locationsPanel.removeAll(); 138 // create header 139 addItemLeft(locationsPanel, new JLabel(Bundle.getMessage("Track")), 1, 0); 140 addItemLeft(locationsPanel, new JLabel(Bundle.getMessage("CarLoadOptions")), 2, 0); 141 addItemLeft(locationsPanel, new JLabel(Bundle.getMessage("ShipLoadOption")), 3, 0); 142 addItemLeft(locationsPanel, new JLabel(Bundle.getMessage("Load")), 4, 0); 143 addItemLeft(locationsPanel, new JLabel(Bundle.getMessage("destinationTrack")), 5, 0); 144 addItemLeft(locationsPanel, new JLabel(Bundle.getMessage("LoadOption")), 6, 0); 145 addItemLeft(locationsPanel, new JLabel(Bundle.getMessage("Schedule")), 7, 0); 146 147 x = 1; 148 for (Location location : locationManager.getLocationsByNameList()) { 149 if (!location.isStaging()) 150 continue; 151 location.removePropertyChangeListener(this); 152 location.addPropertyChangeListener(this); 153 addItemLeft(locationsPanel, new JLabel(location.getName()), 0, x++); 154 // list staging tracks 155 for (Track track : location.getTracksByNameList(Track.STAGING)) { 156 // listen for changes 157 track.removePropertyChangeListener(this); 158 track.addPropertyChangeListener(this); 159 addItemLeft(locationsPanel, new JLabel(track.getName()), 1, x); 160 addItemLeft(locationsPanel, new JLabel(getTrackCarLoadOptions(track)), 2, x); 161 addItemLeft(locationsPanel, new JLabel(track.getShipLoadOptionString()), 3, x); 162 listSpurs(track); 163 x++; 164 } 165 } 166 locationsPanel.revalidate(); 167 revalidate(); 168 repaint(); 169 } 170 171 private String getTrackCarLoadOptions(Track track) { 172 StringBuffer options = new StringBuffer(); 173 if (track.isLoadSwapEnabled()) { 174 options.append(Bundle.getMessage("ABV_SwapDefaultLoads") + ", "); 175 } 176 if (track.isLoadEmptyEnabled()) { 177 options.append(Bundle.getMessage("ABV_EmptyDefaultLoads") + ", "); 178 } 179 if (track.isRemoveCustomLoadsEnabled()) { 180 options.append(Bundle.getMessage("ABV_EmptyCustomLoads") + ", "); 181 } 182 if (track.isAddCustomLoadsEnabled()) { 183 options.append(Bundle.getMessage("ABV_GenerateCustomLoad") + ", "); 184 } 185 if (track.isAddCustomLoadsAnySpurEnabled()) { 186 options.append(Bundle.getMessage("ABV_GenerateCustomLoadAnySpur") + ", "); 187 } 188 if (track.isAddCustomLoadsAnyStagingTrackEnabled()) { 189 options.append(Bundle.getMessage("ABV_GereateCustomLoadStaging")); 190 } 191 return options.toString(); 192 } 193 194 /* 195 * List spurs that this staging track can service 196 */ 197 private void listSpurs(Track track) { 198 // is this staging track configured to generate custom loads? 199 if (!track.isAddCustomLoadsAnySpurEnabled() && !track.isAddCustomLoadsEnabled()) { 200 return; 201 } 202 String type = (String) typesComboBox.getSelectedItem(); 203 if (!track.isTypeNameAccepted(type)) { 204 return; 205 } 206 if (allLoadsCheckBox.isSelected()) { 207 for (String load : carLoads.getNames(type)) { 208 listSpurs(track, type, load); 209 } 210 } else { 211 String load = (String) loadsComboBox.getSelectedItem(); 212 listSpurs(track, type, load); 213 } 214 } 215 216 private void listSpurs(Track track, String type, String load) { 217 if (load == null || !track.isLoadNameAndCarTypeShipped(load, type)) { 218 return; 219 } 220 // ignore default empty and load names 221 if (generatedLoadsCheckBox.isSelected() && 222 (load.equals(carLoads.getDefaultEmptyName()) || load.equals(carLoads.getDefaultLoadName()))) { 223 return; 224 } 225 // now list all of the spurs with schedules for this type and load 226 for (Location location : locationManager.getLocationsByNameList()) { 227 // only spurs have schedules 228 if (!location.hasSpurs()) 229 continue; 230 // find spurs with a schedule 231 for (Track spur : location.getTracksByNameList(Track.SPUR)) { 232 Schedule sch = spur.getSchedule(); 233 if (sch == null) { 234 continue; 235 } 236 // listen for changes 237 spur.removePropertyChangeListener(this); 238 spur.addPropertyChangeListener(this); 239 sch.removePropertyChangeListener(this); 240 sch.addPropertyChangeListener(this); 241 // determine if schedule is requesting car type and load 242 for (ScheduleItem si : sch.getItemsBySequenceList()) { 243 if (spur.isLoadNameAccepted(load) && 244 si.getTypeName().equals(type) && 245 (si.getReceiveLoadName().equals(load) || 246 (si.getReceiveLoadName().equals(ScheduleItem.NONE) && 247 !generatedLoadsCheckBox.isSelected()))) { 248 addItemLeft(locationsPanel, new JLabel(load), 4, x); 249 addItemLeft(locationsPanel, new JLabel(location.getName() + " (" + spur.getName() + ")"), 5, x); 250 addItemLeft(locationsPanel, new JLabel(spur.getLoadOptionString()), 6, x); 251 addItemLeft(locationsPanel, new JLabel(sch.getName() + " " + si.getId()), 7, x++); 252 } 253 } 254 } 255 } 256 } 257 258 @Override 259 public void dispose() { 260 locationManager.removePropertyChangeListener(this); 261 carTypes.removePropertyChangeListener(this); 262 carLoads.removePropertyChangeListener(this); 263 for (Location location : locationManager.getLocationsByNameList()) { 264 location.removePropertyChangeListener(this); 265 } 266 for (Track spur : locationManager.getTracks(Track.SPUR)) { 267 Schedule sch = spur.getSchedule(); 268 if (sch == null) { 269 continue; 270 } 271 spur.removePropertyChangeListener(this); 272 sch.removePropertyChangeListener(this); 273 } 274 super.dispose(); 275 } 276 277 @Override 278 public void propertyChange(java.beans.PropertyChangeEvent e) { 279 log.debug("Property change ({}) old: ({}) new: ({})", e.getPropertyName(), e.getOldValue(), e.getNewValue()); // NOI18N 280 281 if (e.getPropertyName().equals(CarTypes.CARTYPES_CHANGED_PROPERTY)) { 282 carTypes.updateComboBox(typesComboBox); 283 } 284 if (e.getSource().getClass().equals(CarLoads.class)) { 285 carLoads.updateComboBox((String) typesComboBox.getSelectedItem(), loadsComboBox); 286 } 287 if (e.getSource().getClass().equals(Schedule.class) || 288 e.getSource().getClass().equals(LocationManager.class) || 289 e.getPropertyName().equals(Track.LOADS_CHANGED_PROPERTY) || 290 e.getPropertyName().equals(Track.LOAD_OPTIONS_CHANGED_PROPERTY) || 291 e.getPropertyName().equals(Location.TYPES_CHANGED_PROPERTY) || 292 e.getPropertyName().equals(Track.TYPES_CHANGED_PROPERTY)) { 293 updateLocations(); 294 } 295 } 296 297 private final static Logger log = LoggerFactory.getLogger(SchedulesAndStagingFrame.class); 298 299}