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 = false; 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 // build menu 127 JMenuBar menuBar = new JMenuBar(); 128 JMenu toolMenu = new JMenu(Bundle.getMessage("MenuTools")); 129 toolMenu.add(new PrintTrainsServingLocationAction(this, false)); 130 toolMenu.add(new PrintTrainsServingLocationAction(this, true)); 131 menuBar.add(toolMenu); 132 setJMenuBar(menuBar); 133 // add help menu to window 134 addHelpMenu("package.jmri.jmrit.operations.Operations_ShowTrainsServicingThisLocation", true); // NOI18N 135 136 setPreferredSize(null); 137 initMinimumSize(); 138 } 139 140 private void updateTrainPane() { 141 log.debug("Updating for location ({}), Track ({})", _location, _track); 142 pTrains.removeAll(); 143 int y = 0; 144 for (Train train : InstanceManager.getDefault(TrainManager.class).getTrainsByNameList()) { 145 Route route = train.getRoute(); 146 if (route == null) { 147 continue; 148 } 149 // determine if the car type is accepted by train 150 boolean typeAccepted = train.isTypeNameAccepted(_carType); 151 if (_carType.equals(NONE)) { 152 // determine if any available car type is accepted by train 153 for (int i = 0; i < typeComboBox.getItemCount(); i++) { 154 if (train.isTypeNameAccepted(typeComboBox.getItemAt(i))) { 155 typeAccepted = true; 156 break; 157 } 158 } 159 } 160 for (RouteLocation rl : route.getLocationsBySequenceList()) { 161 if (_location != null && rl.getName().equals(_location.getName())) { 162 boolean pickup = false; 163 boolean setout = false; 164 // monitor move count in the route for this location 165 train.getRoute().removePropertyChangeListener(this); 166 train.getRoute().addPropertyChangeListener(this); 167 if (rl.isPickUpAllowed() && 168 rl.getMaxCarMoves() > 0 && 169 !train.isLocationSkipped(rl.getId()) && 170 typeAccepted && 171 (train.isLocalSwitcher() || 172 (rl.getTrainDirection() & _location.getTrainDirections()) != 0) && 173 (train.isLocalSwitcher() || 174 _track == null || 175 ((rl.getTrainDirection() & _track.getTrainDirections()) != 0)) && 176 (_track == null || _track.isPickupTrainAccepted(train))) { 177 pickup = true; 178 } 179 if (rl.isDropAllowed() && 180 rl.getMaxCarMoves() > 0 && 181 !train.isLocationSkipped(rl.getId()) && 182 typeAccepted && 183 (train.isLocalSwitcher() || 184 (rl.getTrainDirection() & _location.getTrainDirections()) != 0) && 185 (train.isLocalSwitcher() || 186 _track == null || 187 ((rl.getTrainDirection() & _track.getTrainDirections()) != 0)) && 188 (_track == null || _track.isDropTrainAccepted(train)) && 189 (_track == null || 190 _carType.equals(NONE) || 191 _track.checkScheduleAttribute(Track.TYPE, _carType, null))) { 192 setout = true; 193 } 194 // now display results 195 if (showAllTrainsCheckBox.isSelected() || pickup || setout) { 196 addItemLeft(pTrains, new JLabel(train.getName()), 0, y); 197 // train direction when servicing this location 198 addItem(pTrains, new JLabel(rl.getTrainDirectionString()), 1, y); 199 if (pickup) { 200 addItem(pTrains, new JLabel(Bundle.getMessage("OkayPickUp")), 2, y); 201 } else { 202 addItem(pTrains, new JLabel(Bundle.getMessage("NoPickUp")), 2, y); 203 } 204 if (setout) { 205 addItem(pTrains, new JLabel(Bundle.getMessage("OkaySetOut")), 3, y); 206 } else { 207 addItem(pTrains, new JLabel(Bundle.getMessage("NoSetOut")), 3, y); 208 } 209 } 210 y++; 211 } 212 } 213 } 214 pTrains.repaint(); 215 pTrains.revalidate(); 216 pack(); 217 } 218 219 @Override 220 @SuppressFBWarnings(value = "ST_WRITE_TO_STATIC_FROM_INSTANCE_METHOD", justification = "GUI ease of use") 221 public void checkBoxActionPerformed(java.awt.event.ActionEvent ae) { 222 log.debug("check box action"); 223 isShowAllTrains = showAllTrainsCheckBox.isSelected(); 224 updateTrainPane(); 225 } 226 227 String _carType = NONE; 228 229 @Override 230 public void comboBoxActionPerformed(java.awt.event.ActionEvent ae) { 231 if (ae.getSource().equals(locationComboBox)) { 232 _location = (Location) locationComboBox.getSelectedItem(); 233 updateTracksComboBox(); 234 updateTypeComboBox(); 235 updateTrainPane(); 236 } 237 if (ae.getSource().equals(trackComboBox)) { 238 if (_track != null) { 239 _track.removePropertyChangeListener(this); 240 } 241 _track = (Track) trackComboBox.getSelectedItem(); 242 if (_track != null) { 243 _track.addPropertyChangeListener(this); 244 } 245 updateTypeComboBox(); 246 updateTrainPane(); 247 } 248 if (typeComboBox.isEnabled() && ae.getSource().equals(typeComboBox)) { 249 if (typeComboBox.getSelectedItem() != null) { 250 _carType = (String) typeComboBox.getSelectedItem(); 251 } 252 updateTrainPane(); 253 } 254 } 255 256 private void updateLocationsComboBox() { 257 InstanceManager.getDefault(LocationManager.class).updateComboBox(locationComboBox); 258 locationComboBox.setSelectedItem(_location); 259 } 260 261 private void updateTracksComboBox() { 262 if (_location != null) { 263 _location.updateComboBox(trackComboBox); 264 } 265 trackComboBox.setSelectedItem(_track); 266 } 267 268 private void updateTypeComboBox() { 269 log.debug("update type combobox"); 270 typeComboBox.setEnabled(false); 271 InstanceManager.getDefault(CarTypes.class).updateComboBox(typeComboBox); 272 // remove car types not serviced by this location and track 273 for (int i = typeComboBox.getItemCount() - 1; i >= 0; i--) { 274 String type = typeComboBox.getItemAt(i); 275 if (_location != null && !_location.acceptsTypeName(type)) { 276 typeComboBox.removeItem(type); 277 } 278 if (_track != null && !_track.isTypeNameAccepted(type)) { 279 typeComboBox.removeItem(type); 280 } 281 } 282 typeComboBox.insertItemAt(NONE, 0); 283 typeComboBox.setSelectedItem(_carType); 284 285 updateTrainPane(); 286 typeComboBox.setEnabled(true); 287 } 288 289 @Override 290 public void dispose() { 291 if (_location != null) { 292 _location.removePropertyChangeListener(this); 293 } 294 if (_track != null) { 295 _track.removePropertyChangeListener(this); 296 } 297 removePropertyChangeAllTrains(); 298 super.dispose(); 299 } 300 301 public void addPropertyChangeAllTrains() { 302 InstanceManager.getDefault(TrainManager.class).addPropertyChangeListener(this); 303 for (Train train : InstanceManager.getDefault(TrainManager.class).getTrainsByNameList()) { 304 train.addPropertyChangeListener(this); 305 } 306 } 307 308 public void removePropertyChangeAllTrains() { 309 InstanceManager.getDefault(TrainManager.class).removePropertyChangeListener(this); 310 for (Train train : InstanceManager.getDefault(TrainManager.class).getTrainsByNameList()) { 311 train.removePropertyChangeListener(this); 312 if (train.getRoute() != null) { 313 train.getRoute().removePropertyChangeListener(this); 314 } 315 } 316 } 317 318 @Override 319 public void propertyChange(java.beans.PropertyChangeEvent e) { 320 if (Control.SHOW_PROPERTY) { 321 log.debug("Property change: ({}) old: ({}) new: ({})", e.getPropertyName(), e.getOldValue(), 322 e.getNewValue()); 323 } 324 if (e.getPropertyName().equals(Location.TYPES_CHANGED_PROPERTY) || 325 e.getPropertyName().equals(Track.TYPES_CHANGED_PROPERTY)) { 326 updateTypeComboBox(); 327 } 328 if (e.getPropertyName().equals(Location.TRAIN_DIRECTION_CHANGED_PROPERTY) || 329 e.getPropertyName().equals(Track.TRAIN_DIRECTION_CHANGED_PROPERTY) || 330 e.getPropertyName().equals(Track.DROP_CHANGED_PROPERTY) || 331 e.getPropertyName().equals(Track.PICKUP_CHANGED_PROPERTY) || 332 e.getPropertyName().equals(Train.TRAIN_ROUTE_CHANGED_PROPERTY) || 333 e.getPropertyName().equals(Train.TYPES_CHANGED_PROPERTY) || 334 e.getPropertyName().equals(Train.STOPS_CHANGED_PROPERTY) || 335 e.getPropertyName().equals(Route.LISTCHANGE_CHANGED_PROPERTY)) { 336 updateTrainPane(); 337 } 338 if (e.getPropertyName().equals(TrainManager.LISTLENGTH_CHANGED_PROPERTY)) { 339 removePropertyChangeAllTrains(); 340 addPropertyChangeAllTrains(); 341 } 342 } 343 344 private final static Logger log = LoggerFactory.getLogger(ShowTrainsServingLocationFrame.class); 345}