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