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}