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}