From 2f75ff792fb0a36b57fed447b685363bc64addbb Mon Sep 17 00:00:00 2001 From: Mathieu Baudier Date: Thu, 5 May 2011 14:35:20 +0000 Subject: [PATCH] Introduce Swing based map viewer NEW - bug 31: Add Swing based map viewer in RCP https://bugzilla.argeo.org/show_bug.cgi?id=31 git-svn-id: https://svn.argeo.org/commons/trunk@4508 4cfe0d0a-d680-48aa-b62c-e0a02a3f76cc --- .../org.argeo.gis.ui.rcp.swing/.classpath | 7 + .../org.argeo.gis.ui.rcp.swing/.project | 28 ++ .../.settings/org.eclipse.jdt.core.prefs | 8 + .../META-INF/MANIFEST.MF | 25 ++ .../META-INF/spring/mapviewer.xml | 12 + .../META-INF/spring/osgi.xml | 13 + .../build.properties | 4 + .../ui/rcp/swing/SwingMapControlCreator.java | 22 ++ .../gis/ui/rcp/swing/SwingMapViewer.java | 47 +++ .../gis/ui/rcp/swing/VersatileZoomTool.java | 285 ++++++++++++++++++ 10 files changed, 451 insertions(+) create mode 100644 gis/plugins/org.argeo.gis.ui.rcp.swing/.classpath create mode 100644 gis/plugins/org.argeo.gis.ui.rcp.swing/.project create mode 100644 gis/plugins/org.argeo.gis.ui.rcp.swing/.settings/org.eclipse.jdt.core.prefs create mode 100644 gis/plugins/org.argeo.gis.ui.rcp.swing/META-INF/MANIFEST.MF create mode 100644 gis/plugins/org.argeo.gis.ui.rcp.swing/META-INF/spring/mapviewer.xml create mode 100644 gis/plugins/org.argeo.gis.ui.rcp.swing/META-INF/spring/osgi.xml create mode 100644 gis/plugins/org.argeo.gis.ui.rcp.swing/build.properties create mode 100644 gis/plugins/org.argeo.gis.ui.rcp.swing/src/main/java/org/argeo/gis/ui/rcp/swing/SwingMapControlCreator.java create mode 100644 gis/plugins/org.argeo.gis.ui.rcp.swing/src/main/java/org/argeo/gis/ui/rcp/swing/SwingMapViewer.java create mode 100644 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/.classpath b/gis/plugins/org.argeo.gis.ui.rcp.swing/.classpath new file mode 100644 index 000000000..92f19d2ff --- /dev/null +++ b/gis/plugins/org.argeo.gis.ui.rcp.swing/.classpath @@ -0,0 +1,7 @@ + + + + + + + diff --git a/gis/plugins/org.argeo.gis.ui.rcp.swing/.project b/gis/plugins/org.argeo.gis.ui.rcp.swing/.project new file mode 100644 index 000000000..83b179023 --- /dev/null +++ b/gis/plugins/org.argeo.gis.ui.rcp.swing/.project @@ -0,0 +1,28 @@ + + + org.argeo.gis.ui.rcp.swing + + + + + + org.eclipse.jdt.core.javabuilder + + + + + org.eclipse.pde.ManifestBuilder + + + + + org.eclipse.pde.SchemaBuilder + + + + + + org.eclipse.pde.PluginNature + org.eclipse.jdt.core.javanature + + diff --git a/gis/plugins/org.argeo.gis.ui.rcp.swing/.settings/org.eclipse.jdt.core.prefs b/gis/plugins/org.argeo.gis.ui.rcp.swing/.settings/org.eclipse.jdt.core.prefs new file mode 100644 index 000000000..ca891a631 --- /dev/null +++ b/gis/plugins/org.argeo.gis.ui.rcp.swing/.settings/org.eclipse.jdt.core.prefs @@ -0,0 +1,8 @@ +#Thu May 05 15:41:33 CEST 2011 +eclipse.preferences.version=1 +org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled +org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.5 +org.eclipse.jdt.core.compiler.compliance=1.5 +org.eclipse.jdt.core.compiler.problem.assertIdentifier=error +org.eclipse.jdt.core.compiler.problem.enumIdentifier=error +org.eclipse.jdt.core.compiler.source=1.5 diff --git a/gis/plugins/org.argeo.gis.ui.rcp.swing/META-INF/MANIFEST.MF b/gis/plugins/org.argeo.gis.ui.rcp.swing/META-INF/MANIFEST.MF new file mode 100644 index 000000000..4a2380d14 --- /dev/null +++ b/gis/plugins/org.argeo.gis.ui.rcp.swing/META-INF/MANIFEST.MF @@ -0,0 +1,25 @@ +Manifest-Version: 1.0 +Bundle-ManifestVersion: 2 +Bundle-Name: RCP specific components based on Swing +Bundle-SymbolicName: org.argeo.gis.ui.rcp.swing +Bundle-Version: 0.3.2.SNAPSHOT +Bundle-RequiredExecutionEnvironment: J2SE-1.5 +Import-Package: com.vividsolutions.jts.geom;version="1.10.0", + javax.jcr;version="2.0.0", + org.argeo.geotools.jcr, + org.argeo.gis.ui, + org.eclipse.swt, + org.eclipse.swt.awt, + org.eclipse.swt.widgets, + org.geotools.data, + org.geotools.geometry, + org.geotools.geometry.jts, + org.geotools.map, + org.geotools.renderer, + org.geotools.renderer.lite, + org.geotools.swing, + org.geotools.swing.event, + org.geotools.swing.tool, + org.opengis.feature, + org.opengis.feature.simple, + org.opengis.geometry diff --git a/gis/plugins/org.argeo.gis.ui.rcp.swing/META-INF/spring/mapviewer.xml b/gis/plugins/org.argeo.gis.ui.rcp.swing/META-INF/spring/mapviewer.xml new file mode 100644 index 000000000..b163efdb8 --- /dev/null +++ b/gis/plugins/org.argeo.gis.ui.rcp.swing/META-INF/spring/mapviewer.xml @@ -0,0 +1,12 @@ + + + + + + + + diff --git a/gis/plugins/org.argeo.gis.ui.rcp.swing/META-INF/spring/osgi.xml b/gis/plugins/org.argeo.gis.ui.rcp.swing/META-INF/spring/osgi.xml new file mode 100644 index 000000000..7a4ec53ed --- /dev/null +++ b/gis/plugins/org.argeo.gis.ui.rcp.swing/META-INF/spring/osgi.xml @@ -0,0 +1,13 @@ + + + + + + + + \ No newline at end of file diff --git a/gis/plugins/org.argeo.gis.ui.rcp.swing/build.properties b/gis/plugins/org.argeo.gis.ui.rcp.swing/build.properties new file mode 100644 index 000000000..5fc538bc8 --- /dev/null +++ b/gis/plugins/org.argeo.gis.ui.rcp.swing/build.properties @@ -0,0 +1,4 @@ +source.. = src/main/java/ +output.. = target/classes/ +bin.includes = META-INF/,\ + . diff --git a/gis/plugins/org.argeo.gis.ui.rcp.swing/src/main/java/org/argeo/gis/ui/rcp/swing/SwingMapControlCreator.java b/gis/plugins/org.argeo.gis.ui.rcp.swing/src/main/java/org/argeo/gis/ui/rcp/swing/SwingMapControlCreator.java new file mode 100644 index 000000000..80c56f80a --- /dev/null +++ b/gis/plugins/org.argeo.gis.ui.rcp.swing/src/main/java/org/argeo/gis/ui/rcp/swing/SwingMapControlCreator.java @@ -0,0 +1,22 @@ +package org.argeo.gis.ui.rcp.swing; + +import javax.jcr.Node; + +import org.argeo.geotools.jcr.GeoJcrMapper; +import org.argeo.gis.ui.MapControlCreator; +import org.argeo.gis.ui.MapViewer; +import org.eclipse.swt.widgets.Composite; + +/** Creates a Swing map viewer */ +public class SwingMapControlCreator implements MapControlCreator { + private GeoJcrMapper geoJcrMapper; + + public MapViewer createMapControl(Node context, Composite parent) { + return new SwingMapViewer(context, geoJcrMapper, parent); + } + + public void setGeoJcrMapper(GeoJcrMapper geoJcrMapper) { + this.geoJcrMapper = geoJcrMapper; + } + +} diff --git a/gis/plugins/org.argeo.gis.ui.rcp.swing/src/main/java/org/argeo/gis/ui/rcp/swing/SwingMapViewer.java b/gis/plugins/org.argeo.gis.ui.rcp.swing/src/main/java/org/argeo/gis/ui/rcp/swing/SwingMapViewer.java new file mode 100644 index 000000000..6a1ed0fc1 --- /dev/null +++ b/gis/plugins/org.argeo.gis.ui.rcp.swing/src/main/java/org/argeo/gis/ui/rcp/swing/SwingMapViewer.java @@ -0,0 +1,47 @@ +package org.argeo.gis.ui.rcp.swing; + +import java.awt.Frame; + +import javax.jcr.Node; + +import org.argeo.geotools.jcr.GeoJcrMapper; +import org.argeo.gis.ui.AbstractMapViewer; +import org.eclipse.swt.SWT; +import org.eclipse.swt.awt.SWT_AWT; +import org.eclipse.swt.widgets.Composite; +import org.geotools.data.FeatureSource; +import org.geotools.map.DefaultMapContext; +import org.geotools.renderer.lite.StreamingRenderer; +import org.geotools.swing.JMapPane; +import org.opengis.feature.simple.SimpleFeature; +import org.opengis.feature.simple.SimpleFeatureType; + +public class SwingMapViewer extends AbstractMapViewer { + private Composite embedded; + private JMapPane mapPane; + private VersatileZoomTool versatileZoomTool; + + public SwingMapViewer(Node context, GeoJcrMapper geoJcrMapper, + Composite parent) { + super(context, geoJcrMapper); + + embedded = new Composite(parent, SWT.EMBEDDED | SWT.NO_BACKGROUND); + Frame frame = SWT_AWT.new_Frame(embedded); + + mapPane = new JMapPane(new StreamingRenderer(), new DefaultMapContext()); + versatileZoomTool = new VersatileZoomTool(); + mapPane.setCursorTool(versatileZoomTool); + + frame.add(mapPane); + + setControl(embedded); + } + + @Override + protected void addFeatureSource(String path, + FeatureSource featureSource) { + // TODO: deal with style and rasters + mapPane.getMapContext().addLayer(featureSource, null); + } + +} 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 index 000000000..6b7b80c8a --- /dev/null +++ b/gis/plugins/org.argeo.gis.ui.rcp.swing/src/main/java/org/argeo/gis/ui/rcp/swing/VersatileZoomTool.java @@ -0,0 +1,285 @@ +/* + * Copyright (C) 2010 Mathieu Baudier + * + * 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; + } + } + } + +} -- 2.30.2