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}