/******************************************************************************* * Copyright (c) 2008, 2012 Stepan Rutz. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * Stepan Rutz - initial implementation * Hallvard Trætteberg - further cleanup and development *******************************************************************************/ package org.eclipse.nebula.widgets.geomap; import java.util.ArrayList; import java.util.EventListener; import java.util.List; import org.eclipse.nebula.widgets.geomap.internal.DefaultMouseHandler; import org.eclipse.nebula.widgets.geomap.internal.InternalGeoMap; import org.eclipse.swt.events.MouseEvent; import org.eclipse.swt.events.MouseListener; import org.eclipse.swt.events.MouseMoveListener; import org.eclipse.swt.events.MouseTrackListener; import org.eclipse.swt.events.MouseWheelListener; import org.eclipse.swt.events.PaintListener; import org.eclipse.swt.graphics.Point; import org.eclipse.swt.graphics.Rectangle; import org.eclipse.swt.widgets.Composite; /** * GeoMap display tiles from openstreetmap as is. This simple minimal viewer supports zoom around mouse-click center and has a simple api. * A number of tiles are cached. If you use this it will create traffic on the tileserver you are * using. Please be conscious about this. * * This class is a JPanel which can be integrated into any swing app just by creating an instance and adding like a JLabel. * * The map has the size <code>256*1<<zoomlevel</code>. This measure is referred to as map-coordinates. Geometric locations * like longitude and latitude can be obtained by helper methods. Note that a point in map-coordinates corresponds to a given * geometric position but also depending on the current zoom level. * * You can zoomIn around current mouse position by left double click. Left right click zooms out. * * <p> * Methods of interest are * <ul> * <li>{@link #setZoom(int)} which sets the map's zoom level. Values between 1 and 18 are allowed.</li> * <li>{@link #setMapPosition(Point)} which sets the map's top left corner. (In map coordinates)</li> * <li>{@link #setCenterPosition(Point)} which sets the map's center position. (In map coordinates)</li> * for the given longitude and latitude. If you want to center the map around this geometric location you need * to pass the result to the method</li> * </ul> * </p> * * <p>For performance tuning the two crucial parameters are the size of the tile cache and the * number of image-loader threads. * </p> * * </p> * * <p>License is EPL (Eclipse Public License) http://www.eclipse.org/legal/epl-v10.html. Contact at stepan.rutz@gmx.de</p> * * @author stepan.rutz * @version $Revision$ */ public class GeoMap extends InternalGeoMap { /** * About message. */ @SuppressWarnings({ "nls" }) public static final String ABOUT_MSG = "GeoMap - Minimal Openstreetmap/Maptile Viewer\r\n" + "Requirements: Java + SWT. Opensource and licensed under EPL.\r\n" + "\r\n" + "Web/Source: <a href=\"http://eclipse.org/nebula\">http://eclipse.org/nebula</a>\r\n" + "Written by Stephan Rutz. Maintained by the Eclipse Nebula Project.\r\n\r\n" + "Tileserver and Nominationserver are accessed online and are part of Openstreetmap.org and not of this software.\r\n"; private Point mouseCoords = new Point(0, 0); private DefaultMouseHandler defaultMouseHandler = new DefaultMouseHandler(this) { public Point getMapSize() { return getSize(); } }; private static final int DEFAULT_CACHE_SIZE = 256; /** * Creates a new <code>GeoMap</code> using the default size * for its internal cache of tiles. The map is showing the position <code>(275091, 180145</code> * at zoom level <code>11</code>. In other words this constructor is best used only in debugging * scenarios. * * @param parent SWT parent <code>Composite</code> * @param style SWT style as in <code>Canvas</code>, since this class inherits from it. Double buffering is always enabed. */ public GeoMap(Composite parent, int style) { this(parent, style, new Point(275091, 180145), 11); } /** * Creates a new <code>GeoMap</code> using the default size for its internal cache of tiles * @param parent SWT parent <code>Composite</code> * @param style SWT style as in <code>Canvas</code>, since this class inherits from it. Double buffering is always enabed. * @param mapPosition initial mapPosition. * @param zoom initial map zoom */ public GeoMap(Composite parent, int style, Point mapPosition, int zoom) { this(parent, style, mapPosition, zoom, DEFAULT_CACHE_SIZE); } private class MouseCoordsHandler implements MouseListener, MouseMoveListener { private void setMouseCoords(MouseEvent e) { mouseCoords = new Point(e.x, e.y); } public void mouseDown(MouseEvent e) { setMouseCoords(e); } public void mouseMove(MouseEvent e) { setMouseCoords(e); } public void mouseUp(MouseEvent e) { setMouseCoords(e); } public void mouseDoubleClick(MouseEvent e) { setMouseCoords(e); } } /** * Creates a new <code>GeoMap</code> using the default size * for its internal cache of tiles * @param parent SWT parent <code>Composite</code> * @param style SWT style as in <code>Canvas</code>, since this class inherits from it. Double buffering is always enabed. * @param mapPosition initial mapPosition. * @param zoom initial map zoom * @param cacheSize initial cache size, eg number of tile-images that are kept in cache * to prevent reloading from the network. */ public GeoMap(Composite parent, int style, Point mapPosition, int zoom, int cacheSize) { super(parent, style, mapPosition, zoom, cacheSize); MouseCoordsHandler mouseCoordsHandler = new MouseCoordsHandler(); addMouseListener(mouseCoordsHandler); addMouseMoveListener(mouseCoordsHandler); addMouseHandler(defaultMouseHandler); } /** * Returns the default mouse handler, so it may be configured or removed. * @return the default mouse handler */ public DefaultMouseHandler getDefaultMouseHandler() { return defaultMouseHandler; } /** * Adds listener to appropriate listener lists depending on the listener interfaces that are implemented. * @param listener the listener */ public void addMouseHandler(EventListener listener) { if (listener instanceof MouseListener) { addMouseListener((MouseListener) listener); } if (listener instanceof MouseMoveListener) { addMouseMoveListener((MouseMoveListener) listener); } if (listener instanceof MouseTrackListener) { addMouseTrackListener((MouseTrackListener) listener); } if (listener instanceof MouseWheelListener) { addMouseWheelListener((MouseWheelListener) listener); } if (listener instanceof PaintListener) { addPaintListener((PaintListener) listener); } } /** * Removes listener from appropriate listener lists depending on the listener interfaces that are implemented. * @param listener the listener */ public void removeMouseHandler(EventListener listener) { if (listener instanceof MouseListener) { removeMouseListener((MouseListener) listener); } if (listener instanceof MouseMoveListener) { removeMouseMoveListener((MouseMoveListener) listener); } if (listener instanceof MouseTrackListener) { removeMouseTrackListener((MouseTrackListener) listener); } if (listener instanceof MouseWheelListener) { removeMouseWheelListener((MouseWheelListener) listener); } if (listener instanceof PaintListener) { removePaintListener((PaintListener) listener); } } // /** * Returns the current TileServer of this GeoMap. * @return the current TileServer */ public TileServer getTileServer() { return geoMapHelper.getTileServer(); } /** * Sets the current TileServer of this GeoMap. * Note that this will clear the map and reload the tiles using the new TileServer. * @param tileServer the TileServer */ public void setTileServer(TileServer tileServer) { geoMapHelper.setTileServer(tileServer); } // private List<GeoMapListener> geoMapListeners; /** * Adds a GeoMapListener, that will be notified of changes to the position and zoom level * @param listener the GeoMapListener */ public void addGeoMapListener(GeoMapListener listener) { if (geoMapListeners == null) { geoMapListeners = new ArrayList<GeoMapListener>(); } geoMapListeners.add(listener); } /** * Removes a GeoMapListener, so it no longer will be notified of changes to the position and zoom level * @param listener the GeoMapListener */ public void removeGeoMapListener(GeoMapListener listener) { if (geoMapListeners != null) { geoMapListeners.remove(listener); } } private void fireCenterChanged() { if (geoMapListeners != null) { for (GeoMapListener listener : geoMapListeners) { listener.centerChanged(this); } } } private void fireZoomChanged() { if (geoMapListeners != null) { for (GeoMapListener listener : geoMapListeners) { listener.zoomChanged(this); } } } // /** * Sets the position of the upper left corner of this GeoMap, without any panning effect. * @param mapPosition the new position */ public void setMapPosition(Point mapPosition) { setMapPosition(mapPosition.x, mapPosition.y); } /** * Sets the position of the upper left corner of this GeoMap, without any panning effect. * @param x the x-coordinate of the position * @param y the y-coordinate of the position */ public void setMapPosition(int x, int y) { super.setMapPosition(x, y); fireCenterChanged(); } /** * Translates the position of the upper left corner of this GeoMap, without any panning effect. * @param tx the relative distance in x-direction * @param ty the relative distance in y-direction */ public void translateMapPosition(int tx, int ty) { GeoMapUtil.translateMapPosition(this, tx, ty); } /** * Sets the zoom level, without any transition effect. * @param zoom the new zoom level */ public void setZoom(int zoom) { super.setZoom(zoom); fireZoomChanged(); } /** * Zooms in, while ensuring that the pivot point remains at the same screen location. * @param pivot the point that will remain at the same screen location. */ public void zoomIn(Point pivot) { GeoMapUtil.zoomIn(this, pivot); redraw(); } /** * Zooms out, while ensuring that the pivot point remains at the same screen location. * @param pivot the point that will remain at the same screen location. */ public void zoomOut(Point pivot) { GeoMapUtil.zoomOut(this, pivot); redraw(); } /** * Zooms into and centers on the specified rectangle. * @param rect the rectangle */ public void zoomTo(Rectangle rect) { GeoMapUtil.zoomTo(this, getSize(), rect, -1); redraw(); } /** * Returns the position of the center of this GeoMap. * The coordinates depend on the zoom level. * @return the position of the center of this GeoMap */ public Point getCenterPosition() { org.eclipse.swt.graphics.Point size = getSize(); Point mapPosition = getMapPosition(); return new Point(mapPosition.x + size.x / 2, mapPosition.y + size.y / 2); } /** * Sets the position of the center of this GeoMap, without any panning effect. * @param mapPosition the new position */ public void setCenterPosition(Point mapPosition) { org.eclipse.swt.graphics.Point size = getSize(); setMapPosition(mapPosition.x - size.x / 2, mapPosition.y - size.y / 2); } /** * Returns the map position of the mouse cursor. * @return the map position of the mouse cursor */ public Point getCursorPosition() { Point mapPosition = getMapPosition(); return new Point(mapPosition.x + mouseCoords.x, mapPosition.y + mouseCoords.y); } }