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