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

Last change on this file was 19050, checked in by taylor.smock, 14 months 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.