source: josm/trunk/src/org/openstreetmap/josm/gui/MapMover.java@ 12658

Last change on this file since 12658 was 12639, checked in by Don-vip, 7 years ago

see #15182 - deprecate shortcut handling and mapframe listener methods in Main. Replacement: same methods in gui.MainApplication

  • Property svn:eol-style set to native
File size: 10.0 KB
RevLine 
[6380]1// License: GPL. For details, see LICENSE file.
[3]2package org.openstreetmap.josm.gui;
3
[1939]4import static org.openstreetmap.josm.tools.I18n.tr;
5
[3]6import java.awt.Cursor;
[102]7import java.awt.Point;
[101]8import java.awt.event.ActionEvent;
9import java.awt.event.KeyEvent;
[3]10import java.awt.event.MouseAdapter;
11import java.awt.event.MouseEvent;
12import java.awt.event.MouseWheelEvent;
[10432]13import java.util.ArrayList;
[11553]14import java.util.Optional;
[3]15
[101]16import javax.swing.AbstractAction;
17
[9824]18import org.openstreetmap.gui.jmapviewer.JMapViewer;
[1939]19import org.openstreetmap.josm.Main;
[7543]20import org.openstreetmap.josm.actions.mapmode.SelectAction;
[10000]21import org.openstreetmap.josm.data.Preferences.PreferenceChangeEvent;
22import org.openstreetmap.josm.data.Preferences.PreferenceChangedListener;
[71]23import org.openstreetmap.josm.data.coor.EastNorth;
[9824]24import org.openstreetmap.josm.data.preferences.BooleanProperty;
[12317]25import org.openstreetmap.josm.gui.MapViewState.MapViewPoint;
[5472]26import org.openstreetmap.josm.tools.Destroyable;
[10432]27import org.openstreetmap.josm.tools.Pair;
[1939]28import org.openstreetmap.josm.tools.Shortcut;
[3]29
30/**
31 * Enables moving of the map by holding down the right mouse button and drag
32 * the mouse. Also, enables zooming by the mouse wheel.
33 *
34 * @author imi
35 */
[10152]36public class MapMover extends MouseAdapter implements Destroyable {
[3]37
[12317]38 /**
39 * Zoom wheel is reversed.
40 */
[9824]41 public static final BooleanProperty PROP_ZOOM_REVERSE_WHEEL = new BooleanProperty("zoom.reverse-wheel", false);
42
[11713]43 static {
44 new JMapViewerUpdater();
45 }
[9824]46
47 private static class JMapViewerUpdater implements PreferenceChangedListener {
48
49 JMapViewerUpdater() {
50 Main.pref.addPreferenceChangeListener(this);
51 updateJMapViewer();
52 }
53
54 @Override
55 public void preferenceChanged(PreferenceChangeEvent e) {
56 if (MapMover.PROP_ZOOM_REVERSE_WHEEL.getKey().equals(e.getKey())) {
57 updateJMapViewer();
58 }
59 }
60
[10000]61 private static void updateJMapViewer() {
[9824]62 JMapViewer.zoomReverseWheel = MapMover.PROP_ZOOM_REVERSE_WHEEL.get();
63 }
64 }
65
[1169]66 private final class ZoomerAction extends AbstractAction {
67 private final String action;
[8510]68
[8836]69 ZoomerAction(String action) {
[10432]70 this(action, "MapMover.Zoomer." + action);
71 }
72
[10433]73 ZoomerAction(String action, String name) {
[1169]74 this.action = action;
[10432]75 putValue(NAME, name);
[101]76 }
[8510]77
[6084]78 @Override
[1169]79 public void actionPerformed(ActionEvent e) {
[6990]80 if (".".equals(action) || ",".equals(action)) {
[11553]81 Point mouse = Optional.ofNullable(nc.getMousePosition()).orElseGet(
82 () -> new Point((int) nc.getBounds().getCenterX(), (int) nc.getBounds().getCenterY()));
83 mouseWheelMoved(new MouseWheelEvent(nc, e.getID(), e.getWhen(), e.getModifiers(), mouse.x, mouse.y, 0, false,
84 MouseWheelEvent.WHEEL_UNIT_SCROLL, 1, ",".equals(action) ? -1 : 1));
[1169]85 } else {
86 EastNorth center = nc.getCenter();
87 EastNorth newcenter = nc.getEastNorth(nc.getWidth()/2+nc.getWidth()/5, nc.getHeight()/2+nc.getHeight()/5);
[7012]88 switch(action) {
89 case "left":
[1722]90 nc.zoomTo(new EastNorth(2*center.east()-newcenter.east(), center.north()));
[7012]91 break;
92 case "right":
[1722]93 nc.zoomTo(new EastNorth(newcenter.east(), center.north()));
[7012]94 break;
95 case "up":
[1722]96 nc.zoomTo(new EastNorth(center.east(), 2*center.north()-newcenter.north()));
[7012]97 break;
98 case "down":
[1722]99 nc.zoomTo(new EastNorth(center.east(), newcenter.north()));
[7012]100 break;
[10217]101 default: // Do nothing
[7012]102 }
[1169]103 }
104 }
[101]105 }
106
[1169]107 /**
108 * The point in the map that was the under the mouse point
109 * when moving around started.
[12317]110 *
111 * This is <code>null</code> if movement is not active
[1169]112 */
[12317]113 private MapViewPoint mousePosMoveStart;
114
[1169]115 /**
116 * The map to move around.
117 */
118 private final NavigatableComponent nc;
[3]119
[10432]120 private final ArrayList<Pair<ZoomerAction, Shortcut>> registeredShortcuts = new ArrayList<>();
121
[1169]122 /**
[7543]123 * Constructs a new {@code MapMover}.
124 * @param navComp the navigatable component
[11713]125 * @since 11713
[1169]126 */
[11713]127 public MapMover(NavigatableComponent navComp) {
[1169]128 this.nc = navComp;
129 nc.addMouseListener(this);
130 nc.addMouseMotionListener(this);
131 nc.addMouseWheelListener(this);
[101]132
[10432]133 registerActionShortcut(new ZoomerAction("right"),
134 Shortcut.registerShortcut("system:movefocusright", tr("Map: {0}", tr("Move right")), KeyEvent.VK_RIGHT, Shortcut.CTRL));
[1023]135
[10432]136 registerActionShortcut(new ZoomerAction("left"),
137 Shortcut.registerShortcut("system:movefocusleft", tr("Map: {0}", tr("Move left")), KeyEvent.VK_LEFT, Shortcut.CTRL));
[1023]138
[10432]139 registerActionShortcut(new ZoomerAction("up"),
140 Shortcut.registerShortcut("system:movefocusup", tr("Map: {0}", tr("Move up")), KeyEvent.VK_UP, Shortcut.CTRL));
141 registerActionShortcut(new ZoomerAction("down"),
142 Shortcut.registerShortcut("system:movefocusdown", tr("Map: {0}", tr("Move down")), KeyEvent.VK_DOWN, Shortcut.CTRL));
[1023]143
[10432]144 // see #10592 - Disable these alternate shortcuts on OS X because of conflict with system shortcut
145 if (!Main.isPlatformOsx()) {
146 registerActionShortcut(new ZoomerAction(",", "MapMover.Zoomer.in"),
147 Shortcut.registerShortcut("view:zoominalternate", tr("Map: {0}", tr("Zoom in")), KeyEvent.VK_COMMA, Shortcut.CTRL));
[1023]148
[10432]149 registerActionShortcut(new ZoomerAction(".", "MapMover.Zoomer.out"),
150 Shortcut.registerShortcut("view:zoomoutalternate", tr("Map: {0}", tr("Zoom out")), KeyEvent.VK_PERIOD, Shortcut.CTRL));
[1169]151 }
152 }
[101]153
[10432]154 private void registerActionShortcut(ZoomerAction action, Shortcut shortcut) {
[12639]155 MainApplication.registerActionShortcut(action, shortcut);
[10432]156 registeredShortcuts.add(new Pair<>(action, shortcut));
157 }
158
[12317]159 private boolean movementInProgress() {
160 return mousePosMoveStart != null;
161 }
162
[1169]163 /**
[7543]164 * If the right (and only the right) mouse button is pressed, move the map.
[1169]165 */
[6084]166 @Override
[1169]167 public void mouseDragged(MouseEvent e) {
168 int offMask = MouseEvent.BUTTON1_DOWN_MASK | MouseEvent.BUTTON2_DOWN_MASK;
[12317]169 boolean allowMovement = (e.getModifiersEx() & (MouseEvent.BUTTON3_DOWN_MASK | offMask)) == MouseEvent.BUTTON3_DOWN_MASK;
170 if (Main.isPlatformOsx()) {
[12630]171 MapFrame map = MainApplication.getMap();
[12317]172 int macMouseMask = MouseEvent.CTRL_DOWN_MASK | MouseEvent.BUTTON1_DOWN_MASK;
[12338]173 boolean macMovement = e.getModifiersEx() == macMouseMask;
[12630]174 boolean allowedMode = !map.mapModeSelect.equals(map.mapMode)
175 || SelectAction.Mode.SELECT.equals(map.mapModeSelect.getMode());
[12317]176 allowMovement |= macMovement && allowedMode;
177 }
178 if (allowMovement) {
179 doMoveForDrag(e);
[6957]180 } else {
[1169]181 endMovement();
[6957]182 }
[1169]183 }
[3]184
[12317]185 private void doMoveForDrag(MouseEvent e) {
186 if (!movementInProgress()) {
187 startMovement(e);
188 }
189 EastNorth center = nc.getCenter();
190 EastNorth mouseCenter = nc.getEastNorth(e.getX(), e.getY());
191 nc.zoomTo(mousePosMoveStart.getEastNorth().add(center).subtract(mouseCenter));
192 }
193
[1169]194 /**
195 * Start the movement, if it was the 3rd button (right button).
196 */
[6957]197 @Override
198 public void mousePressed(MouseEvent e) {
[1169]199 int offMask = MouseEvent.BUTTON1_DOWN_MASK | MouseEvent.BUTTON2_DOWN_MASK;
[1939]200 int macMouseMask = MouseEvent.CTRL_DOWN_MASK | MouseEvent.BUTTON1_DOWN_MASK;
[10670]201 if ((e.getButton() == MouseEvent.BUTTON3 && (e.getModifiersEx() & offMask) == 0) ||
202 (Main.isPlatformOsx() && e.getModifiersEx() == macMouseMask)) {
[1169]203 startMovement(e);
[1939]204 }
[1169]205 }
[3]206
[1169]207 /**
208 * Change the cursor back to it's pre-move cursor.
209 */
[6957]210 @Override
211 public void mouseReleased(MouseEvent e) {
[10659]212 if (e.getButton() == MouseEvent.BUTTON3 || (Main.isPlatformOsx() && e.getButton() == MouseEvent.BUTTON1)) {
[1169]213 endMovement();
[1939]214 }
[1169]215 }
[3]216
[1169]217 /**
218 * Start movement by setting a new cursor and remember the current mouse
219 * position.
220 * @param e The mouse event that leat to the movement from.
221 */
222 private void startMovement(MouseEvent e) {
[12317]223 if (movementInProgress()) {
[1169]224 return;
[12317]225 }
226 mousePosMoveStart = nc.getState().getForView(e.getX(), e.getY());
[3919]227 nc.setNewCursor(Cursor.MOVE_CURSOR, this);
[1169]228 }
[101]229
[1169]230 /**
231 * End the movement. Setting back the cursor and clear the movement variables
232 */
233 private void endMovement() {
[12317]234 if (!movementInProgress()) {
[1169]235 return;
[12317]236 }
[3919]237 nc.resetCursor(this);
[12317]238 mousePosMoveStart = null;
[1169]239 }
[3]240
[1169]241 /**
242 * Zoom the map by 1/5th of current zoom per wheel-delta.
243 * @param e The wheel event.
244 */
[6084]245 @Override
[1169]246 public void mouseWheelMoved(MouseWheelEvent e) {
[9824]247 int rotation = PROP_ZOOM_REVERSE_WHEEL.get() ? -e.getWheelRotation() : e.getWheelRotation();
248 nc.zoomManyTimes(e.getX(), e.getY(), rotation);
[1169]249 }
[3]250
[1169]251 /**
[6957]252 * Emulates dragging on Mac OSX.
[1169]253 */
[6084]254 @Override
[1939]255 public void mouseMoved(MouseEvent e) {
[12317]256 if (!movementInProgress()) {
[1939]257 return;
[12317]258 }
[1939]259 // Mac OSX simulates with ctrl + mouse 1 the second mouse button hence no dragging events get fired.
260 // Is only the selected mouse button pressed?
[6957]261 if (Main.isPlatformOsx()) {
[1939]262 if (e.getModifiersEx() == MouseEvent.CTRL_DOWN_MASK) {
[12317]263 doMoveForDrag(e);
[1939]264 } else {
265 endMovement();
266 }
267 }
268 }
269
[5472]270 @Override
271 public void destroy() {
[10432]272 for (Pair<ZoomerAction, Shortcut> shortcut : registeredShortcuts) {
[12639]273 MainApplication.unregisterActionShortcut(shortcut.a, shortcut.b);
[5472]274 }
275 }
[3]276}
Note: See TracBrowser for help on using the repository browser.