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 public DefaultMapController(JMapViewer map) { 040 super(map); 041 } 042 043 @Override 044 public void mouseDragged(MouseEvent e) { 045 if (!movementEnabled || !isMoving) 046 return; 047 // Is only the selected mouse button pressed? 048 if ((e.getModifiersEx() & MOUSE_BUTTONS_MASK) == movementMouseButtonMask 049 || isPlatformOsx() && e.getModifiersEx() == MAC_MOUSE_BUTTON3_MASK) { 050 Point p = e.getPoint(); 051 if (lastDragPoint != null) { 052 int diffx = lastDragPoint.x - p.x; 053 int diffy = lastDragPoint.y - p.y; 054 map.moveMap(diffx, diffy); 055 } 056 lastDragPoint = p; 057 } 058 } 059 060 @Override 061 public void mouseClicked(MouseEvent e) { 062 if (doubleClickZoomEnabled && e.getClickCount() == 2 && e.getButton() == MouseEvent.BUTTON1) { 063 map.zoomIn(e.getPoint()); 064 } 065 } 066 067 @Override 068 public void mousePressed(MouseEvent e) { 069 if (e.getButton() == movementMouseButton || isPlatformOsx() && e.getModifiersEx() == MAC_MOUSE_BUTTON3_MASK) { 070 lastDragPoint = null; 071 isMoving = true; 072 } 073 } 074 075 @Override 076 public void mouseReleased(MouseEvent e) { 077 if (e.getButton() == movementMouseButton || isPlatformOsx() && e.getButton() == MouseEvent.BUTTON1) { 078 lastDragPoint = null; 079 isMoving = false; 080 } 081 } 082 083 @Override 084 public void mouseWheelMoved(MouseWheelEvent e) { 085 if (wheelZoomEnabled) { 086 int rotation = JMapViewer.zoomReverseWheel ? -e.getWheelRotation() : e.getWheelRotation(); 087 map.setZoom(map.getZoom() - rotation, e.getPoint()); 088 } 089 } 090 091 public boolean isMovementEnabled() { 092 return movementEnabled; 093 } 094 095 /** 096 * Enables or disables that the map pane can be moved using the mouse. 097 * 098 * @param movementEnabled {@code true} to allow the map pane to be moved using the mouse 099 */ 100 public void setMovementEnabled(boolean movementEnabled) { 101 this.movementEnabled = movementEnabled; 102 } 103 104 public int getMovementMouseButton() { 105 return movementMouseButton; 106 } 107 108 /** 109 * Sets the mouse button that is used for moving the map. Possible values are: 110 * <ul> 111 * <li>{@link MouseEvent#BUTTON1} (left mouse button)</li> 112 * <li>{@link MouseEvent#BUTTON2} (middle mouse button)</li> 113 * <li>{@link MouseEvent#BUTTON3} (right mouse button)</li> 114 * </ul> 115 * 116 * @param movementMouseButton the mouse button that is used for moving the map 117 */ 118 public void setMovementMouseButton(int movementMouseButton) { 119 this.movementMouseButton = movementMouseButton; 120 switch (movementMouseButton) { 121 case MouseEvent.BUTTON1: 122 movementMouseButtonMask = MouseEvent.BUTTON1_DOWN_MASK; 123 break; 124 case MouseEvent.BUTTON2: 125 movementMouseButtonMask = MouseEvent.BUTTON2_DOWN_MASK; 126 break; 127 case MouseEvent.BUTTON3: 128 movementMouseButtonMask = MouseEvent.BUTTON3_DOWN_MASK; 129 break; 130 default: 131 throw new RuntimeException("Unsupported button"); 132 } 133 } 134 135 public boolean isWheelZoomEnabled() { 136 return wheelZoomEnabled; 137 } 138 139 public void setWheelZoomEnabled(boolean wheelZoomEnabled) { 140 this.wheelZoomEnabled = wheelZoomEnabled; 141 } 142 143 public boolean isDoubleClickZoomEnabled() { 144 return doubleClickZoomEnabled; 145 } 146 147 public void setDoubleClickZoomEnabled(boolean doubleClickZoomEnabled) { 148 this.doubleClickZoomEnabled = doubleClickZoomEnabled; 149 } 150 151 @Override 152 public void mouseEntered(MouseEvent e) { 153 } 154 155 @Override 156 public void mouseExited(MouseEvent e) { 157 } 158 159 @Override 160 public void mouseMoved(MouseEvent e) { 161 // Mac OSX simulates with ctrl + mouse 1 the second mouse button hence no dragging events get fired. 162 // 163 if (isPlatformOsx()) { 164 if (!movementEnabled || !isMoving) 165 return; 166 // Is only the selected mouse button pressed? 167 if (e.getModifiersEx() == MouseEvent.CTRL_DOWN_MASK) { 168 Point p = e.getPoint(); 169 if (lastDragPoint != null) { 170 int diffx = lastDragPoint.x - p.x; 171 int diffy = lastDragPoint.y - p.y; 172 map.moveMap(diffx, diffy); 173 } 174 lastDragPoint = p; 175 } 176 177 } 178 179 } 180 181 /** 182 * Replies true if we are currently running on OSX 183 * 184 * @return true if we are currently running on OSX 185 */ 186 public static boolean isPlatformOsx() { 187 String os = System.getProperty("os.name"); 188 return os != null && os.toLowerCase(Locale.ENGLISH).startsWith("mac os x"); 189 } 190}