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 spurs with schedules and their loads 024 * 025 * @author Dan Boudreau Copyright (C) 2012, 2015, 2021 026 */ 027public class SchedulesByLoadFrame extends OperationsFrame implements java.beans.PropertyChangeListener { 028 029 // managers' 030 LocationManager locationManager = InstanceManager.getDefault(LocationManager.class); 031 CarLoads carLoads = InstanceManager.getDefault(CarLoads.class); 032 CarTypes carTypes = InstanceManager.getDefault(CarTypes.class); 033 034 // combo box 035 JComboBox<String> typesComboBox = carTypes.getComboBox(); 036 JComboBox<String> loadsComboBox = new JComboBox<>(); 037 038 // panels 039 JPanel locationsPanel; 040 041 // checkbox 042 JCheckBox allLoadsCheckBox = new JCheckBox(Bundle.getMessage("allLoads")); 043 JCheckBox allTypesCheckBox = new JCheckBox(Bundle.getMessage("allTypes")); 044 045 public SchedulesByLoadFrame() { 046 super(Bundle.getMessage("MenuItemShowSchedulesByLoad")); 047 048 // the following code sets the frame's initial state 049 getContentPane().setLayout(new BoxLayout(getContentPane(), BoxLayout.Y_AXIS)); 050 051 // load the panel 052 JPanel p1 = new JPanel(); 053 p1.setMaximumSize(new Dimension(2000, 200)); 054 p1.setLayout(new BoxLayout(p1, BoxLayout.X_AXIS)); 055 056 JPanel type = new JPanel(); 057 type.setLayout(new GridBagLayout()); 058 type.setBorder(BorderFactory.createTitledBorder(Bundle.getMessage("Type"))); 059 addItem(type, typesComboBox, 0, 0); 060 addItem(type, allTypesCheckBox, 1, 0); 061 062 JPanel load = new JPanel(); 063 load.setLayout(new GridBagLayout()); 064 load.setBorder(BorderFactory.createTitledBorder(Bundle.getMessage("Load"))); 065 addItem(load, loadsComboBox, 0, 0); 066 addItem(load, allLoadsCheckBox, 1, 0); 067 068 p1.add(type); 069 p1.add(load); 070 071 locationsPanel = new JPanel(); 072 locationsPanel.setLayout(new GridBagLayout()); 073 JScrollPane locationsPane = new JScrollPane(locationsPanel); 074 locationsPane.setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED); 075 locationsPane.setBorder(BorderFactory.createTitledBorder(Bundle.getMessage("Locations"))); 076 077 getContentPane().add(p1); 078 getContentPane().add(locationsPane); 079 080 addComboBoxAction(typesComboBox); 081 addComboBoxAction(loadsComboBox); 082 083 addCheckBoxAction(allTypesCheckBox); 084 addCheckBoxAction(allLoadsCheckBox); 085 086 // property changes 087 locationManager.addPropertyChangeListener(this); 088 carTypes.addPropertyChangeListener(this); 089 carLoads.addPropertyChangeListener(this); 090 091 // build menu 092 JMenuBar menuBar = new JMenuBar(); 093 JMenu toolMenu = new JMenu(Bundle.getMessage("MenuTools")); 094 toolMenu.add(new CarLoadEditFrameAction()); 095 toolMenu.addSeparator(); 096 toolMenu.add(new PrintCarLoadsAction(true)); 097 toolMenu.add(new PrintCarLoadsAction(false)); 098 menuBar.add(toolMenu); 099 setJMenuBar(menuBar); 100 addHelpMenu("package.jmri.jmrit.operations.Operations_ShowSchedulesByCarTypeAndLoad", true); // NOI18N 101 102 // select first item to load contents 103 typesComboBox.setSelectedIndex(0); 104 105 initMinimumSize(new Dimension(Control.panelWidth700, Control.panelHeight250)); 106 } 107 108 @Override 109 public void comboBoxActionPerformed(java.awt.event.ActionEvent ae) { 110 if (ae.getSource() == typesComboBox) { 111 updateLoadComboBox(); 112 } 113 if (ae.getSource() == loadsComboBox) { 114 updateLocations(); 115 } 116 117 } 118 119 @Override 120 public void checkBoxActionPerformed(java.awt.event.ActionEvent ae) { 121 typesComboBox.setEnabled(!allTypesCheckBox.isSelected()); 122 loadsComboBox.setEnabled(!allLoadsCheckBox.isSelected()); 123 updateLoadComboBox(); 124 updateLocations(); 125 } 126 127 private void updateLoadComboBox() { 128 if (allTypesCheckBox.isSelected()) { 129 carLoads.updateComboBox(loadsComboBox); 130 } else if (typesComboBox.getSelectedItem() != null) { 131 String type = (String) typesComboBox.getSelectedItem(); 132 carLoads.updateComboBox(type, loadsComboBox); 133 } 134 } 135 136 private void updateLocations() { 137 String type = (String) typesComboBox.getSelectedItem(); 138 String load = (String) loadsComboBox.getSelectedItem(); 139 log.debug("Update locations for type ({}) load ({})", type, load); 140 locationsPanel.removeAll(); 141 int x = 0; 142 addItemLeft(locationsPanel, new JLabel(Bundle.getMessage("trackSchedule")), 1, x); 143 addItemLeft(locationsPanel, new JLabel(Bundle.getMessage("receiveTypeLoad")), 2, x); 144 addItemLeft(locationsPanel, new JLabel(Bundle.getMessage("shipLoad")), 3, x); 145 addItemLeft(locationsPanel, new JLabel(Bundle.getMessage("destinationTrack")), 4, x++); 146 147 // determine if load is default empty or load 148 boolean defaultLoad = carLoads.getDefaultLoadName().equals(load) || carLoads.getDefaultEmptyName().equals(load); 149 150 for (Location location : locationManager.getLocationsByNameList()) { 151 // only spurs have schedules 152 if (!location.hasSpurs()) 153 continue; 154 addItemLeft(locationsPanel, new JLabel(location.getName()), 0, x++); 155 // now look for a spur with a schedule 156 for (Track spur : location.getTracksByNameList(Track.SPUR)) { 157 Schedule sch = spur.getSchedule(); 158 if (sch == null) { 159 continue; 160 } 161 // listen for changes 162 spur.removePropertyChangeListener(this); 163 spur.addPropertyChangeListener(this); 164 sch.removePropertyChangeListener(this); 165 sch.addPropertyChangeListener(this); 166 167 // determine if schedule is requesting car type and load 168 for (ScheduleItem si : sch.getItemsBySequenceList()) { 169 // skip if car type doesn't carry load name 170 if (allTypesCheckBox.isSelected() && 171 !allLoadsCheckBox.isSelected() && 172 !carLoads.containsName(si.getTypeName(), load)) { 173 continue; 174 } 175 if ((allTypesCheckBox.isSelected() || si.getTypeName().equals(type)) && 176 (allLoadsCheckBox.isSelected() || 177 si.getReceiveLoadName().equals(load) || 178 si.getReceiveLoadName().equals(ScheduleItem.NONE) || 179 si.getShipLoadName().equals(load) || 180 (si.getShipLoadName().equals(ScheduleItem.NONE) && defaultLoad))) { 181 // is the schedule item valid? 182 String status = spur.checkScheduleValid(); 183 if (!status.equals(Schedule.SCHEDULE_OKAY)) { 184 addItemLeft(locationsPanel, new JLabel(" " + status), 0, x); 185 } 186 addItemLeft(locationsPanel, new JLabel(spur.getName() + " (" + spur.getScheduleName() + ")"), 1, 187 x); 188 // create string Receive(type, delivery, road, load) 189 String s = si.getTypeName() + 190 ", " + 191 si.getSetoutTrainScheduleName() + 192 ", " + 193 si.getRoadName() + 194 ", " + 195 si.getReceiveLoadName(); 196 addItemLeft(locationsPanel, new JLabel(Bundle.getMessage("Receive") + " (" + s + ")"), 2, x); 197 // create string Ship(load, pickup) 198 addItemLeft(locationsPanel, new JLabel(Bundle.getMessage( 199 "Ship") + " (" + si.getShipLoadName() + ", " + si.getPickupTrainScheduleName() + ")"), 200 3, x++); 201 // now the destination and track 202 if (si.getDestination() != null) { 203 addItemLeft(locationsPanel, 204 new JLabel(si.getDestinationName() + " (" + si.getDestinationTrackName() + ")"), 4, 205 x - 1); 206 } 207 // report if spur can't service the selected load 208 if (!allLoadsCheckBox.isSelected() && 209 si.getReceiveLoadName().equals(ScheduleItem.NONE) && 210 !spur.isLoadNameAndCarTypeAccepted(load, type)) { 211 addItemLeft(locationsPanel, 212 new JLabel (Bundle.getMessage("spurNotTypeLoad", 213 spur.getName(), type, load )), 214 2, x++); 215 } 216 } 217 } 218 } 219 } 220 locationsPanel.revalidate(); 221 revalidate(); 222 repaint(); 223 } 224 225 @Override 226 public void dispose() { 227 locationManager.removePropertyChangeListener(this); 228 carTypes.removePropertyChangeListener(this); 229 carLoads.removePropertyChangeListener(this); 230 for (Track spur : locationManager.getTracks(Track.SPUR)) { 231 Schedule sch = spur.getSchedule(); 232 if (sch == null) { 233 continue; 234 } 235 spur.removePropertyChangeListener(this); 236 sch.removePropertyChangeListener(this); 237 } 238 super.dispose(); 239 } 240 241 @Override 242 public void propertyChange(java.beans.PropertyChangeEvent e) { 243 log.debug("Property change ({}) old: ({}) new: ({})", e.getPropertyName(), e.getOldValue(), e.getNewValue()); // NOI18N 244 245 if (e.getPropertyName().equals(CarTypes.CARTYPES_CHANGED_PROPERTY)) { 246 carTypes.updateComboBox(typesComboBox); 247 } 248 if (e.getSource().getClass().equals(CarLoads.class)) { 249 carLoads.updateComboBox((String) typesComboBox.getSelectedItem(), loadsComboBox); 250 } 251 if (e.getSource().getClass().equals(Schedule.class) || 252 e.getSource().getClass().equals(LocationManager.class) || 253 e.getPropertyName().equals(Track.LOADS_CHANGED_PROPERTY) || 254 e.getPropertyName().equals(Track.TYPES_CHANGED_PROPERTY)) { 255 updateLocations(); 256 } 257 } 258 259 private final static Logger log = LoggerFactory.getLogger(SchedulesByLoadFrame.class); 260 261}