001package jmri.jmrit.operations.trains.gui;
002
003import java.awt.Dimension;
004import java.awt.GridBagLayout;
005
006import javax.swing.*;
007
008import org.slf4j.Logger;
009import org.slf4j.LoggerFactory;
010
011import jmri.jmrit.operations.CommonConductorYardmasterPanel;
012import jmri.jmrit.operations.rollingstock.RollingStock;
013import jmri.jmrit.operations.rollingstock.cars.Car;
014import jmri.jmrit.operations.routes.RouteLocation;
015import jmri.jmrit.operations.setup.Control;
016import jmri.jmrit.operations.trains.Train;
017import jmri.jmrit.operations.trains.TrainManager;
018import jmri.jmrit.operations.trains.trainbuilder.TrainCommon;
019
020/**
021 * Conductor Panel. Shows work for a train one location at a time.
022 *
023 * @author Dan Boudreau Copyright (C) 2011, 2013
024 * 
025 */
026public class TrainConductorPanel extends CommonConductorYardmasterPanel {
027
028    // labels
029    JLabel textTrainName = new JLabel();
030    JLabel textTrainDepartureTime = new JLabel();
031    JLabel textNextLocationName = new JLabel();
032
033    // panels
034    JPanel pTrainDepartureTime = new JPanel();
035
036    /**
037     * Default constructor required to use as JavaBean.
038     */
039    public TrainConductorPanel() {
040        this(null);
041    }
042
043    public TrainConductorPanel(Train train) {
044        super();
045
046        _train = train;
047
048        // row 2
049        JPanel pRow2 = new JPanel();
050        pRow2.setLayout(new BoxLayout(pRow2, BoxLayout.X_AXIS));
051
052        // row 2a (train name)
053        JPanel pTrainName = new JPanel();
054        pTrainName.setBorder(BorderFactory.createTitledBorder(Bundle.getMessage("Train")));
055        pTrainName.add(textTrainName);
056
057        pRow2.add(pTrainName);
058        pRow2.add(pTrainDescription);
059        pRow2.add(pRailRoadName);
060
061        JPanel pLocation = new JPanel();
062        pLocation.setLayout(new BoxLayout(pLocation, BoxLayout.X_AXIS));
063
064        // row 10b (train departure time)
065        pTrainDepartureTime.setBorder(BorderFactory.createTitledBorder(Bundle.getMessage("DepartTime")));
066        pTrainDepartureTime.add(textTrainDepartureTime);
067
068        // row 10c (next location name)
069        JPanel pNextLocationName = new JPanel();
070        pNextLocationName.setBorder(BorderFactory.createTitledBorder(Bundle.getMessage("NextLocation")));
071        pNextLocationName.add(textNextLocationName);
072
073        pLocation.add(pLocationName); // location name
074        pLocation.add(pTrainDepartureTime);
075        pLocation.add(pNextLocationName);
076
077        // row 14
078        JPanel pRow14 = new JPanel();
079        pRow14.setLayout(new BoxLayout(pRow14, BoxLayout.X_AXIS));
080        pRow14.setMaximumSize(new Dimension(2000, 200));
081
082        // row 14b
083        JPanel pMoveButton = new JPanel();
084        pMoveButton.setLayout(new GridBagLayout());
085        pMoveButton.setBorder(BorderFactory.createTitledBorder(Bundle.getMessage("Train")));
086        addItem(pMoveButton, moveButton, 1, 0);
087
088        pRow14.add(pButtons);
089        pRow14.add(pMoveButton);
090
091        add(pRow2);
092        add(pLocation);
093        add(textTrainCommentPane);
094        add(textTrainRouteCommentPane); // train route comment
095        add(textTrainRouteLocationCommentPane); // train route location comment
096        add(textLocationCommentPane);
097        add(pTrackComments);
098        add(textTrainStatusPane);
099        add(locoPane);
100        add(pWorkPanes);
101        add(movePane);
102        add(pStatus);
103        add(pRow14);
104
105        // setup buttons
106        addButtonAction(moveButton);
107
108        if (_train != null) {
109            loadTrainDescription();
110            loadTrainComment();
111            loadRouteComment();
112            loadRailroadName();
113            // listen for train changes
114            _train.addPropertyChangeListener(this);
115        }
116        trainManager.addPropertyChangeListener(this);
117        
118        update();
119    }
120
121    @Override
122    public void buttonActionPerformed(java.awt.event.ActionEvent ae) {
123        if (ae.getSource() == moveButton) {
124            _train.move();
125            return;
126        }
127        super.buttonActionPerformed(ae);
128    }
129
130    private boolean queued = false;
131
132    @Override
133    protected void update() {
134        log.debug("queue update");
135        if (queued) {
136            return;
137        }
138        queued = true;
139        // use invokeLater to prevent deadlock
140        SwingUtilities.invokeLater(() -> {
141            log.debug("run update, setMode: {}", isSetMode);
142            queued = false;
143            initialize();
144            if (_train != null && _train.getRoute() != null) {
145                textTrainName.setText(_train.getIconName());
146                RouteLocation rl = _train.getCurrentRouteLocation();
147                if (rl != null) {
148                    loadRouteLocationComment(rl);
149
150                    textLocationName.setText(trainManager.isShowLocationHyphenNameEnabled() ? rl.getLocation().getName()
151                            : rl.getLocation().getSplitName());
152                    pTrainDepartureTime.setVisible(_train.isShowArrivalAndDepartureTimesEnabled() &&
153                            !rl.getDepartureTimeHourMinutes().equals(RouteLocation.NONE));
154                    textTrainDepartureTime.setText(rl.getFormatedDepartureTime());
155
156                    loadLocationComment(rl.getLocation());
157
158                    textNextLocationName
159                            .setText(trainManager.isShowLocationHyphenNameEnabled() ? _train.getNextLocationName()
160                                    : TrainCommon.splitString(_train.getNextLocationName()));
161                    
162                    updateTrackComments(rl, IS_MANIFEST);
163                    
164                    textTrainStatusPane.setText(TrainCommon.getTrainMessage(_train, rl));
165                            
166                    // check for locos
167                    updateLocoPanes(rl);
168
169                    // now update the car pick ups and set outs
170                    blockCars(rl, IS_MANIFEST);
171                }
172
173                textStatus.setText(getStatus(rl, IS_MANIFEST));
174
175                // adjust move button text
176                if (rl == _train.getTrainTerminatesRouteLocation()) {
177                    moveButton.setText(Bundle.getMessage("Terminate"));
178                } else {
179                    moveButton.setText(Bundle.getMessage("Move"));
180                }
181            }
182            updateComplete();
183        });
184    }
185
186    @Override
187    public void dispose() {
188        trainManager.removePropertyChangeListener(this);
189        removePropertyChangeListerners();
190        if (_train != null) {
191            _train.removePropertyChangeListener(this);
192        }
193        super.dispose();
194    }
195
196    @Override
197    public void propertyChange(java.beans.PropertyChangeEvent e) {
198        if (Control.SHOW_PROPERTY) {
199            log.debug("Property change ({}) for: ({}) old: {}, new: {}", e.getPropertyName(), e.getSource().toString(),
200                    e.getOldValue(), e.getNewValue());
201        }
202        if (e.getPropertyName().equals(Train.TRAIN_MOVE_COMPLETE_CHANGED_PROPERTY) ||
203                e.getPropertyName().equals(Train.BUILT_CHANGED_PROPERTY)) {
204            clearAndUpdate();
205        }
206        if ((e.getPropertyName().equals(RollingStock.ROUTE_LOCATION_CHANGED_PROPERTY) && e.getNewValue() == null) ||
207                (e.getPropertyName().equals(RollingStock.ROUTE_DESTINATION_CHANGED_PROPERTY) &&
208                        e.getNewValue() == null) ||
209                e.getPropertyName().equals(RollingStock.TRAIN_CHANGED_PROPERTY) ||
210                e.getPropertyName().equals(Train.TRAIN_MODIFIED_CHANGED_PROPERTY) ||
211                e.getPropertyName().equals(TrainManager.TRAINS_SHOW_FULL_NAME_PROPERTY)) {
212            // remove car from list so the text get's updated
213            if (e.getSource().getClass().equals(Car.class)) {
214                Car car = (Car) e.getSource();
215                removeCarFromList(car);
216            }
217            update();
218        }
219    }
220
221    private final static Logger log = LoggerFactory.getLogger(TrainConductorPanel.class);
222}