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

Last change on this file since 19050 was 19050, checked in by taylor.smock, 6 weeks ago

Revert most var changes from r19048, fix most new compile warnings and checkstyle issues

Also, document why various ErrorProne checks were originally disabled and fix
generic SonarLint issues.

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