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}