001package jmri.jmrit.operations.trains.tools; 002 003import java.awt.Dimension; 004import java.awt.GridBagLayout; 005import java.text.MessageFormat; 006 007import javax.swing.*; 008 009import org.slf4j.Logger; 010import org.slf4j.LoggerFactory; 011 012import jmri.InstanceManager; 013import jmri.jmrit.operations.OperationsFrame; 014import jmri.jmrit.operations.rollingstock.cars.Car; 015import jmri.jmrit.operations.rollingstock.cars.CarManager; 016import jmri.jmrit.operations.routes.RouteLocation; 017import jmri.jmrit.operations.setup.Control; 018import jmri.jmrit.operations.setup.Setup; 019import jmri.jmrit.operations.trains.*; 020 021/** 022 * Show Cars In Train Frame. This frame lists all cars assigned to a train in 023 * the correct blocking order. Also show which cars are to be picked up and set 024 * out at each location in the train's route. 025 * 026 * @author Dan Boudreau Copyright (C) 2012 027 */ 028public class ShowCarsInTrainFrame extends OperationsFrame implements java.beans.PropertyChangeListener { 029 030 Train _train = null; 031 CarManager carManager = InstanceManager.getDefault(CarManager.class); 032 TrainManager trainManager = InstanceManager.getDefault(TrainManager.class); 033 034 // labels 035 JLabel textTrainName = new JLabel(); 036 JLabel textLocationName = new JLabel(); 037 JLabel textNextLocationName = new JLabel(); 038 JTextPane textStatus = new JTextPane(); 039 JLabel textPickUp = new JLabel(Bundle.getMessage("Pickup")); 040 JLabel textInTrain = new JLabel(Bundle.getMessage("InTrain")); 041 JLabel textSetOut = new JLabel(Bundle.getMessage("SetOut")); 042 043 // panels 044 JPanel pCars = new JPanel(); 045 046 public ShowCarsInTrainFrame() { 047 super(); 048 } 049 050 public void initComponents(Train train) { 051 _train = train; 052 053 getContentPane().setLayout(new BoxLayout(getContentPane(), BoxLayout.Y_AXIS)); 054 055 JScrollPane carPane = new JScrollPane(pCars); 056 carPane.setBorder(BorderFactory.createTitledBorder(Bundle.getMessage("Cars"))); 057 carPane.setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED); 058 // carPane.setPreferredSize(new Dimension(200, 300)); 059 060 // Set up the panels 061 // Layout the panel by rows 062 // row 2 063 JPanel pRow2 = new JPanel(); 064 pRow2.setLayout(new BoxLayout(pRow2, BoxLayout.X_AXIS)); 065 066 // row 2a (train name) 067 JPanel pTrainName = new JPanel(); 068 pTrainName.setBorder(BorderFactory.createTitledBorder(Bundle.getMessage("Train"))); 069 pTrainName.add(textTrainName); 070 071 pRow2.add(pTrainName); 072 073 // row 6 074 JPanel pRow6 = new JPanel(); 075 pRow6.setLayout(new BoxLayout(pRow6, BoxLayout.X_AXIS)); 076 077 // row 10 078 JPanel pRow10 = new JPanel(); 079 pRow10.setLayout(new BoxLayout(pRow10, BoxLayout.X_AXIS)); 080 081 // row 10a (location name) 082 JPanel pLocationName = new JPanel(); 083 pLocationName.setBorder(BorderFactory.createTitledBorder("Location")); 084 pLocationName.add(textLocationName); 085 086 // row 10c (next location name) 087 JPanel pNextLocationName = new JPanel(); 088 pNextLocationName.setBorder(BorderFactory.createTitledBorder(Bundle.getMessage("NextLocation"))); 089 pNextLocationName.add(textNextLocationName); 090 091 pRow10.add(pLocationName); 092 pRow10.add(pNextLocationName); 093 094 // row 12 095 JPanel pRow12 = new JPanel(); 096 pRow12.setLayout(new BoxLayout(pRow12, BoxLayout.X_AXIS)); 097 098 pCars.setLayout(new GridBagLayout()); 099 pRow12.add(carPane); 100 101 // row 13 102 // JPanel pStatus = new JPanel(); 103 // pStatus.setLayout(new GridBagLayout()); 104 textStatus.setBorder(BorderFactory.createTitledBorder("")); 105 // addItem(pStatus, textStatus, 0, 0); 106 textStatus.setBackground(null); 107 textStatus.setEditable(false); 108 109 getContentPane().add(pRow2); 110 getContentPane().add(pRow6); 111 getContentPane().add(pRow10); 112 getContentPane().add(pRow12); 113 getContentPane().add(textStatus); 114 115 if (_train != null) { 116 setTitle(Bundle.getMessage("TitleShowCarsInTrain", _train.getName())); 117 118 // listen for train changes 119 _train.addPropertyChangeListener(this); 120 } 121 122 // build menu 123 JMenuBar menuBar = new JMenuBar(); 124 if (train != null) { 125 JMenu toolMenu = new JMenu(Bundle.getMessage("MenuTools")); 126 toolMenu.add(new PrintShowCarsInTrainAction(false, train)); 127 toolMenu.add(new PrintShowCarsInTrainAction(true, train)); 128 menuBar.add(toolMenu); 129 } 130 setJMenuBar(menuBar); 131 addHelpMenu("package.jmri.jmrit.operations.Operations_ShowCarsInTrain", true); // NOI18N 132 133 initMinimumSize(new Dimension(Control.panelWidth300, Control.panelHeight500)); 134 update(); 135 } 136 137 private void update() { 138 log.debug("queue update"); 139 // use invokeLater to prevent deadlock 140 SwingUtilities.invokeLater(() -> { 141 log.debug("update"); 142 if (_train == null || _train.getRoute() == null) { 143 return; 144 } 145 textTrainName.setText(_train.getIconName()); 146 pCars.removeAll(); 147 RouteLocation rl = _train.getCurrentRouteLocation(); 148 if (rl != null) { 149 textLocationName.setText(trainManager.isShowLocationHyphenNameEnabled() 150 ? rl.getLocation().getName() : rl.getLocation().getSplitName()); 151 textNextLocationName.setText(trainManager.isShowLocationHyphenNameEnabled() 152 ? _train.getNextLocationName() : TrainCommon.splitString(_train.getNextLocationName())); 153 // add header 154 int i = 0; 155 addItemLeft(pCars, textPickUp, 0, 0); 156 addItemLeft(pCars, textInTrain, 1, 0); 157 addItemLeft(pCars, textSetOut, 2, i++); 158 // block cars by destination 159 // caboose or FRED is placed at end of the train 160 // passenger cars are already blocked in the car list 161 // passenger cars with negative block numbers are placed at 162 // the front of the train, positive numbers at the end of 163 // the train. 164 for (RouteLocation rld : _train.getRoute().getLocationsBySequenceList()) { 165 for (Car car : carManager.getByTrainDestinationList(_train)) { 166 if (TrainCommon.isNextCar(car, rl, rld, true)) { 167 log.debug("car ({}) routelocation ({}) track ({}) route destination ({})", 168 car.toString(), car 169 .getRouteLocation().getName(), 170 car.getTrackName(), car.getRouteDestination().getName()); 171 JCheckBox checkBox = new JCheckBox(car.getRoadName().split(TrainCommon.HYPHEN)[0] + 172 " " + 173 TrainCommon.splitString(car.getNumber())); 174 if (car.getRouteDestination() == rl) { 175 addItemLeft(pCars, checkBox, 2, i++); // set out 176 } else if (car.getRouteLocation() == rl && car.getTrack() != null) { 177 addItemLeft(pCars, checkBox, 0, i++); // pick up 178 } else { 179 addItemLeft(pCars, checkBox, 1, i++); // in 180 // train 181 } 182 } 183 } 184 } 185 186 if (rl != _train.getTrainTerminatesRouteLocation()) { 187 textStatus.setText(getStatus(rl)); 188 } else { 189 textStatus.setText(MessageFormat.format(TrainManifestText.getStringTrainTerminates(), 190 new Object[]{_train.getTrainTerminatesName()})); 191 } 192 } 193 pCars.repaint(); 194 }); 195 } 196 197 private String getStatus(RouteLocation rl) { 198 if (Setup.isPrintLoadsAndEmptiesEnabled()) { 199 int emptyCars = _train.getNumberEmptyCarsInTrain(rl); 200 return MessageFormat.format(TrainManifestText.getStringTrainDepartsLoads(), new Object[]{ 201 rl.getSplitName(), rl.getTrainDirectionString(), 202 _train.getNumberCarsInTrain(rl) - emptyCars, emptyCars, _train.getTrainLength(rl), 203 Setup.getLengthUnit().toLowerCase(), _train.getTrainWeight(rl)}); 204 } else { 205 return MessageFormat.format(TrainManifestText.getStringTrainDepartsCars(), 206 new Object[]{rl.getSplitName(), rl.getTrainDirectionString(), _train.getNumberCarsInTrain(), 207 _train.getTrainLength(rl), Setup.getLengthUnit().toLowerCase(), 208 _train.getTrainWeight(rl)}); 209 } 210 } 211 212 @Override 213 public void dispose() { 214 if (_train != null) { 215 _train.removePropertyChangeListener(this); 216 } 217 super.dispose(); 218 } 219 220 @Override 221 public void propertyChange(java.beans.PropertyChangeEvent e) { 222 // if (Control.showProperty) 223 log.debug("Property change {} from: {} old: {} new: {}", e.getPropertyName(), e.getSource().toString(), 224 e.getOldValue(), e.getNewValue()); // NOI18N 225 if (e.getPropertyName().equals(Train.BUILT_CHANGED_PROPERTY) || 226 e.getPropertyName().equals(Train.TRAIN_MOVE_COMPLETE_CHANGED_PROPERTY)) { 227 update(); 228 } 229 } 230 231 private final static Logger log = LoggerFactory.getLogger(ShowCarsInTrainFrame.class); 232}