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