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

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

refactor handling of null values - use Java 8 Optional where possible

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