001package jmri.jmrit.operations.locations.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 edu.umd.cs.findbugs.annotations.SuppressFBWarnings; 012import jmri.InstanceManager; 013import jmri.jmrit.operations.OperationsFrame; 014import jmri.jmrit.operations.locations.*; 015import jmri.jmrit.operations.rollingstock.cars.CarTypes; 016import jmri.jmrit.operations.routes.Route; 017import jmri.jmrit.operations.routes.RouteLocation; 018import jmri.jmrit.operations.setup.Control; 019import jmri.jmrit.operations.trains.Train; 020import jmri.jmrit.operations.trains.TrainManager; 021 022/** 023 * Frame to show which trains can service this location 024 * 025 * @author Dan Boudreau Copyright (C) 2014 026 */ 027public class ShowTrainsServingLocationFrame extends OperationsFrame implements java.beans.PropertyChangeListener { 028 029 Location _location = null; 030 Track _track = null; 031 032 // panels 033 JPanel pTrains = new JPanel(); 034 035 // combo boxes 036 JComboBox<Location> locationComboBox = new JComboBox<>(); 037 JComboBox<Track> trackComboBox = new JComboBox<>(); 038 JComboBox<String> typeComboBox = new JComboBox<>(); 039 040 // check boxes 041 JCheckBox showAllTrainsCheckBox = new JCheckBox(Bundle.getMessage("ShowAllTrains")); 042 043 // make show all trains consistent during a session 044 private static boolean isShowAllTrains = true; 045 046 public ShowTrainsServingLocationFrame() { 047 super(Bundle.getMessage("TitleShowTrains")); 048 } 049 050 public void initComponents(Location location, Track track) { 051 052 _location = location; 053 _track = track; 054 055 // general GUI config 056 getContentPane().setLayout(new BoxLayout(getContentPane(), BoxLayout.Y_AXIS)); 057 058 // Set up the panels 059 JPanel pLocations = new JPanel(); 060 pLocations.setLayout(new GridBagLayout()); 061 pLocations.setBorder(BorderFactory.createTitledBorder(Bundle.getMessage("Location"))); 062 pLocations.setMaximumSize(new Dimension(2000, 50)); 063 064 addItem(pLocations, locationComboBox, 0, 0); 065 066 JPanel pTracks = new JPanel(); 067 pTracks.setLayout(new GridBagLayout()); 068 pTracks.setBorder(BorderFactory.createTitledBorder(Bundle.getMessage("Track"))); 069 pTracks.setMaximumSize(new Dimension(2000, 50)); 070 071 addItem(pTracks, trackComboBox, 0, 0); 072 073 JPanel pCarType = new JPanel(); 074 pCarType.setLayout(new GridBagLayout()); 075 pCarType.setBorder(BorderFactory.createTitledBorder(Bundle.getMessage("Type"))); 076 pCarType.setMaximumSize(new Dimension(2000, 50)); 077 078 addItem(pCarType, typeComboBox, 0, 0); 079 080 JPanel pOptions = new JPanel(); 081 pOptions.setLayout(new GridBagLayout()); 082 pOptions.setBorder(BorderFactory.createTitledBorder(Bundle.getMessage("Options"))); 083 084 addItem(pOptions, showAllTrainsCheckBox, 0, 0); 085 086 pTrains.setLayout(new GridBagLayout()); 087 JScrollPane trainsPane = new JScrollPane(pTrains); 088 trainsPane.setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED); 089 trainsPane.setBorder(BorderFactory.createTitledBorder(Bundle.getMessage("Trains"))); 090 091 getContentPane().add(pLocations); 092 getContentPane().add(pTracks); 093 getContentPane().add(pCarType); 094 getContentPane().add(pOptions); 095 getContentPane().add(trainsPane); 096 097 // show all trains 098 showAllTrainsCheckBox.setToolTipText(Bundle.getMessage("TipDeselectedShowAllTrains")); 099 addCheckBoxAction(showAllTrainsCheckBox); 100 showAllTrainsCheckBox.setSelected(isShowAllTrains); 101 102 // setup combo box 103 updateLocationsComboBox(); 104 updateTracksComboBox(); 105 updateTypeComboBox(); 106 107 addComboBoxAction(locationComboBox); 108 addComboBoxAction(trackComboBox); 109 addComboBoxAction(typeComboBox); 110 111 // increase width of combobox so large text names display properly 112 Dimension boxsize = typeComboBox.getMinimumSize(); 113 if (boxsize != null) { 114 boxsize.setSize(boxsize.width + 10, boxsize.height); 115 typeComboBox.setMinimumSize(boxsize); 116 } 117 118 if (location != null) { 119 location.addPropertyChangeListener(this); 120 } 121 if (track != null) { 122 track.addPropertyChangeListener(this); 123 } 124 addPropertyChangeAllTrains(); 125 126 // add help menu to window 127 addHelpMenu("package.jmri.jmrit.operations.Operations_ShowTrainsServicingThisLocation", true); // NOI18N 128 129 setPreferredSize(null); 130 initMinimumSize(); 131 } 132 133 private void updateTrainPane() { 134 log.debug("Updating for location ({}), Track ({})", _location, _track); 135 pTrains.removeAll(); 136 int y = 0; 137 for (Train train : InstanceManager.getDefault(TrainManager.class).getTrainsByNameList()) { 138 Route route = train.getRoute(); 139 if (route == null) { 140 continue; 141 } 142 // determine if the car type is accepted by train 143 boolean typeAccepted = train.isTypeNameAccepted(_carType); 144 if (_carType.equals(NONE)) { 145 // determine if any available car type is accepted by train 146 for (int i = 0; i < typeComboBox.getItemCount(); i++) { 147 if (train.isTypeNameAccepted(typeComboBox.getItemAt(i))) { 148 typeAccepted = true; 149 break; 150 } 151 } 152 } 153 for (RouteLocation rl : route.getLocationsBySequenceList()) { 154 if (_location != null && rl.getName().equals(_location.getName())) { 155 boolean pickup = false; 156 boolean setout = false; 157 // monitor move count in the route for this location 158 train.getRoute().removePropertyChangeListener(this); 159 train.getRoute().addPropertyChangeListener(this); 160 if (rl.isPickUpAllowed() && 161 rl.getMaxCarMoves() > 0 && 162 !train.isLocationSkipped(rl.getId()) && 163 typeAccepted && 164 (train.isLocalSwitcher() || 165 (rl.getTrainDirection() & _location.getTrainDirections()) != 0) && 166 (train.isLocalSwitcher() || 167 _track == null || 168 ((rl.getTrainDirection() & _track.getTrainDirections()) != 0)) && 169 (_track == null || _track.isPickupTrainAccepted(train))) { 170 pickup = true; 171 } 172 if (rl.isDropAllowed() && 173 rl.getMaxCarMoves() > 0 && 174 !train.isLocationSkipped(rl.getId()) && 175 typeAccepted && 176 (train.isLocalSwitcher() || 177 (rl.getTrainDirection() & _location.getTrainDirections()) != 0) && 178 (train.isLocalSwitcher() || 179 _track == null || 180 ((rl.getTrainDirection() & _track.getTrainDirections()) != 0)) && 181 (_track == null || _track.isDropTrainAccepted(train)) && 182 (_track == null || 183 _carType.equals(NONE) || 184 _track.checkScheduleAttribute(Track.TYPE, _carType, null))) { 185 setout = true; 186 } 187 // now display results 188 if (showAllTrainsCheckBox.isSelected() || pickup || setout) { 189 addItemLeft(pTrains, new JLabel(train.getName()), 0, y); 190 // train direction when servicing this location 191 addItem(pTrains, new JLabel(rl.getTrainDirectionString()), 1, y); 192 if (pickup) { 193 addItem(pTrains, new JLabel(Bundle.getMessage("OkayPickUp")), 2, y); 194 } else { 195 addItem(pTrains, new JLabel(Bundle.getMessage("NoPickUp")), 2, y); 196 } 197 if (setout) { 198 addItem(pTrains, new JLabel(Bundle.getMessage("OkaySetOut")), 3, y); 199 } else { 200 addItem(pTrains, new JLabel(Bundle.getMessage("NoSetOut")), 3, y); 201 } 202 } 203 y++; 204 } 205 } 206 } 207 pTrains.repaint(); 208 pTrains.revalidate(); 209 pack(); 210 } 211 212 @Override 213 @SuppressFBWarnings(value = "ST_WRITE_TO_STATIC_FROM_INSTANCE_METHOD", justification = "GUI ease of use") 214 public void checkBoxActionPerformed(java.awt.event.ActionEvent ae) { 215 log.debug("check box action"); 216 isShowAllTrains = showAllTrainsCheckBox.isSelected(); 217 updateTrainPane(); 218 } 219 220 private String _carType = NONE; 221 222 @Override 223 public void comboBoxActionPerformed(java.awt.event.ActionEvent ae) { 224 if (ae.getSource().equals(locationComboBox)) { 225 _location = (Location) locationComboBox.getSelectedItem(); 226 updateTracksComboBox(); 227 updateTypeComboBox(); 228 updateTrainPane(); 229 } 230 if (ae.getSource().equals(trackComboBox)) { 231 if (_track != null) { 232 _track.removePropertyChangeListener(this); 233 } 234 _track = (Track) trackComboBox.getSelectedItem(); 235 if (_track != null) { 236 _track.addPropertyChangeListener(this); 237 } 238 updateTypeComboBox(); 239 updateTrainPane(); 240 } 241 if (typeComboBox.isEnabled() && ae.getSource().equals(typeComboBox)) { 242 if (typeComboBox.getSelectedItem() != null) { 243 _carType = (String) typeComboBox.getSelectedItem(); 244 } 245 updateTrainPane(); 246 } 247 } 248 249 private void updateLocationsComboBox() { 250 InstanceManager.getDefault(LocationManager.class).updateComboBox(locationComboBox); 251 locationComboBox.setSelectedItem(_location); 252 } 253 254 private void updateTracksComboBox() { 255 if (_location != null) { 256 _location.updateComboBox(trackComboBox); 257 } 258 trackComboBox.setSelectedItem(_track); 259 } 260 261 private void updateTypeComboBox() { 262 log.debug("update type combobox"); 263 typeComboBox.setEnabled(false); 264 InstanceManager.getDefault(CarTypes.class).updateComboBox(typeComboBox); 265 // remove car types not serviced by this location and track 266 for (int i = typeComboBox.getItemCount() - 1; i >= 0; i--) { 267 String type = typeComboBox.getItemAt(i); 268 if (_location != null && !_location.acceptsTypeName(type)) { 269 typeComboBox.removeItem(type); 270 } 271 if (_track != null && !_track.isTypeNameAccepted(type)) { 272 typeComboBox.removeItem(type); 273 } 274 } 275 typeComboBox.insertItemAt(NONE, 0); 276 typeComboBox.setSelectedItem(_carType); 277 278 updateTrainPane(); 279 typeComboBox.setEnabled(true); 280 } 281 282 @Override 283 public void dispose() { 284 if (_location != null) { 285 _location.removePropertyChangeListener(this); 286 } 287 if (_track != null) { 288 _track.removePropertyChangeListener(this); 289 } 290 removePropertyChangeAllTrains(); 291 super.dispose(); 292 } 293 294 public void addPropertyChangeAllTrains() { 295 InstanceManager.getDefault(TrainManager.class).addPropertyChangeListener(this); 296 for (Train train : InstanceManager.getDefault(TrainManager.class).getTrainsByNameList()) { 297 train.addPropertyChangeListener(this); 298 } 299 } 300 301 public void removePropertyChangeAllTrains() { 302 InstanceManager.getDefault(TrainManager.class).removePropertyChangeListener(this); 303 for (Train train : InstanceManager.getDefault(TrainManager.class).getTrainsByNameList()) { 304 train.removePropertyChangeListener(this); 305 if (train.getRoute() != null) { 306 train.getRoute().removePropertyChangeListener(this); 307 } 308 } 309 } 310 311 @Override 312 public void propertyChange(java.beans.PropertyChangeEvent e) { 313 if (Control.SHOW_PROPERTY) { 314 log.debug("Property change: ({}) old: ({}) new: ({})", e.getPropertyName(), e.getOldValue(), 315 e.getNewValue()); 316 } 317 if (e.getPropertyName().equals(Location.TYPES_CHANGED_PROPERTY) || 318 e.getPropertyName().equals(Track.TYPES_CHANGED_PROPERTY)) { 319 updateTypeComboBox(); 320 } 321 if (e.getPropertyName().equals(Location.TRAIN_DIRECTION_CHANGED_PROPERTY) || 322 e.getPropertyName().equals(Track.TRAIN_DIRECTION_CHANGED_PROPERTY) || 323 e.getPropertyName().equals(Track.DROP_CHANGED_PROPERTY) || 324 e.getPropertyName().equals(Track.PICKUP_CHANGED_PROPERTY) || 325 e.getPropertyName().equals(Train.TRAIN_ROUTE_CHANGED_PROPERTY) || 326 e.getPropertyName().equals(Train.TYPES_CHANGED_PROPERTY) || 327 e.getPropertyName().equals(Train.STOPS_CHANGED_PROPERTY) || 328 e.getPropertyName().equals(Route.LISTCHANGE_CHANGED_PROPERTY)) { 329 updateTrainPane(); 330 } 331 if (e.getPropertyName().equals(TrainManager.LISTLENGTH_CHANGED_PROPERTY)) { 332 removePropertyChangeAllTrains(); 333 addPropertyChangeAllTrains(); 334 } 335 } 336 337 private final static Logger log = LoggerFactory.getLogger(ShowTrainsServingLocationFrame.class); 338}