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