001// License: GPL. For details, see Readme.txt file. 002package org.openstreetmap.gui.jmapviewer; 003 004import java.awt.Point; 005import java.awt.event.MouseEvent; 006import java.awt.event.MouseListener; 007import java.awt.event.MouseMotionListener; 008import java.awt.event.MouseWheelEvent; 009import java.awt.event.MouseWheelListener; 010import java.util.Locale; 011 012/** 013 * Default map controller which implements map moving by pressing the right 014 * mouse button and zooming by double click or by mouse wheel. 015 * 016 * @author Jan Peter Stotz 017 * 018 */ 019public class DefaultMapController extends JMapController implements MouseListener, MouseMotionListener, 020MouseWheelListener { 021 022 private static final int MOUSE_BUTTONS_MASK = MouseEvent.BUTTON3_DOWN_MASK | MouseEvent.BUTTON1_DOWN_MASK 023 | MouseEvent.BUTTON2_DOWN_MASK; 024 025 private static final int MAC_MOUSE_BUTTON3_MASK = MouseEvent.CTRL_DOWN_MASK | MouseEvent.BUTTON1_DOWN_MASK; 026 027 private Point lastDragPoint; 028 029 private boolean isMoving; 030 031 private boolean movementEnabled = true; 032 033 private int movementMouseButton = MouseEvent.BUTTON3; 034 private int movementMouseButtonMask = MouseEvent.BUTTON3_DOWN_MASK; 035 036 private boolean wheelZoomEnabled = true; 037 private boolean doubleClickZoomEnabled = true; 038 039 /** 040 * Constructs a new {@code DefaultMapController}. 041 * @param map map panel 042 */ 043 public DefaultMapController(JMapViewer map) { 044 super(map); 045 } 046 047 @Override 048 public void mouseDragged(MouseEvent e) { 049 if (!movementEnabled || !isMoving) 050 return; 051 // Is only the selected mouse button pressed? 052 if ((e.getModifiersEx() & MOUSE_BUTTONS_MASK) == movementMouseButtonMask 053 || (isPlatformOsx() && e.getModifiersEx() == MAC_MOUSE_BUTTON3_MASK)) { 054 Point p = e.getPoint(); 055 if (lastDragPoint != null) { 056 int diffx = lastDragPoint.x - p.x; 057 int diffy = lastDragPoint.y - p.y; 058 map.moveMap(diffx, diffy); 059 } 060 lastDragPoint = p; 061 } 062 } 063 064 @Override 065 public void mouseClicked(MouseEvent e) { 066 if (doubleClickZoomEnabled && e.getClickCount() == 2 && e.getButton() == MouseEvent.BUTTON1) { 067 map.zoomIn(e.getPoint()); 068 } 069 } 070 071 @Override 072 public void mousePressed(MouseEvent e) { 073 if (e.getButton() == movementMouseButton || (isPlatformOsx() && e.getModifiersEx() == MAC_MOUSE_BUTTON3_MASK)) { 074 lastDragPoint = null; 075 isMoving = true; 076 } 077 } 078 079 @Override 080 public void mouseReleased(MouseEvent e) { 081 if (e.getButton() == movementMouseButton || (isPlatformOsx() && e.getButton() == MouseEvent.BUTTON1)) { 082 lastDragPoint = null; 083 isMoving = false; 084 } 085 } 086 087 @Override 088 public void mouseWheelMoved(MouseWheelEvent e) { 089 if (wheelZoomEnabled) { 090 int rotation = JMapViewer.zoomReverseWheel ? -e.getWheelRotation() : e.getWheelRotation(); 091 map.setZoom(map.getZoom() - rotation, e.getPoint()); 092 } 093 } 094 095 /** 096 * Determines if the map pane is allowed to be moved using the mouse 097 * @return {@code true} to allow the map pane to be moved using the mouse 098 */ 099 public boolean isMovementEnabled() { 100 return movementEnabled; 101 } 102 103 /** 104 * Enables or disables that the map pane can be moved using the mouse. 105 * 106 * @param movementEnabled {@code true} to allow the map pane to be moved using the mouse 107 */ 108 public void setMovementEnabled(boolean movementEnabled) { 109 this.movementEnabled = movementEnabled; 110 } 111 112 public int getMovementMouseButton() { 113 return movementMouseButton; 114 } 115 116 /** 117 * Sets the mouse button that is used for moving the map. Possible values are: 118 * <ul> 119 * <li>{@link MouseEvent#BUTTON1} (left mouse button)</li> 120 * <li>{@link MouseEvent#BUTTON2} (middle mouse button)</li> 121 * <li>{@link MouseEvent#BUTTON3} (right mouse button)</li> 122 * </ul> 123 * 124 * @param movementMouseButton the mouse button that is used for moving the map 125 */ 126 public void setMovementMouseButton(int movementMouseButton) { 127 this.movementMouseButton = movementMouseButton; 128 switch (movementMouseButton) { 129 case MouseEvent.BUTTON1: 130 movementMouseButtonMask = MouseEvent.BUTTON1_DOWN_MASK; 131 break; 132 case MouseEvent.BUTTON2: 133 movementMouseButtonMask = MouseEvent.BUTTON2_DOWN_MASK; 134 break; 135 case MouseEvent.BUTTON3: 136 movementMouseButtonMask = MouseEvent.BUTTON3_DOWN_MASK; 137 break; 138 default: 139 throw new RuntimeException("Unsupported button"); 140 } 141 } 142 143 public boolean isWheelZoomEnabled() { 144 return wheelZoomEnabled; 145 } 146 147 public void setWheelZoomEnabled(boolean wheelZoomEnabled) { 148 this.wheelZoomEnabled = wheelZoomEnabled; 149 } 150 151 public boolean isDoubleClickZoomEnabled() { 152 return doubleClickZoomEnabled; 153 } 154 155 public void setDoubleClickZoomEnabled(boolean doubleClickZoomEnabled) { 156 this.doubleClickZoomEnabled = doubleClickZoomEnabled; 157 } 158 159 @Override 160 public void mouseEntered(MouseEvent e) { 161 // do nothing 162 } 163 164 @Override 165 public void mouseExited(MouseEvent e) { 166 // do nothing 167 } 168 169 @Override 170 public void mouseMoved(MouseEvent e) { 171 // Mac OSX simulates with ctrl + mouse 1 the second mouse button hence no dragging events get fired. 172 // 173 if (isPlatformOsx()) { 174 if (!movementEnabled || !isMoving) 175 return; 176 // Is only the selected mouse button pressed? 177 if (e.getModifiersEx() == MouseEvent.CTRL_DOWN_MASK) { 178 Point p = e.getPoint(); 179 if (lastDragPoint != null) { 180 int diffx = lastDragPoint.x - p.x; 181 int diffy = lastDragPoint.y - p.y; 182 map.moveMap(diffx, diffy); 183 } 184 lastDragPoint = p; 185 } 186 } 187 } 188 189 /** 190 * Replies true if we are currently running on OSX 191 * 192 * @return true if we are currently running on OSX 193 */ 194 public static boolean isPlatformOsx() { 195 String os = System.getProperty("os.name"); 196 return os != null && os.toLowerCase(Locale.ENGLISH).startsWith("mac os x"); 197 } 198}