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