]> git.argeo.org Git - lgpl/argeo-commons.git/blobdiff - gis/plugins/org.argeo.gis.ui.rcp.swing/src/main/java/org/argeo/gis/ui/rcp/swing/VersatileZoomTool.java
Introduce Swing based map viewer
[lgpl/argeo-commons.git] / gis / plugins / org.argeo.gis.ui.rcp.swing / src / main / java / org / argeo / gis / ui / rcp / swing / VersatileZoomTool.java
diff --git a/gis/plugins/org.argeo.gis.ui.rcp.swing/src/main/java/org/argeo/gis/ui/rcp/swing/VersatileZoomTool.java b/gis/plugins/org.argeo.gis.ui.rcp.swing/src/main/java/org/argeo/gis/ui/rcp/swing/VersatileZoomTool.java
new file mode 100644 (file)
index 0000000..6b7b80c
--- /dev/null
@@ -0,0 +1,285 @@
+/*
+ * Copyright (C) 2010 Mathieu Baudier <mbaudier@argeo.org>
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *         http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.argeo.gis.ui.rcp.swing;
+
+import java.awt.Color;
+import java.awt.Cursor;
+import java.awt.Graphics2D;
+import java.awt.Point;
+import java.awt.Rectangle;
+import java.awt.event.MouseEvent;
+import java.awt.event.MouseWheelEvent;
+import java.awt.event.MouseWheelListener;
+import java.awt.geom.Point2D;
+
+import javax.swing.SwingUtilities;
+import javax.swing.event.MouseInputAdapter;
+
+import org.geotools.geometry.DirectPosition2D;
+import org.geotools.geometry.Envelope2D;
+import org.geotools.geometry.jts.ReferencedEnvelope;
+import org.geotools.swing.JMapPane;
+import org.geotools.swing.event.MapMouseEvent;
+import org.geotools.swing.tool.AbstractZoomTool;
+
+public class VersatileZoomTool extends AbstractZoomTool {
+       // private Log log = LogFactory.getLog(VersatileZoomTool.class);
+
+       // private static final ResourceBundle stringRes = ResourceBundle
+       // .getBundle("org/geotools/swing/Text");
+
+       // Cursors
+       private Cursor zoomInCursor;
+       private Cursor panCursor;
+       private Cursor defaultCursor;
+
+       // Variable values
+       private Point2D startDragPos;
+       private Point panePos;
+       private boolean computingZoomBox;
+       private boolean panning;
+
+       private Point2D fieldPosition;
+
+       /**
+        * Constructor
+        */
+       public VersatileZoomTool() {
+               // Toolkit tk = Toolkit.getDefaultToolkit();
+               // zoomInCursor = tk.createCustomCursor(new ImageIcon(getClass()
+               // .getResource("/org/geotools/swing/icons/mActionZoomIn.png"))
+               // .getImage(), new Point(14, 9), stringRes
+               // .getString("tool_name_zoom_in"));
+               zoomInCursor = new Cursor(Cursor.SE_RESIZE_CURSOR);
+               // panCursor = tk.createCustomCursor(new
+               // ImageIcon(getClass().getResource(
+               // "/org/geotools/swing/icons/mActionPan.png")).getImage(),
+               // new Point(15, 15), stringRes.getString("tool_name_pan"));
+               panCursor = new Cursor(Cursor.HAND_CURSOR);
+               defaultCursor = new Cursor(Cursor.CROSSHAIR_CURSOR);
+
+               startDragPos = new DirectPosition2D();
+               computingZoomBox = false;
+               panning = false;
+
+       }
+
+       /**
+        * Zoom in by the currently set increment, with the map centred at the
+        * location (in world coords) of the mouse click
+        * 
+        * @param e
+        *            map mapPane mouse event
+        */
+       @Override
+       public void onMouseClicked(MapMouseEvent e) {
+               if (SwingUtilities.isLeftMouseButton(e))
+                       centerMapToEvent(e, getZoom());
+               else if (SwingUtilities.isRightMouseButton(e))
+                       centerMapToEvent(e, 1 / getZoom());
+               else if (SwingUtilities.isMiddleMouseButton(e)) {
+                       if (fieldPosition != null) {
+                               Envelope2D env = new Envelope2D();
+                               final double increment = 0.1d;
+                               env.setFrameFromDiagonal(fieldPosition.getX() - increment,
+                                               fieldPosition.getY() - increment, fieldPosition.getX()
+                                                               + increment, fieldPosition.getY() + increment);
+                               getMapPane().setDisplayArea(env);
+                       }
+               }
+       }
+
+       protected void centerMapToEvent(MapMouseEvent e, Double zoomArg) {
+               Rectangle paneArea = getMapPane().getVisibleRect();
+               DirectPosition2D mapPos = e.getMapPosition();
+
+               double scale = getMapPane().getWorldToScreenTransform().getScaleX();
+               double newScale = scale * zoomArg;
+
+               DirectPosition2D corner = new DirectPosition2D(mapPos.getX() - 0.5d
+                               * paneArea.getWidth() / newScale, mapPos.getY() + 0.5d
+                               * paneArea.getHeight() / newScale);
+
+               Envelope2D newMapArea = new Envelope2D();
+               newMapArea.setFrameFromCenter(mapPos, corner);
+               getMapPane().setDisplayArea(newMapArea);
+       }
+
+       /**
+        * Records the map position of the mouse event in case this button press is
+        * the beginning of a mouse drag
+        * 
+        * @param ev
+        *            the mouse event
+        */
+       @Override
+       public void onMousePressed(MapMouseEvent ev) {
+               if (SwingUtilities.isLeftMouseButton(ev)) {
+                       startDragPos = new DirectPosition2D();
+                       startDragPos.setLocation(ev.getMapPosition());
+               } else if (SwingUtilities.isMiddleMouseButton(ev)
+                               || SwingUtilities.isRightMouseButton(ev)) {
+                       panePos = ev.getPoint();
+                       panning = true;
+               }
+       }
+
+       /**
+        * Records that the mouse is being dragged
+        * 
+        * @param ev
+        *            the mouse event
+        */
+       @Override
+       public void onMouseDragged(MapMouseEvent ev) {
+               if (SwingUtilities.isLeftMouseButton(ev)) {
+                       computingZoomBox = true;
+               } else if (panning) {
+                       Point pos = ev.getPoint();
+                       if (!pos.equals(panePos)) {
+                               getMapPane().moveImage(pos.x - panePos.x, pos.y - panePos.y);
+                               panePos = pos;
+                       }
+               }
+               getMapPane().setCursor(getCursor());
+       }
+
+       /**
+        * If the mouse was dragged, determines the bounds of the box that the user
+        * defined and passes this to the mapPane's
+        * {@link org.geotools.swing.JMapPane#setDisplayArea(org.opengis.geometry.Envelope) }
+        * method
+        * 
+        * @param ev
+        *            the mouse event
+        */
+       @Override
+       public void onMouseReleased(MapMouseEvent ev) {
+               if (computingZoomBox && !ev.getPoint().equals(startDragPos)) {
+                       Envelope2D env = new Envelope2D();
+                       env.setFrameFromDiagonal(startDragPos, ev.getMapPosition());
+                       computingZoomBox = false;
+                       getMapPane().setDisplayArea(env);
+               } else if (panning) {
+                       panning = false;
+                       getMapPane().repaint();
+               }
+               getMapPane().setCursor(getCursor());
+       }
+
+       /**
+        * Get the mouse cursor for this tool
+        */
+       @Override
+       public Cursor getCursor() {
+               if (computingZoomBox)
+                       return zoomInCursor;
+               else if (panning)
+                       return panCursor;
+               else
+                       return defaultCursor;
+       }
+
+       /**
+        * We use a custom drag box
+        */
+       @Override
+       public boolean drawDragBox() {
+               return false;
+       }
+
+       @Override
+       public void setMapPane(JMapPane pane) {
+               super.setMapPane(pane);
+               VariableDragBox dragBox = new VariableDragBox();
+               getMapPane().addMouseListener(dragBox);
+               getMapPane().addMouseMotionListener(dragBox);
+               getMapPane().addMouseWheelListener(new MouseWheelListener() {
+                       private double clickToZoom = 0.1; // 1 wheel click is 10% zoom
+
+                       public void mouseWheelMoved(MouseWheelEvent ev) {
+                               int clicks = ev.getWheelRotation();
+                               // -ve means wheel moved up, +ve means down
+                               int sign = (clicks < 0 ? -1 : 1);
+
+                               ReferencedEnvelope env = getMapPane().getDisplayArea();
+                               if (env == null)
+                                       return;
+                               double width = env.getWidth();
+                               double delta = width * clickToZoom * sign;
+
+                               env.expandBy(delta);
+                               getMapPane().setDisplayArea(env);
+                               getMapPane().repaint();
+                       }
+               });
+       }
+
+       public void setFieldPosition(Point2D fieldPosition) {
+               this.fieldPosition = fieldPosition;
+       }
+
+       /**
+        * Custom drag box (hacked from JMapPane) so that we can change the behavior
+        * depending on whether we pan or zoom.
+        */
+       private class VariableDragBox extends MouseInputAdapter {
+
+               private Point startPos;
+               private Rectangle rect;
+               private boolean dragged;
+
+               VariableDragBox() {
+                       rect = new Rectangle();
+                       dragged = false;
+               }
+
+               @Override
+               public void mousePressed(MouseEvent e) {
+                       startPos = new Point(e.getPoint());
+               }
+
+               @Override
+               public void mouseDragged(MouseEvent e) {
+                       if (computingZoomBox) {
+                               Graphics2D g2D = (Graphics2D) getMapPane().getGraphics();
+                               g2D.setColor(Color.WHITE);
+                               g2D.setXORMode(Color.RED);
+                               if (dragged) {
+                                       g2D.drawRect(rect.x, rect.y, rect.width, rect.height);
+                               }
+
+                               rect.setFrameFromDiagonal(startPos, e.getPoint());
+                               g2D.drawRect(rect.x, rect.y, rect.width, rect.height);
+
+                               dragged = true;
+                       }
+               }
+
+               @Override
+               public void mouseReleased(MouseEvent e) {
+                       if (dragged) {
+                               Graphics2D g2D = (Graphics2D) getMapPane().getGraphics();
+                               g2D.setColor(Color.WHITE);
+                               g2D.setXORMode(Color.RED);
+                               g2D.drawRect(rect.x, rect.y, rect.width, rect.height);
+                               dragged = false;
+                       }
+               }
+       }
+
+}