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