001package jmri.jmrit.operations.trains;
002
003import java.awt.Point;
004import java.awt.event.ActionEvent;
005import java.util.List;
006
007import javax.swing.*;
008
009import jmri.InstanceManager;
010import jmri.jmrit.display.Editor;
011import jmri.jmrit.display.LocoIcon;
012import jmri.jmrit.operations.rollingstock.cars.Car;
013import jmri.jmrit.operations.rollingstock.cars.CarManager;
014import jmri.jmrit.operations.routes.Route;
015import jmri.jmrit.operations.routes.RouteLocation;
016import jmri.jmrit.operations.trains.tools.ShowCarsInTrainAction;
017import jmri.jmrit.throttle.ThrottleFrameManager;
018import jmri.util.swing.JmriJOptionPane;
019import jmri.util.swing.JmriMouseEvent;
020
021/**
022 * An icon that displays the position of a train icon on a panel.
023 * <p>
024 * The icon can always be repositioned and its popup menu is always active.
025 *
026 * @author Bob Jacobsen Copyright (c) 2002
027 * @author Daniel Boudreau Copyright (C) 2008
028 */
029public class TrainIcon extends LocoIcon {
030
031    public TrainIcon(Editor editor) {
032        // super ctor call to make sure this is an icon label
033        super(editor);
034    }
035
036    // train icon tool tips are always enabled
037    @Override
038    public void setShowToolTip(boolean set) {
039        _showTooltip = true;
040    }
041
042    /**
043     * Pop-up only if right click and not dragged return true if a popup item is
044     * set
045     */
046    @Override
047    public boolean showPopUp(JPopupMenu popup) {
048        if (_train != null) {
049            // first action is either "Move" or "Terminate" train
050            String actionText = (_train.getCurrentRouteLocation() == _train.getTrainTerminatesRouteLocation())
051                    ? Bundle.getMessage("Terminate") : Bundle.getMessage("Move");
052            popup.add(new AbstractAction(actionText) {
053                @Override
054                public void actionPerformed(ActionEvent e) {
055                    _train.move();
056                }
057            });
058            popup.add(makeTrainRouteMenu());
059            popup.add(new TrainConductorAction(_train));
060            popup.add(new ShowCarsInTrainAction(_train));
061            if (!isEditable()) {
062                popup.add(new AbstractAction(Bundle.getMessage("SetX&Y")) {
063                    @Override
064                    public void actionPerformed(ActionEvent e) {
065                        if (!_train.setTrainIconCoordinates()) {
066                            JmriJOptionPane.showMessageDialog(null, Bundle.getMessage("SeeOperationsSettings"), Bundle
067                                    .getMessage("SetX&YisDisabled"), JmriJOptionPane.ERROR_MESSAGE);
068                        }
069                    }
070                });
071            }
072        }
073        popup.add(new ThrottleAction(Bundle.getMessage("Throttle")));
074        popup.add(makeLocoIconMenu());
075        if (!isEditable()) {
076            getEditor().setRemoveMenu(this, popup);
077        }
078        return true;
079    }
080
081    Train _train = null;
082
083    public void setTrain(Train train) {
084        _train = train;
085    }
086
087    public Train getTrain() {
088        return _train;
089    }
090
091    int _consistNumber = 0;
092
093    public void setConsistNumber(int cN) {
094        this._consistNumber = cN;
095    }
096
097    private int getConsistNumber() {
098        return _consistNumber;
099    }
100
101    jmri.jmrit.throttle.ThrottleFrame _tf = null;
102
103    private void createThrottle() {
104        _tf = InstanceManager.getDefault(ThrottleFrameManager.class).createThrottleFrame();
105        if (getConsistNumber() > 0) {
106            _tf.getAddressPanel().setAddress(getConsistNumber(), false); // use consist address
107            if (JmriJOptionPane.showConfirmDialog(null, Bundle.getMessage("SendFunctionCommands"), Bundle
108                    .getMessage("ConsistThrottle"), JmriJOptionPane.YES_NO_OPTION) == JmriJOptionPane.YES_OPTION) {
109                _tf.getAddressPanel().setRosterEntry(_entry); // use lead loco address
110            }
111        } else {
112            _tf.getAddressPanel().setRosterEntry(_entry);
113        }
114        _tf.toFront();
115    }
116
117    private JMenu makeTrainRouteMenu() {
118        JMenu routeMenu = new JMenu(Bundle.getMessage("Route"));
119        Route route = _train.getRoute();
120        if (route == null) {
121            return routeMenu;
122        }
123        List<Car> carList = InstanceManager.getDefault(CarManager.class).getByTrainList(_train);
124        for (RouteLocation rl : route.getLocationsBySequenceList()) {
125            int pickupCars = 0;
126            int dropCars = 0;
127            String current = "     ";
128            if (_train.getCurrentRouteLocation() == rl) {
129                current = "-> "; // NOI18N
130            }
131            for (Car car : carList) {
132                if (car.getRouteLocation() == rl && !car.getTrackName().equals(Car.NONE)) {
133                    pickupCars++;
134                }
135                if (car.getRouteDestination() == rl) {
136                    dropCars++;
137                }
138            }
139            String rText = "";
140            String pickups = "";
141            String drops = "";
142            if (pickupCars > 0) {
143                pickups = " " + Bundle.getMessage("Pickup") + " " + pickupCars;
144                if (dropCars > 0) {
145                    drops = ", " + Bundle.getMessage("SetOut") + " " + dropCars;
146                }
147            } else if (dropCars > 0) {
148                drops = " " + Bundle.getMessage("SetOut") + " " + dropCars;
149            }
150            if (pickupCars > 0 || dropCars > 0) {
151                rText = current + rl.getName() + "  (" + pickups + drops + " )";
152            } else {
153                rText = current + rl.getName();
154            }
155            routeMenu.add(new RouteAction(rText, rl));
156        }
157        return routeMenu;
158    }
159
160    public class ThrottleAction extends AbstractAction {
161        public ThrottleAction(String actionName) {
162            super(actionName);
163            if (_entry == null) {
164                setEnabled(false);
165            }
166        }
167
168        @Override
169        public void actionPerformed(ActionEvent e) {
170            createThrottle();
171        }
172    }
173
174    /**
175     * Moves train from current location to the one selected by user.
176     *
177     */
178    public class RouteAction extends AbstractAction {
179        RouteLocation _rl;
180
181        public RouteAction(String actionName, RouteLocation rl) {
182            super(actionName);
183            _rl = rl;
184        }
185
186        @Override
187        public void actionPerformed(ActionEvent e) {
188            log.debug("Route location selected {}", _rl.getName());
189            Route route = _train.getRoute();
190            List<RouteLocation> routeList = route.getLocationsBySequenceList();
191            // determine where the train is in the route
192            for (int r = 0; r < routeList.size(); r++) {
193                RouteLocation rl = routeList.get(r);
194                if (_train.getCurrentRouteLocation() == rl) {
195                    log.debug("Train is at location {}", rl.getName());
196                    // Is train at this route location?
197                    if (rl == _rl) {
198                        break;
199                    }
200                    for (int i = r + 1; i < routeList.size(); i++) {
201                        RouteLocation nextRl = routeList.get(i);
202                        // did user select the next location in the route?
203                        if (nextRl == _rl && i == r + 1) {
204                            _train.move();
205                        } else if (nextRl == _rl) {
206                            if (JmriJOptionPane.showConfirmDialog(null, Bundle
207                                    .getMessage("MoveTrainTo", _rl.getName()), 
208                                    Bundle.getMessage("MoveTrain", _train.getIconName()),
209                                    JmriJOptionPane.YES_NO_OPTION) == JmriJOptionPane.YES_OPTION) {
210                                while (_train.getCurrentRouteLocation() != _rl) {
211                                    _train.move();
212                                }
213                            }
214                        }
215                    }
216                }
217            }
218        }
219    }
220
221
222    // route
223
224    /**
225     * Determine if user moved the train icon to next location in a train's
226     * route.
227     */
228    @Override
229    public void doMouseDragged(JmriMouseEvent event) {
230        log.debug("Mouse dragged, X={} Y={}", getX(), getY());
231        if (_train != null) {
232            RouteLocation next = _train.getNextRouteLocation(_train.getCurrentRouteLocation());
233            if (next != null) {
234                Point nextPoint = next.getTrainIconCoordinates();
235                log.debug("Next location ({}), X={} Y={}", next.getName(), nextPoint.x, nextPoint.y);
236                if (Math.abs(getX() - nextPoint.x) < next.getTrainIconRangeX() && Math.abs(getY() - nextPoint.y) < next.getTrainIconRangeY()) {
237                    log.debug("Train icon ({}) within range of ({})", _train.getName(), next.getName());
238                    if (JmriJOptionPane.showConfirmDialog(null, Bundle.getMessage("MoveTrainTo",
239                            next.getName()), Bundle.getMessage("MoveTrain",
240                            _train.getIconName()), JmriJOptionPane.YES_NO_OPTION) == JmriJOptionPane.YES_OPTION) {
241                        _train.move();
242                    }
243                }
244            }
245        }
246    }
247
248    private static final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(TrainIcon.class);
249}