[Schmitzm-commits] r740 - in trunk/src: schmitzm/geotools/gui schmitzm/geotools/map/event schmitzm/geotools/styling skrueger/geotools skrueger/geotools/labelsearch skrueger/geotools/selection
scm-commit@wald.intevation.org
scm-commit at wald.intevation.org
Wed Mar 3 11:32:17 CET 2010
Author: alfonx
Date: 2010-03-03 11:32:14 +0100 (Wed, 03 Mar 2010)
New Revision: 740
Added:
trunk/src/schmitzm/geotools/gui/MapRenderingStateEvent.java
trunk/src/schmitzm/geotools/gui/XMapPane.java
trunk/src/schmitzm/geotools/gui/XMapPaneAction.java
trunk/src/schmitzm/geotools/gui/XMapPaneActionAdapter.java
trunk/src/schmitzm/geotools/gui/XMapPaneAction_Pan.java
trunk/src/schmitzm/geotools/gui/XMapPaneAction_Select.java
trunk/src/schmitzm/geotools/gui/XMapPaneAction_Zoom.java
trunk/src/schmitzm/geotools/gui/XMapPaneEvent.java
trunk/src/schmitzm/geotools/gui/XMapPaneMouseListener.java
trunk/src/schmitzm/geotools/gui/XMapPaneTool.java
Removed:
trunk/src/schmitzm/geotools/map/event/MapPaneEvent.java
trunk/src/schmitzm/geotools/map/event/MapRenderingStateEvent.java
trunk/src/skrueger/geotools/XMapPane.java
trunk/src/skrueger/geotools/XMapPaneAction.java
trunk/src/skrueger/geotools/XMapPaneActionAdapter.java
trunk/src/skrueger/geotools/XMapPaneAction_Pan.java
trunk/src/skrueger/geotools/XMapPaneAction_Select.java
trunk/src/skrueger/geotools/XMapPaneAction_Zoom.java
trunk/src/skrueger/geotools/XMapPaneMouseListener.java
trunk/src/skrueger/geotools/XMapPaneTool.java
Modified:
trunk/src/schmitzm/geotools/gui/GeoMapPane.java
trunk/src/schmitzm/geotools/gui/JMapEditorPane.java
trunk/src/schmitzm/geotools/gui/JMapEditorToolBar.java
trunk/src/schmitzm/geotools/gui/LayeredMapFrame.java
trunk/src/schmitzm/geotools/gui/MapActionControlPane.java
trunk/src/schmitzm/geotools/gui/SelectableXMapPane.java
trunk/src/schmitzm/geotools/map/event/FeatureSelectedEvent.java
trunk/src/schmitzm/geotools/map/event/GeneralSelectionEvent.java
trunk/src/schmitzm/geotools/map/event/GridCoverageSelectedEvent.java
trunk/src/schmitzm/geotools/map/event/JEditorPaneEvent.java
trunk/src/schmitzm/geotools/map/event/JMapPaneListener.java
trunk/src/schmitzm/geotools/map/event/MapAreaChangedEvent.java
trunk/src/schmitzm/geotools/map/event/ObjectSelectionEvent.java
trunk/src/schmitzm/geotools/map/event/ScaleChangedEvent.java
trunk/src/schmitzm/geotools/styling/StylingUtil.java
trunk/src/skrueger/geotools/MapPaneToolBar.java
trunk/src/skrueger/geotools/RenderingExecutor.java
trunk/src/skrueger/geotools/labelsearch/SearchResultFeature.java
trunk/src/skrueger/geotools/selection/FeatureMapLayerSelectionSynchronizer.java
Log:
Moved XMapPane and it's listeners/actions/tools to schmitzm.geotools.swing
Modified: trunk/src/schmitzm/geotools/gui/GeoMapPane.java
===================================================================
--- trunk/src/schmitzm/geotools/gui/GeoMapPane.java 2010-03-03 01:48:43 UTC (rev 739)
+++ trunk/src/schmitzm/geotools/gui/GeoMapPane.java 2010-03-03 10:32:14 UTC (rev 740)
@@ -44,11 +44,9 @@
import schmitzm.geotools.GTUtil;
import schmitzm.geotools.map.event.JMapPaneListener;
import schmitzm.geotools.map.event.MapAreaChangedEvent;
-import schmitzm.geotools.map.event.MapPaneEvent;
import schmitzm.geotools.map.event.ScaleChangedEvent;
import schmitzm.swing.JPanel;
import schmitzm.swing.SwingUtil;
-import skrueger.geotools.XMapPane;
/**
* Das {@code GeoMapPane} erweitert das {@link SelectableXMapPane} um einen
@@ -206,7 +204,7 @@
// MapListener that listens to Scale and MapArea changes
this.mapPane.addMapPaneListener(new JMapPaneListener() {
- public void performMapPaneEvent(MapPaneEvent e) {
+ public void performMapPaneEvent(XMapPaneEvent e) {
if (e instanceof ScaleChangedEvent) {
ScaleChangedEvent sce = (ScaleChangedEvent) e;
getScalePane().setScale(sce.getNewScale());
Modified: trunk/src/schmitzm/geotools/gui/JMapEditorPane.java
===================================================================
--- trunk/src/schmitzm/geotools/gui/JMapEditorPane.java 2010-03-03 01:48:43 UTC (rev 739)
+++ trunk/src/schmitzm/geotools/gui/JMapEditorPane.java 2010-03-03 10:32:14 UTC (rev 740)
@@ -65,10 +65,6 @@
import schmitzm.swing.InputOption;
import schmitzm.swing.MultipleOptionPane;
import schmitzm.swing.event.MouseInputType;
-import skrueger.geotools.XMapPane;
-import skrueger.geotools.XMapPaneAction;
-import skrueger.geotools.XMapPaneActionAdapter;
-import skrueger.geotools.XMapPaneTool;
import com.vividsolutions.jts.geom.Coordinate;
import com.vividsolutions.jts.geom.Geometry;
Modified: trunk/src/schmitzm/geotools/gui/JMapEditorToolBar.java
===================================================================
--- trunk/src/schmitzm/geotools/gui/JMapEditorToolBar.java 2010-03-03 01:48:43 UTC (rev 739)
+++ trunk/src/schmitzm/geotools/gui/JMapEditorToolBar.java 2010-03-03 10:32:14 UTC (rev 740)
@@ -48,7 +48,6 @@
import schmitzm.geotools.map.event.JMapPaneListener;
import schmitzm.geotools.map.event.LayerEditCanceledEvent;
import schmitzm.geotools.map.event.LayerEditFinishedEvent;
-import schmitzm.geotools.map.event.MapPaneEvent;
import schmitzm.swing.ExceptionDialog;
import schmitzm.swing.ManualInputOption;
import schmitzm.swing.MultipleOptionPane;
@@ -101,7 +100,7 @@
this.actionButtons = new TreeMap<Integer,JButton>();
// Create a Listener to sniff the zooms on the JMapPane
this.mapPaneListener = new JMapPaneListener() {
- public void performMapPaneEvent(MapPaneEvent e) {
+ public void performMapPaneEvent(XMapPaneEvent e) {
if ( !(e instanceof JEditorPaneEvent) )
return;
Modified: trunk/src/schmitzm/geotools/gui/LayeredMapFrame.java
===================================================================
--- trunk/src/schmitzm/geotools/gui/LayeredMapFrame.java 2010-03-03 01:48:43 UTC (rev 739)
+++ trunk/src/schmitzm/geotools/gui/LayeredMapFrame.java 2010-03-03 10:32:14 UTC (rev 740)
@@ -49,7 +49,6 @@
import schmitzm.geotools.map.event.FeatureSelectedEvent;
import schmitzm.geotools.map.event.GridCoverageSelectedEvent;
import schmitzm.geotools.map.event.JMapPaneListener;
-import schmitzm.geotools.map.event.MapPaneEvent;
import schmitzm.swing.SelectionInputOption;
import schmitzm.swing.SwingUtil;
@@ -211,7 +210,7 @@
featuresFrame.setSize(new Dimension(400, 200));
// Ausgewaehlte Features werden im Detail-Frame angezeigt
mapPane.addMapPaneListener(new JMapPaneListener() {
- public void performMapPaneEvent(MapPaneEvent e) {
+ public void performMapPaneEvent(XMapPaneEvent e) {
// Wenn Features ueber die Maus aus der Karte ausgewaehlt werden,
// oeffnet sich ein Detail-Fenster
if (e instanceof FeatureSelectedEvent && e.getSourceObject() == mapPane) {
Modified: trunk/src/schmitzm/geotools/gui/MapActionControlPane.java
===================================================================
--- trunk/src/schmitzm/geotools/gui/MapActionControlPane.java 2010-03-03 01:48:43 UTC (rev 739)
+++ trunk/src/schmitzm/geotools/gui/MapActionControlPane.java 2010-03-03 10:32:14 UTC (rev 740)
@@ -43,7 +43,6 @@
import schmitzm.geotools.map.event.FeatureSelectedEvent;
import schmitzm.swing.CaptionsChangeable;
import schmitzm.swing.SwingUtil;
-import skrueger.geotools.XMapPaneTool;
/**
* Diese Klasse stellt einen {@link JToolBar} dar, mit dem zwischen den
Copied: trunk/src/schmitzm/geotools/gui/MapRenderingStateEvent.java (from rev 736, trunk/src/schmitzm/geotools/map/event/MapRenderingStateEvent.java)
===================================================================
--- trunk/src/schmitzm/geotools/map/event/MapRenderingStateEvent.java 2010-03-02 16:22:12 UTC (rev 736)
+++ trunk/src/schmitzm/geotools/gui/MapRenderingStateEvent.java 2010-03-03 10:32:14 UTC (rev 740)
@@ -0,0 +1,26 @@
+package schmitzm.geotools.gui;
+
+import org.opengis.display.canvas.RenderingState;
+
+
+/**
+ * Events of this Class are fired, when rendering starts and stops. Cancels and
+ * Errors are fired as Stops.
+ *
+ * @author stefan
+ *
+ */
+public class MapRenderingStateEvent extends XMapPaneEvent {
+
+ private final RenderingState state;
+
+ public MapRenderingStateEvent(XMapPane source, RenderingState state) {
+ super(source);
+ this.state = state;
+ }
+
+ public RenderingState getState() {
+ return state;
+ }
+
+}
Property changes on: trunk/src/schmitzm/geotools/gui/MapRenderingStateEvent.java
___________________________________________________________________
Name: svn:mime-type
+ text/plain
Name: svn:keywords
+ Id URL
Name: svn:eol-style
+ native
Modified: trunk/src/schmitzm/geotools/gui/SelectableXMapPane.java
===================================================================
--- trunk/src/schmitzm/geotools/gui/SelectableXMapPane.java 2010-03-03 01:48:43 UTC (rev 739)
+++ trunk/src/schmitzm/geotools/gui/SelectableXMapPane.java 2010-03-03 10:32:14 UTC (rev 740)
@@ -76,11 +76,9 @@
import schmitzm.geotools.map.event.GridCoverageValueSelectedEvent;
import schmitzm.geotools.map.event.JMapPaneListener;
import schmitzm.geotools.map.event.MapAreaChangedEvent;
-import schmitzm.geotools.map.event.MapPaneEvent;
import schmitzm.geotools.map.event.ScaleChangedEvent;
import schmitzm.geotools.styling.StylingUtil;
import skrueger.geotools.GeomFilterGenerator;
-import skrueger.geotools.XMapPane;
import skrueger.geotools.GeomFilterGenerator.BoundingBoxFilterGenerator;
import com.vividsolutions.jts.geom.Coordinate;
Copied: trunk/src/schmitzm/geotools/gui/XMapPane.java (from rev 736, trunk/src/skrueger/geotools/XMapPane.java)
===================================================================
--- trunk/src/skrueger/geotools/XMapPane.java 2010-03-02 16:22:12 UTC (rev 736)
+++ trunk/src/schmitzm/geotools/gui/XMapPane.java 2010-03-03 10:32:14 UTC (rev 740)
@@ -0,0 +1,2952 @@
+package schmitzm.geotools.gui;
+
+import java.awt.Color;
+import java.awt.Cursor;
+import java.awt.Font;
+import java.awt.Graphics;
+import java.awt.Graphics2D;
+import java.awt.Image;
+import java.awt.Point;
+import java.awt.Rectangle;
+import java.awt.RenderingHints;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.awt.event.ComponentAdapter;
+import java.awt.event.ComponentEvent;
+import java.awt.event.MouseEvent;
+import java.awt.event.MouseListener;
+import java.awt.geom.AffineTransform;
+import java.awt.geom.NoninvertibleTransformException;
+import java.awt.geom.Point2D;
+import java.awt.image.BufferedImage;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Vector;
+
+import javax.swing.JList;
+import javax.swing.Timer;
+import javax.swing.border.Border;
+
+import org.apache.log4j.Logger;
+import org.geotools.data.FeatureSource;
+import org.geotools.data.memory.MemoryFeatureCollection;
+import org.geotools.factory.GeoTools;
+import org.geotools.feature.FeatureCollection;
+import org.geotools.geometry.DirectPosition2D;
+import org.geotools.geometry.jts.JTS;
+import org.geotools.geometry.jts.ReferencedEnvelope;
+import org.geotools.map.DefaultMapContext;
+import org.geotools.map.DefaultMapLayer;
+import org.geotools.map.MapContext;
+import org.geotools.map.MapLayer;
+import org.geotools.map.event.MapLayerEvent;
+import org.geotools.map.event.MapLayerListEvent;
+import org.geotools.map.event.MapLayerListListener;
+import org.geotools.map.event.MapLayerListener;
+import org.geotools.referencing.CRS;
+import org.geotools.renderer.GTRenderer;
+import org.geotools.renderer.label.LabelCacheImpl;
+import org.geotools.renderer.lite.LabelCache;
+import org.geotools.renderer.lite.RendererUtilities;
+import org.geotools.renderer.lite.StreamingRenderer;
+import org.geotools.resources.image.ImageUtilities;
+import org.geotools.styling.Style;
+import org.geotools.swing.JMapPane;
+import org.geotools.swing.event.MapMouseEvent;
+import org.geotools.swing.event.MapPaneListener;
+import org.opengis.display.canvas.RenderingState;
+import org.opengis.feature.simple.SimpleFeature;
+import org.opengis.feature.simple.SimpleFeatureType;
+import org.opengis.referencing.FactoryException;
+import org.opengis.referencing.crs.CoordinateReferenceSystem;
+import org.opengis.referencing.operation.MathTransform;
+import org.opengis.referencing.operation.TransformException;
+
+import schmitzm.geotools.GTUtil;
+import schmitzm.geotools.JTSUtil;
+import schmitzm.geotools.io.GeoImportUtil;
+import schmitzm.geotools.map.event.JMapPaneListener;
+import schmitzm.geotools.map.event.MapLayerAdapter;
+import schmitzm.geotools.styling.StylingUtil;
+import schmitzm.lang.LangUtil;
+import schmitzm.swing.JPanel;
+import schmitzm.swing.SwingUtil;
+import schmitzm.swing.event.MouseInputType;
+import skrueger.geotools.RenderingExecutor;
+
+import com.vividsolutions.jts.geom.Coordinate;
+import com.vividsolutions.jts.geom.Envelope;
+import com.vividsolutions.jts.geom.Geometry;
+
+/**
+ * The {@link XMapPane} class uses a Geotools {@link GTRenderer} to paint up to
+ * two {@link MapContext}s: a "local" {@link MapContext} and a "background"
+ * {@link MapContext}. The idea is, that rendering a background layer made up of
+ * e.g. OSM data, may take much longer than rendering local data.<br>
+ * Every {@link MapContext} is rendered on a {@link Thread} of it's own.
+ * Starting/ cancelling these threads is done by the {@link RenderingExecutor}.<br>
+ * <br>
+ * While the renderers are rending the map, a <br>
+ * The {@link XMapPane} is based on schmitzm {@link JPanel}, so
+ * {@link #print(Graphics)} will automatically set the background of components
+ * to pure white.
+ *
+ * The XMapPane has a {@link MouseListener} that manages zooming.<br>
+ * A logo/icon to float in the lower left corner may be set with
+ * {@link #setMapImage(BufferedImage)}<br>
+ *
+ * @see SelectableXMapPane - an extension of {@link XMapPane} that supports
+ * selecting features.
+ *
+ * @author stefan
+ *
+ */
+public class XMapPane extends JPanel {
+
+ /**
+ * If {@link #maxExtend} is <code>null</code> the following rules are used
+ * to create a default maximum.
+ * <ul>
+ * <li>Values < 0 : don't grow to fit the monitors aspect ratio, no
+ * margin</li>
+ * <li>Values 0 : grow to fit the monitors aspect ratio, no margin</li>
+ * <li>Values > 0 : grow to fit the monitors aspect ratio, and add a
+ * relative margin</li>
+ * </ul>
+ * **/
+ private double defaultMaxMapExtendMode = .05;
+
+ // private static final int IMAGETYPE = BufferedImage.TYPE_INT_RGB;
+ // private static final int IMAGETYPE_withAlpha =
+ // BufferedImage.TYPE_INT_ARGB;
+ private static final int IMAGETYPE = BufferedImage.TYPE_3BYTE_BGR;
+
+ public XMapPaneTool getTool() {
+ return tool;
+ }
+
+ /**
+ * If the {@link JPanel} is disabled, it shows nothing and the images are
+ * disposed.
+ */
+ @Override
+ public void setEnabled(boolean enabled) {
+ super.setEnabled(enabled);
+ if (enabled == false)
+ disposeImages();
+ else
+ requestStartRendering();
+ }
+
+ private static final int IMAGETYPE_withAlpha = BufferedImage.TYPE_4BYTE_ABGR;
+
+ private final static Logger LOGGER = Logger.getLogger(XMapPane.class);
+
+ /**
+ * A flag indicating whether the {@link XMapPane} is accepting repaints from
+ * the EDT. @see {@link XMapPane#setPainting(boolean))
+ **/
+ private boolean acceptsRepaintCalls = true;
+
+ /**
+ * Main {@link MapContext} that holds all layers that are rendered into the
+ * {@link #localImage} by the {@link #localRenderer}
+ */
+ MapContext localContext;
+
+ /**
+ * {@link MapContext} holding the background layers. Use it for layers that
+ * CAN take very long for rendering, like layer from the Internet: WMS, WFS,
+ * OSM...<br>
+ * <code>null</code> by default.
+ *
+ * @see #setBgContext(MapContext)
+ * @see #getBgContext()
+ */
+ MapContext bgContext;
+
+ /**
+ * While threads are working, calls {@link XMapPane#updateFinalImage()}
+ * regularly and {@link #repaint()}. This {@link Timer} is stopped when all
+ * renderers have finished.
+ *
+ * @see INITIAL_REPAINT_DELAYAL
+ * @see #REPEATING_REPAINT_DELAY
+ */
+ final private Timer repaintTimer;
+
+ /**
+ * The initial delay in milliseconds until the {@link #finalImage} is
+ * updated the first time.
+ */
+ public static final int INITIAL_REPAINT_DELAY = 900;
+
+ /**
+ * While the {@link #bgExecuter} and {@link #localExecuter} are rendering,
+ * the {@link #repaintTimer} is regularly updating the {@link #finalImage}
+ * with previews.
+ */
+ public static final int REPEATING_REPAINT_DELAY = 500;
+
+ /**
+ * Default delay (milliseconds) before the map will be redrawn when resizing
+ * the pane. This is to avoid flickering while drag-resizing.
+ *
+ * @see #resizeTimer
+ */
+ public static final int DEFAULT_RESIZING_PAINT_DELAY = 600;
+
+ /**
+ * This not-repeating {@link Timer} is re-started whenever the component is
+ * resized. That means => only if the component is not resizing for
+ * {@link #DEFAULT_RESIZING_PAINT_DELAY} milliseconds, does the
+ * {@link XMapPane} react.
+ */
+ private final Timer resizeTimer;
+
+ /**
+ * Flag for no-tool.
+ */
+ public static final int NONE = -123;
+ //
+ // /**
+ // * Flag fuer Modus "Kartenausschnitt bewegen". Nicht fuer Window-Auswahl
+ // * moeglich!
+ // *
+ // * @see #setState(int)
+ // */
+ // public static final int PAN = 1;
+ //
+ // /**
+ // * Flag fuer Modus "Heran zoomen".
+ // *
+ // * @see #setState(int)
+ // * @see #setState(int)
+ // */
+ // public static final int ZOOM_IN = 2;
+ //
+ // /**
+ // * Flag fuer Modus "Heraus zoomen". Nicht fuer Window-Auswahl moeglich!
+ // *
+ // * @see #setState(int)
+ // */
+ // public static final int ZOOM_OUT = 3;
+
+ /**
+ * {@link Font} used to paint the wait messages into the map
+ *
+ * @see #addGadgets(Graphics2D, boolean)
+ */
+ final static Font waitFont = new Font("Arial", Font.BOLD, 28);
+
+ /**
+ * {@link Font} used to paint error messages into the map
+ *
+ * @see #addGadgets(Graphics2D, boolean)
+ */
+ final static Font errorFont = new Font("Arial", Font.BOLD, 13);
+
+ /**
+ * If last average last two renderings took more than that many ms, show the
+ * user a scaled preview
+ **/
+ private static final long PRESCALE_MINTIME = 230;
+
+ /**
+ * The wait message painted into the map while rendering is going on on
+ * another thread.
+ *
+ * @see #addGadgets(Graphics2D, boolean)
+ */
+ final String waitMsg = SwingUtil.R("WaitMess");
+
+ /**
+ * Konvertiert die Maus-Koordinaten (relativ zum <code>JMapPane</code>) in
+ * Karten-Koordinaten.
+ *
+ * @param e
+ * Maus-Ereignis
+ */
+ public static DirectPosition2D getMapCoordinatesFromEvent(final MouseEvent e) {
+ // aktuelle Geo-Position aus GeoMouseEvent ermitteln
+ if (e != null && e instanceof MapMouseEvent)
+ try {
+ return ((MapMouseEvent) e).getMapPosition();
+ } catch (final Exception err) {
+ LOGGER
+ .error(
+ "return ((GeoMouseEvent) e).getMapCoordinate(null).toPoint2D();",
+ err);
+ }
+
+ // aktuelle Geo-Position ueber Transformation des JMapPane berechnen
+ if (e != null && e.getSource() instanceof XMapPane) {
+
+ final XMapPane xMapPane = (XMapPane) e.getSource();
+
+ if (!xMapPane.isWellDefined())
+ return null;
+
+ final AffineTransform at = xMapPane.getScreenToWorld();
+ if (at != null) {
+ Point2D transformed = at.transform(e.getPoint(), null);
+ return new DirectPosition2D(xMapPane.getMapContext()
+ .getCoordinateReferenceSystem(), transformed.getX(),
+ transformed.getY());
+ }
+ return null;
+ }
+ throw new IllegalArgumentException(
+ "MouseEvent has to be of instance MapMouseEvent or come from an XMapPane");
+ }
+
+ /**
+ * Listens to changes of the "background" {@link MapContext} and triggers
+ * repaints where needed.
+ */
+ private final MapLayerListListener bgContextListener = new MapLayerListListener() {
+
+ @Override
+ public void layerAdded(final MapLayerListEvent event) {
+ final MapLayer layer = event.getLayer();
+ layer.addMapLayerListener(bgMapLayerListener);
+ requestStartRendering();
+ }
+
+ @Override
+ public void layerChanged(final MapLayerListEvent event) {
+ requestStartRendering();
+ }
+
+ @Override
+ public void layerMoved(final MapLayerListEvent event) {
+ requestStartRendering();
+ }
+
+ @Override
+ public void layerRemoved(final MapLayerListEvent event) {
+ if (event.getLayer() != null)
+ event.getLayer().removeMapLayerListener(bgMapLayerListener);
+ requestStartRendering();
+ }
+ };
+
+ /**
+ * This {@link RenderingExecutor} manages the creation and cancellation of
+ * up to one {@link Thread} for rendering the {@link #localContext}.
+ */
+ private final RenderingExecutor localExecuter = new RenderingExecutor(this);
+
+ /**
+ * This {@link RenderingExecutor} manages the creation and cancellation of
+ * up to one {@link Thread} for rendering the {@link #bgContext}.
+ */
+ protected RenderingExecutor bgExecuter;
+
+ /**
+ * The {@link #localRenderer} for the {@link #localContext} uses this
+ * {@link Image}.
+ */
+ private BufferedImage localImage;
+
+ /**
+ * The {@link #bgRenderer} for the {@link #bgContext} uses this
+ * {@link Image}.
+ */
+ private BufferedImage bgImage;
+
+ /**
+ * This {@link Image} is a merge of the {@link #bgImage},
+ * {@link #localImage} and {@link #addGadgets(Graphics2D, boolean)}. It is
+ * updated with {@link #updateFinalImage()} and used for painting in
+ * {@link #paintComponent(Graphics)}
+ */
+ private BufferedImage finalImage;
+
+ /**
+ * Optionally a transparent image to paint over the map in the lower right
+ * corner.
+ *
+ * @see #addGadgets(Graphics2D)
+ * @see #setMapImage(BufferedImage)
+ **/
+ private BufferedImage mapImage = null;
+
+ /**
+ * Listens to each layer in the local {@link MapContext} for changes and
+ * triggers repaints.
+ */
+ protected MapLayerListener bgMapLayerListener = new MapLayerAdapter() {
+
+ @Override
+ public void layerChanged(final MapLayerEvent event) {
+ requestStartRendering();
+ }
+
+ @Override
+ public void layerHidden(final MapLayerEvent event) {
+ requestStartRendering();
+ }
+
+ @Override
+ public void layerShown(final MapLayerEvent event) {
+ requestStartRendering();
+ }
+ };
+
+ /**
+ * A flag indicating if dispose() was already called. If true, then further
+ * use of this {@link SelectableXMapPane} is undefined.
+ */
+ private boolean disposed = false;
+
+ /**
+ * While dragging, the {@link #updateFinalImage()} method is translating the
+ * cached images while setting it together.
+ **/
+ private final Point imageOrigin = new Point(0, 0);
+ /**
+ * For every rendering thread started,
+ * {@link GTUtil#createGTRenderer(MapContext)} is called to create a new
+ * renderer. These Java2D rendering hints are passed to the
+ * {@link GTRenderer}. The java2dHints are the same for all renderers (bg
+ * and local).
+ */
+ private RenderingHints java2dHints;
+
+ protected LabelCache labelCache = new LabelCacheImpl();
+
+ /**
+ * Listens to changes of the "local" {@link MapContext} and triggers
+ * repaints where needed.
+ */
+ private final MapLayerListListener localContextListener = new MapLayerListListener() {
+
+ @Override
+ public void layerAdded(final MapLayerListEvent event) {
+ event.getLayer().addMapLayerListener(localMapLayerListener);
+
+ getLocalRenderer().setContext(getMapContext());
+ requestStartRendering();
+
+ }
+
+ @Override
+ public void layerChanged(final MapLayerListEvent event) {
+ // getLocalRenderer().setContext(getMapContext()); geht doch auch
+ // ohne?!?!? wow...
+ requestStartRendering();
+ }
+
+ @Override
+ public void layerMoved(final MapLayerListEvent event) {
+ getLocalRenderer().setContext(getMapContext());
+ requestStartRendering();
+ }
+
+ @Override
+ public void layerRemoved(final MapLayerListEvent event) {
+ if (event.getLayer() != null)
+ event.getLayer().removeMapLayerListener(localMapLayerListener);
+ getLocalRenderer().setContext(getMapContext());
+ requestStartRendering();
+ }
+ };
+
+ /**
+ * Listens to each layer in the local {@link MapContext} for changes and
+ * triggers repaints. We don't have to listen layerChanged, because that is
+ * already done in {@link #localContextListener}
+ */
+ protected MapLayerListener localMapLayerListener = new MapLayerAdapter() {
+
+ // @Override
+ // public void layerChanged(final MapLayerEvent event) {
+ // // getLocalRenderer().setContext(getMapContext()); // betters for SLD
+ // // // changes?!
+ // // requestStartRendering();
+ // }
+
+ @Override
+ public void layerHidden(final MapLayerEvent event) {
+ requestStartRendering();
+ }
+
+ @Override
+ public void layerShown(final MapLayerEvent event) {
+ requestStartRendering();
+ }
+ };
+
+ final private GTRenderer localRenderer = GTUtil.createGTRenderer();
+
+ private final GTRenderer bgRenderer = GTUtil.createGTRenderer();
+
+ /**
+ * the area of the map to draw
+ */
+ protected Envelope mapArea = null;
+
+ /**
+ * A flag set it {@link #setMapArea(Envelope)} to indicated the
+ * {@link #paintComponent(Graphics)} method, that the image on-screen is
+ * associated with {@link #oldMapArea} and may hence be scaled for a quick
+ * preview.<br>
+ * The flag is reset
+ **/
+ private boolean mapAreaChanged = false;
+
+ /**
+ * This color is used as the default background color when painting a map.
+ */
+ private Color mapBackgroundColor = null;
+
+ /**
+ * A flag indicating that the shown image is invalid and needs to be
+ * re-rendered.
+ */
+ protected boolean mapImageInvalid = true;
+
+ /**
+ * Holds a flag for each layer, whether it is regarded or ignored on
+ * {@link #SELECT_TOP}, {@link #SELECT_ALL} and {@link #SELECT_ONE_FROM_TOP}
+ * actions.
+ */
+ final protected HashMap<MapLayer, Boolean> mapLayerSelectable = new HashMap<MapLayer, Boolean>();
+
+ /**
+ * List of listeners of this {@link XMapPane}
+ */
+ protected Vector<JMapPaneListener> mapPaneListeners = new Vector<JMapPaneListener>();
+ /**
+ * If not <code>null</code>, the {@link XMapPane} will not allow to zoom/pan
+ * out of that area
+ **/
+ private Envelope maxExtend = null;
+ private Double maxZoomScale = Double.MIN_VALUE;
+
+ private Double minZoomScale = Double.MAX_VALUE;
+
+ /**
+ * We store the old mapArea for a moment to use it for the
+ * "quick scaled preview" in case of ZoomOut
+ **/
+ protected Envelope oldMapArea = null;
+
+ /**
+ * We store the old transform for a moment to use it for the
+ * "quick scaled preview" in case of ZoomIn
+ **/
+ protected AffineTransform oldScreenToWorld = null;
+
+ /**
+ * A flag indicating, that the image size has changed and the buffered
+ * images are not big enough any more
+ **/
+ protected boolean paneResized = true;
+
+ private BufferedImage preFinalImage;
+
+ // ** if 0, no quick preview will be shown **/
+ // private int quickPreviewHint = 0;
+
+ private Map<Object, Object> rendererHints = GTUtil
+ .getDefaultGTRendererHints(getLocalRenderer());
+
+ /**
+ * If set to <code>true</code>, the {@link #startRenderThreadsTimer} will
+ * start rendering {@link Thread}s
+ **/
+ private volatile Boolean requestStartRendering = false;
+
+ /**
+ * Transformation zwischen Fenster-Koordinaten und Karten-Koordinaten
+ * (lat/lon)
+ */
+ protected AffineTransform screenToWorld = null;
+
+ /**
+ * The flag {@link #requestStartRendering} can be set to true by events.
+ * This {@link Timer} checks the flag regularly and starts one renderer
+ * thread.
+ */
+ final private Timer startRenderThreadsTimer;
+ //
+ // /**
+ // * The default state is ZOOM_IN, hence by default the
+ // * {@link #xMapPaneMouseListener} is also enabled.
+ // **/
+ // private int state = ZOOM_IN;
+ //
+ // /**
+ // * Manuell gesetzter statischer Cursor, unabhaengig von der aktuellen
+ // * MapPane-Funktion
+ // */
+ // protected Cursor staticCursor = null;
+
+ private AffineTransform worldToScreen;
+
+ // /**
+ // * This {@link MouseListener} is managing all zoom related tasks
+ // */
+ // private final ZoomXMapPaneMouseListener zoomMapPaneMouseListener = new
+ // ZoomXMapPaneMouseListener(
+ // this);
+
+ /**
+ * This {@link MouseListener} is managing all zoom related tasks
+ */
+ private final XMapPaneMouseListener xMapPaneMouseListener = new XMapPaneMouseListener(
+ this);
+
+ /** Is set if a renderer has an error **/
+ protected ArrayList<Exception> renderingErrors = new ArrayList<Exception>();
+
+ /**
+ * If <code>true</code>, then rendering exceptions are rendererd into the
+ * map pane
+ **/
+ private boolean showExceptions = false;
+
+ public XMapPane() {
+ this(null, null);
+ }
+
+ /**
+ * full constructor extending JPanel
+ *
+ * @param rendererHints
+ * may be <code>null</code>. Otherwise a {@link Map<Object,
+ * Object>} of {@link RenderingHints} to override the default
+ * from {@link GTUtil#getDefaultGTRendererHints(GTRenderer)}
+ *
+ * @param localContext
+ * The main {@link MapContext} to use. If <code>null</code>, an
+ * empty {@link DefaultMapContext} will be created.
+ */
+ public XMapPane(final MapContext localContext_,
+ final Map<Object, Object> rendererHints) {
+
+ super(true);
+
+ stopBlinkTimer = initBlinkTimer();
+
+ // A default setting
+ RenderingHints hintsJava2d = ImageUtilities.NN_INTERPOLATION_HINT;
+ setJava2dHints(hintsJava2d);
+
+ setRendererHints(rendererHints);
+
+ setOpaque(true);
+
+ if (localContext_ != null)
+ setLocalContext(localContext_);
+
+ /**
+ * Adding the #zoomMapPaneMouseListener
+ */
+ this.addMouseListener(xMapPaneMouseListener);
+ this.addMouseMotionListener(xMapPaneMouseListener);
+ this.addMouseWheelListener(xMapPaneMouseListener);
+
+ // By default the XMapPAne uses the ZOOM_IN tool.
+ setTool(XMapPaneTool.ZOOM_IN);
+
+ /*
+ * We use a Timer object to avoid rendering delays and flickering when
+ * the user is drag-resizing the parent container of this map pane.
+ *
+ * Using a ComponentListener doesn't work because, unlike a JFrame, the
+ * pane receives a stream of events during drag-resizing.
+ */
+ resizeTimer = new Timer(DEFAULT_RESIZING_PAINT_DELAY,
+ new ActionListener() {
+
+ public void actionPerformed(final ActionEvent e) {
+ if (!isWellDefined())
+ return;
+
+ // LOGGER.debug("resizeTimer performed");
+
+ // final Rectangle bounds = getVisibleRect();
+ //
+ // System.out.println("\n\ntimer performs with bounds = "
+ // + bounds);
+
+ // final Envelope geoMapArea = tranformWindowToGeo(
+ // bounds.x, bounds.y, bounds.x + bounds.width,
+ // bounds.y + bounds.height);
+
+ paneResized = true;
+ if (!setMapArea(getMapArea())) {
+ // It's important to request new rendering here.
+ // setMapArea only returns true and only calls
+ // requestStartRendering if the maparea has changed.
+ // But if the component is resized, the maparea
+ // doesn't have to change.
+ requestStartRendering();
+ }
+
+ }
+ });
+ resizeTimer.setRepeats(false);
+
+ this.addComponentListener(new ComponentAdapter() {
+
+ private Rectangle oldVisibleRect;
+
+ @Override
+ public void componentResized(final ComponentEvent e) {
+
+ // Seems to be called twice with the same size..
+ if (oldVisibleRect != null
+ && oldVisibleRect.equals(getVisibleRect())) {
+ // LOGGER.debug("skipping resize.");
+ return;
+ }
+
+ // LOGGER.debug("resized: " + getVisibleRect());
+ resizeTimer.restart();
+ oldVisibleRect = getVisibleRect();
+ }
+
+ });
+
+ /*
+ * Setting up the repaintTimer. Not started automatically.
+ */
+ repaintTimer = new Timer(REPEATING_REPAINT_DELAY, new ActionListener() {
+
+ @Override
+ public void actionPerformed(final ActionEvent e) {
+ if ((!localExecuter.isRunning())
+ && (bgExecuter != null && !bgExecuter.isRunning())) {
+ repaintTimer.stop();
+ } else {
+ updateFinalImage();
+ XMapPane.this.repaint(100);
+
+ }
+ }
+ });
+
+ repaintTimer.setInitialDelay(INITIAL_REPAINT_DELAY);
+ repaintTimer.setRepeats(true);
+
+ /*
+ * Setting up the startRenderThreadsTimer. This Timer starts
+ * automatically.
+ */
+ startRenderThreadsTimer = new Timer(100, new ActionListener() {
+
+ @Override
+ public void actionPerformed(final ActionEvent e) {
+ synchronized (requestStartRendering) {
+ if (requestStartRendering && isWellDefined() && isEnabled()) {
+
+ if (localExecuter.isRunning()) {
+ localExecuter.cancelTask();
+ } else {
+ // Stupidly, but we have to recheck the
+ setMapArea(getMapArea());
+ requestStartRendering = false;
+ startRendering();
+ }
+ }
+ }
+ }
+ });
+ startRenderThreadsTimer.start();
+
+ }
+
+ /**
+ * Propagiert ein Ereignis an alle angeschlossenen Listener. Es gibt
+ * verschiedene implementationen von {@link XMapPaneEvent}
+ *
+ * @param e
+ * Ereignis
+ */
+ public void fireMapPaneEvent(XMapPaneEvent e) {
+ for (JMapPaneListener l : mapPaneListeners)
+ l.performMapPaneEvent(e);
+ }
+
+ /**
+ * Fuegt der Map einen Listener hinzu.
+ *
+ * @param l
+ * neuer Listener
+ */
+ public void addMapPaneListener(final JMapPaneListener l) {
+ mapPaneListeners.add(l);
+ }
+
+ /**
+ * Korrigiert den {@link Envelope} aka {@code mapArea} auf die beste
+ * erlaubte Flaeche damit die Massstabsbeschaenkungen noch eingehalten
+ * werden, FALLS der uebergeben Envelope nicht schon gueltig sein sollte.<br>
+ * Since 21. April 09: Before thecalculation starts, the aspect ratio is
+ * corrected. This change implies, that setMapArea() will most of the time
+ * not allow setting to a wrong aspectRatio.
+ *
+ * @author <a href="mailto:skpublic at wikisquare.de">Stefan Alfons
+ * Krüger</a>
+ */
+ public ReferencedEnvelope bestAllowedMapArea(ReferencedEnvelope env) {
+
+ if (getWidth() == 0)
+ return env;
+
+ if (env == null)
+ return null;
+
+ Envelope newArea = null;
+
+ /**
+ * Correct the aspect Ratio before we check the rest. Otherwise we might
+ * easily fail. We allow to grow here, because we don't check against
+ * the maxExtend
+ */
+ final Rectangle curPaintArea = getVisibleRect();
+
+ env = JTSUtil.fixAspectRatio(curPaintArea, env, true);
+
+ final double scale = env.getWidth() / getWidth();
+ final double centerX = env.getMinX() + env.getWidth() / 2.;
+ final double centerY = env.getMinY() + env.getHeight() / 2.;
+ double newWidth2 = 0;
+ double newHeight2 = 0;
+ if (scale < getMaxZoomScale()) {
+ // ****************************************************************************
+ // Wir zoomen weiter rein als erlaubt => Anpassen des envelope
+ // ****************************************************************************
+ newWidth2 = getMaxZoomScale() * getWidth() / 2.;
+ newHeight2 = getMaxZoomScale() * getHeight() / 2.;
+ } else if (scale > getMinZoomScale()) {
+ // ****************************************************************************
+ // Wir zoomen weiter raus als erlaubt => Anpassen des envelope
+ // ****************************************************************************
+ newWidth2 = getMinZoomScale() * getWidth() / 2.;
+ newHeight2 = getMinZoomScale() * getHeight() / 2.;
+ } else {
+ // ****************************************************************************
+ // Die mapArea / der Envelope ist ist gueltig! Keine Aenderungen
+ // ****************************************************************************
+ newArea = env;
+ }
+
+ if (newArea == null) {
+
+ final Coordinate ll = new Coordinate(centerX - newWidth2, centerY
+ - newHeight2);
+ final Coordinate ur = new Coordinate(centerX + newWidth2, centerY
+ + newHeight2);
+
+ newArea = new Envelope(ll, ur);
+ }
+
+ final Envelope maxAllowedExtend = getMaxExtend();
+
+ // This variable is used to break the loop if it runs forever...
+ Envelope lastCalculatedArea = null;
+ /*
+ * If a maxAllowedExtend is set, we have to honour that...
+ */
+ while (maxAllowedExtend != null && !maxAllowedExtend.contains(newArea)
+ && newArea != null && !newArea.isNull()
+ && !Double.isNaN(newArea.getMinX())
+ && !Double.isNaN(newArea.getMaxX())
+ && !Double.isNaN(newArea.getMinY())
+ && !Double.isNaN(newArea.getMaxY())) // Due to Double precision
+ // problems, this may
+ // iterate for ever
+ {
+
+ if (newArea.equals(lastCalculatedArea))
+ break;
+ // Check that we are not iterating for ever due to double precision
+ // rounding errors
+ lastCalculatedArea = newArea;
+
+ // Exceeds top? Move down and maybe cut
+ if (newArea.getMaxY() > maxAllowedExtend.getMaxY()) {
+ final double divY = newArea.getMaxY()
+ - maxAllowedExtend.getMaxY();
+ // LOGGER.debug("Moving area down by " + divY);
+
+ newArea = new Envelope(new Coordinate(newArea.getMinX(),
+ newArea.getMinY() - divY), new Coordinate(newArea
+ .getMaxX(), newArea.getMaxY() - divY));
+
+ if (newArea.getMinY() < maxAllowedExtend.getMinY()) {
+ // LOGGER.debug("Now it exeeds the bottom border.. cut!");
+ // And cut the bottom if it moved out of the area
+ newArea = new Envelope(new Coordinate(newArea.getMinX(),
+ maxAllowedExtend.getMinY()), new Coordinate(newArea
+ .getMaxX(), newArea.getMaxY()));
+
+ // LOGGER.debug("and fix aspect ratio");
+
+ newArea = JTSUtil.fixAspectRatio(getVisibleRect(),
+ new ReferencedEnvelope(newArea, env
+ .getCoordinateReferenceSystem()), false);
+ }
+ }
+
+ // Exceeds bottom? Move up and maybe cut
+ if (newArea.getMinY() < maxAllowedExtend.getMinY()) {
+ final double divY = newArea.getMinY()
+ - maxAllowedExtend.getMinY();
+ // LOGGER.debug("Moving area up by " + divY);
+
+ newArea = new Envelope(new Coordinate(newArea.getMinX(),
+ newArea.getMinY() - divY), new Coordinate(newArea
+ .getMaxX(), newArea.getMaxY() - divY));
+
+ if (newArea.getMaxY() > maxAllowedExtend.getMaxY()) {
+ // LOGGER.debug("Now it exeeds the top border.. cut!");
+ // And cut the bottom if it moved out of the area
+ newArea = new Envelope(new Coordinate(newArea.getMinX(),
+ newArea.getMinY()), new Coordinate(newArea
+ .getMaxX(), maxAllowedExtend.getMaxY()));
+
+ // LOGGER.debug("and fix aspect ratio");
+
+ newArea = JTSUtil.fixAspectRatio(getVisibleRect(),
+ new ReferencedEnvelope(newArea, env
+ .getCoordinateReferenceSystem()), false);
+ }
+ }
+
+ // Exceeds to the right? move and maybe cut
+ if (newArea.getMaxX() > maxAllowedExtend.getMaxX()) {
+
+ // Move left..
+ final double divX = newArea.getMaxX()
+ - maxAllowedExtend.getMaxX();
+ // LOGGER.debug("Moving area left by " + divX);
+
+ newArea = new Envelope(new Coordinate(newArea.getMinX() - divX,
+ newArea.getMinY()), new Coordinate(newArea.getMaxX()
+ - divX, newArea.getMaxY()));
+
+ if (newArea.getMinX() < maxAllowedExtend.getMinX()) {
+ // LOGGER.debug("Now it exeeds the left border.. cut!");
+ // And cut the left if it moved out of the area
+ newArea = new Envelope(new Coordinate(maxAllowedExtend
+ .getMinX(), newArea.getMinY()), new Coordinate(
+ newArea.getMaxX(), newArea.getMaxY()));
+
+ // LOGGER.debug("and fix aspect ratio");
+
+ newArea = JTSUtil.fixAspectRatio(getVisibleRect(),
+ new ReferencedEnvelope(newArea, env
+ .getCoordinateReferenceSystem()), false);
+ }
+ }
+
+ // Exceeds to the left? move and maybe cut
+ if (newArea.getMinX() < maxAllowedExtend.getMinX()) {
+
+ // Move right..
+ final double divX = newArea.getMinX()
+ - maxAllowedExtend.getMinX();
+ // LOGGER.debug("Moving area right by " + divX);
+
+ newArea = new Envelope(new Coordinate(newArea.getMinX() - divX,
+ newArea.getMinY()), new Coordinate(newArea.getMaxX()
+ - divX, newArea.getMaxY()));
+
+ if (newArea.getMaxX() > maxAllowedExtend.getMaxX()) {
+ // LOGGER.debug("Now it exeeds the right border.. cut!");
+ // And cut the left if it moved out of the area
+ newArea = new Envelope(new Coordinate(newArea.getMinX(),
+ newArea.getMinY()), new Coordinate(maxAllowedExtend
+ .getMaxX(), newArea.getMaxY()));
+
+ // LOGGER.debug("and fix aspect ratio");
+
+ newArea = JTSUtil.fixAspectRatio(getVisibleRect(),
+ new ReferencedEnvelope(newArea, env
+ .getCoordinateReferenceSystem()), false);
+ }
+ }
+
+ }
+
+ return new ReferencedEnvelope(newArea, env
+ .getCoordinateReferenceSystem());
+ }
+
+ /**
+ * Should be called when the {@link JMapPane} is not needed no more to help
+ * the GarbageCollector
+ *
+ * Removes all {@link JMapPaneListener}s that are registered
+ *
+ * @author <a href="mailto:skpublic at wikisquare.de">Stefan Alfons
+ * Krüger</a>
+ */
+ public void dispose() {
+ if (isDisposed())
+ return;
+
+ setPainting(false);
+
+ resizeTimer.stop();
+ startRenderThreadsTimer.stop();
+
+ disposed = true;
+
+ if (bgExecuter != null) {
+ bgExecuter.cancelTask();
+ bgExecuter.dispose();
+ }
+
+ if (localExecuter.isRunning()) {
+ int i = 0;
+ localExecuter.cancelTask();
+ while (i++ < 10 && localExecuter.isRunning()) {
+ try {
+ Thread.sleep(200);
+ } catch (final InterruptedException e) {
+ LOGGER
+ .warn(
+ "while XMapPane we are waiting for the localExcutor to stop",
+ e);
+ }
+ }
+ if (localExecuter.isRunning()) {
+ LOGGER
+ .warn("localExecutor Thread still running after 2s! Continuing anyways...");
+ }
+ localExecuter.dispose();
+ }
+
+ disposeImages();
+
+ // Remove all mapPaneListeners that have registered with us
+ mapPaneListeners.clear();
+
+ removeMouseMotionListener(xMapPaneMouseListener);
+ removeMouseListener(xMapPaneMouseListener);
+
+ if (localContext != null)
+ getMapContext().clearLayerList();
+ if (bgContext != null)
+ getBgContext().clearLayerList();
+
+ removeAll();
+ }
+
+ /**
+ * Draws a rectangle in XOR mode from the origin at {@link #startPos} to the
+ * given point. All in screen coordinates.
+ */
+ protected void drawRectangle(final Graphics graphics, final Point startPos,
+ final Point e) {
+ drawRectangle(graphics, startPos, e, Color.WHITE, false);
+ }
+
+ /**
+ * Draws a rectangle in XOR mode from the origin at {@link #startPos} to the
+ * given point. All in screen coordinates.
+ */
+ protected void drawRectangle(final Graphics graphics, final Point startPos,
+ final Point e, Color color, boolean fill) {
+
+ if (!isWellDefined())
+ return;
+
+ // undraw last box/draw new box
+ final int left = Math.min(startPos.x, e.x);
+ final int right = Math.max(startPos.x, e.x);
+ final int top = Math.max(startPos.y, e.y);
+ final int bottom = Math.min(startPos.y, e.y);
+ final int width = right - left;
+ final int height = top - bottom;
+
+ if (width == 0 && height == 0)
+ return;
+
+ graphics.setXORMode(color);
+
+ if (fill) {
+ graphics.fillRect(left, bottom, width, height);
+ graphics.setXORMode(Color.WHITE);
+ }
+
+ graphics.drawRect(left, bottom, width, height);
+ }
+
+ /**
+ * Diretly paints scaled preview into the {@link SelectableXMapPane}. Used
+ * to give the user something to look at while we are rendering. Method
+ * should be called after {@link #setMapArea(Envelope)} has been set to the
+ * new mapArea and transform has been reset.<br>
+ *
+ * @param g
+ * Graphics2D to paint the preview into
+ */
+ protected boolean drawScaledPreviewImage_Zoom(final Graphics2D graphics) {
+
+ // if (1 == 1)return false;
+ // if (quickPreviewHint == 0)
+ // return false;
+
+ if (oldMapArea == null)
+ return false;
+
+ if (getPreFinalImage() == null)
+ return false;
+
+ final Rectangle visibleArea = getVisibleRect();
+
+ // Calculate the oldMapArea in the current WindowCoordinates:
+ final Envelope oldMapWindow = tranformGeoToWindow(oldMapArea.getMinX(),
+ oldMapArea.getMinY(), oldMapArea.getMaxX(), oldMapArea
+ .getMaxY());
+
+ final int xx1 = (int) Math.round(oldMapWindow.getMinX());
+ final int yy1 = (int) Math.round(oldMapWindow.getMinY());
+ final int xx2 = (int) Math.round(oldMapWindow.getMaxX());
+ final int yy2 = (int) Math.round(oldMapWindow.getMaxY());
+
+ graphics.setRenderingHint(RenderingHints.KEY_INTERPOLATION,
+ RenderingHints.VALUE_INTERPOLATION_NEAREST_NEIGHBOR);
+ graphics.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
+ RenderingHints.VALUE_ANTIALIAS_OFF);
+ graphics.setRenderingHint(RenderingHints.KEY_RENDERING,
+ RenderingHints.VALUE_RENDER_SPEED);
+
+ graphics.drawImage(getPreFinalImage(), xx1, yy1, xx2, yy2,
+ (int) visibleArea.getMinX(), (int) visibleArea.getMinY(),
+ (int) visibleArea.getMaxX(), (int) visibleArea.getMaxY(),
+ getMapBackgroundColor(), null);
+
+ final Rectangle painedArea = new Rectangle(xx1, yy1, xx2 - xx1, yy2
+ - yy1);
+
+ SwingUtil.clearAround(graphics, painedArea, visibleArea,
+ getMapBackgroundColor());
+
+ addGadgets(graphics, true);
+
+ // quickPreviewHint = 0;
+
+ repaintTimer.restart();
+
+ // Something has been drawn
+ return true;
+ }
+
+ public MapContext getBgContext() {
+ return bgContext;
+ }
+
+ /**
+ * Lazyly initializes a {@link BufferedImage} for the background renderer.
+ */
+ private Image getBgImage() {
+ if (bgImage == null) {
+ bgImage = new BufferedImage(getVisibleRect().width,
+ getVisibleRect().height, IMAGETYPE);
+ SwingUtil.clearImage(finalImage, getMapBackgroundColor());
+ }
+
+ return bgImage;
+ }
+
+ public MapContext getMapContext() {
+ if (localContext == null) {
+ setLocalContext(new DefaultMapContext());
+ }
+ return localContext;
+ }
+
+ private BufferedImage getFinalImage() {
+ //
+ if (finalImage == null) {
+ // Rectangle curPaintArea = getVisibleRect();
+ finalImage = new BufferedImage(getVisibleRect().width,
+ getVisibleRect().height, IMAGETYPE);
+ SwingUtil.clearImage(finalImage, getMapBackgroundColor());
+
+ // requestStartRendering();
+ }
+ return finalImage;
+ }
+
+ /**
+ * Lazyly initializes a {@link BufferedImage} for the background renderer.
+ */
+ private BufferedImage getLocalImage() {
+
+ if (localImage == null) {
+ localImage = new BufferedImage(getVisibleRect().width,
+ getVisibleRect().height, IMAGETYPE_withAlpha);
+ SwingUtil.clearImage(localImage, getMapBackgroundColor());
+ }
+
+ return localImage;
+ }
+
+ /**
+ * Returns a copy of the mapArea
+ *
+ * @return
+ */
+ public ReferencedEnvelope getMapArea() {
+ if (mapArea == null) {
+ ReferencedEnvelope mapArea_ = null;
+ try {
+ mapArea_ = localContext.getLayerBounds();
+ } catch (final Exception e) {
+ LOGGER.warn("localContext.getLayerBounds()", e);
+ }
+
+ if (mapArea_ == null && bgContext != null) {
+ try {
+ mapArea_ = bgContext.getLayerBounds();
+ } catch (final IOException e) {
+ LOGGER.warn("bgContext.getLayerBounds()", e);
+ }
+ }
+
+ if (mapArea_ != null) {
+ mapArea = bestAllowedMapArea(mapArea_);
+ requestStartRendering();
+ }
+ }
+
+ if (mapArea == null)
+ return null;
+
+ // TODO is needed at all, this should go to setMapArea maybe
+ if (localContext.getCoordinateReferenceSystem() == null)
+ try {
+ localContext.setCoordinateReferenceSystem(GeoImportUtil
+ .getDefaultCRS());
+ } catch (final Exception e) {
+ throw new RuntimeException("setting context CRS:", e);
+ }
+
+ return new ReferencedEnvelope(mapArea, localContext
+ .getCoordinateReferenceSystem());
+ }
+
+ /**
+ * Returns the background {@link Color} of the map pane. If not set, the
+ * methods looks for a parent component and will use its background color.
+ * If no parent component is available, WHITE is returned.
+ **/
+ public Color getMapBackgroundColor() {
+ if (mapBackgroundColor == null) {
+ if (getParent() != null)
+ return getParent().getBackground();
+ else
+ return Color.WHITE;
+ }
+ return mapBackgroundColor;
+ }
+
+ /**
+ * Get the BufferedImage to use as a flaoting icon in the lower right
+ * corner.
+ *
+ * @return <code>null</code> if the feature is deactivated.
+ */
+ public BufferedImage getMapImage() {
+ return mapImage;
+ }
+
+ /**
+ * Returns the evelope of the viewable area. The JMapPane will never show
+ * anything outside of this extend. If this has been set to
+ * <code>null</code> via {@link #setMaxExtend(Envelope)}, it tries to return
+ * quickly the context's bounds. It it takes to long to determine the
+ * context bounds, <code>null</code> is returned.
+ *
+ * @param maxExtend
+ * <code>null</code> to not have this restriction.
+ */
+
+ public Envelope getMaxExtend() {
+ if (maxExtend == null) {
+
+ // The next command may take long time!
+ // long start = System.currentTimeMillis();
+ final ReferencedEnvelope layerBounds = getVisibleLayoutBounds(localContext);
+ //
+ // LOGGER.info(
+ // (System.currentTimeMillis()-start)+"m to get maxExtend");
+ //
+ if (layerBounds == null) {
+ // // TODO Last fallback could be the CRS valid area
+ return null;
+ }
+
+ return JTSUtil.fixAspectRatio(getVisibleRect(),
+ addDefaultMargin(layerBounds), true);
+
+ }
+ return maxExtend;
+ }
+
+ public static final String SPECIAL_LINES_LAYER_ID = "SPECIAL_LINES_LAYER_ID";
+
+ /**
+ * This method ignores sepcial layers like {@link #SPECIAL_LINES_LAYER_ID}
+ */
+ protected ReferencedEnvelope getVisibleLayoutBounds(MapContext context) {
+ ReferencedEnvelope result = null;
+ CoordinateReferenceSystem crs = context.getAreaOfInterest()
+ .getCoordinateReferenceSystem();
+
+ final int length = context.getLayerCount();
+ MapLayer layer;
+ FeatureSource<SimpleFeatureType, SimpleFeature> fs;
+ ReferencedEnvelope env;
+ CoordinateReferenceSystem sourceCrs;
+
+ for (int i = 0; i < length; i++) {
+ layer = context.getLayer(i);
+
+ if (!layer.isVisible())
+ continue;
+
+
+ if (layer.getTitle().equals(SPECIAL_LINES_LAYER_ID))
+ continue;
+ /*
+ * fs = layer.getFeatureSource(); sourceCrs =
+ * fs.getSchema().getDefaultGeometry() .getCoordinateSystem(); env =
+ * new ReferencedEnvelope(fs.getBounds(), sourceCrs);
+ */
+
+ env = layer.getBounds();
+ if (env == null) {
+ continue;
+ } else {
+ try {
+ sourceCrs = env.getCoordinateReferenceSystem();
+ if ((sourceCrs != null) && crs != null
+ && !CRS.equalsIgnoreMetadata(sourceCrs, crs)) {
+ env = env.transform(crs, true);
+ }
+
+ } catch (FactoryException e) {
+ LOGGER
+ .warn(
+ "Data source and map context coordinate system differ, yet it was not possible to get a projected bounds estimate...",
+ e);
+ } catch (TransformException e) {
+ LOGGER
+ .warn(
+ "Data source and map context coordinate system differ, yet it was not possible to get a projected bounds estimate...",
+ e);
+ }
+
+ if (result == null) {
+ result = env;
+ } else {
+ result.expandToInclude(env);
+ }
+ }
+ }
+
+ return result;
+
+ }
+
+ /**
+ * Retuns the maximum allowed zoom scale. This is the smaller number value
+ * of the two. Defaults to {@link Double}.MIN_VALUE
+ *
+ * @author <a href="mailto:skpublic at wikisquare.de">Stefan Alfons
+ * Krüger</a>
+ */
+ public Double getMaxZoomScale() {
+ return maxZoomScale;
+ }
+
+ /**
+ * Retuns the minimum allowed zoom scale. This is the bigger number value of
+ * the two. Defaults to {@link Double}.MAX_VALUE
+ *
+ * @author <a href="mailto:skpublic at wikisquare.de">Stefan Alfons
+ * Krüger</a>
+ */
+ public Double getMinZoomScale() {
+ return minZoomScale;
+ }
+
+ private Image getPreFinalImage() {
+ return preFinalImage;
+ }
+
+ public Map<Object, Object> getRendererHints() {
+ // Clear label cache
+ labelCache.clear();
+ rendererHints.put(StreamingRenderer.LABEL_CACHE_KEY, labelCache);
+
+ return rendererHints;
+ }
+
+ /**
+ * Liefert eine affine Transformation, um von den Fenster-Koordinaten in die
+ * Karten-Koordinaten (Lat/Lon) umzurechnen.
+ *
+ * @return eine Kopie der aktuellen Transformation; <code>null</code> wenn
+ * noch keine Karte angezeigt wird
+ */
+ public AffineTransform getScreenToWorld() {
+ if (screenToWorld == null)
+ resetTransforms();
+ // nur Kopie der Transformation zurueckgeben!
+ if (screenToWorld == null)
+ return null;
+ return new AffineTransform(screenToWorld);
+ }
+
+ // public int getState() {
+ // return state;
+ // }
+ //
+ // /**
+ // * Liefert den statisch eingestellten Cursor, der unabhaengig von der
+ // * eingestellten MapPane-Aktion (Zoom, Auswahl, ...) verwendet wird.
+ // *
+ // * @return {@code null}, wenn kein statischer Cursor verwendet, sondern
+ // der
+ // * Cursor automatisch je nach MapPane-Aktion eingestellt wird.
+ // */
+ // public Cursor getStaticCursor() {
+ // return this.staticCursor;
+ // }
+
+ public AffineTransform getWorldToScreenTransform() {
+ if (worldToScreen == null) {
+ resetTransforms();
+ }
+ // nur Kopie der Transformation zurueckgeben!
+ return new AffineTransform(worldToScreen);
+ }
+
+ /**
+ * A flag indicating if dispose() has already been called. If true, then
+ * further use of this {@link SelectableXMapPane} is undefined.
+ */
+ private boolean isDisposed() {
+ return disposed;
+ }
+
+ /**
+ * Returns whether a layer is regarded or ignored on {@link #SELECT_TOP},
+ * {@link #SELECT_ALL} and {@link #SELECT_ONE_FROM_TOP} actions. Returns
+ * <code>true</code> if the selectability has not been defined.
+ *
+ * @param layer
+ * a layer
+ */
+ public boolean isMapLayerSelectable(final MapLayer layer) {
+ final Boolean selectable = mapLayerSelectable.get(layer);
+ return selectable == null ? true : selectable;
+ }
+
+ /**
+ * Return <code>true</code> if a CRS and a {@link #mapArea} are set and the
+ * {@link XMapPane} is visible and has bounds set.
+ */
+ public boolean isWellDefined() {
+ try {
+ if (getMapContext() == null)
+ return false;
+ if (getMapContext().getLayerCount() <= 0)
+ return false;
+ if (getVisibleRect().getWidth() == 0)
+ return false;
+ if (getVisibleRect().getHeight() == 0)
+ return false;
+ // if (getMapArea() == null)
+ // return false;
+ } catch (final Exception e) {
+ return false;
+ }
+ return true;
+ }
+
+ /**
+ * Usually called from {@link XMapPaneAction_Pan} to pan the image.
+ *
+ * @param startPos
+ * in screen coordinates
+ * @param lastPos
+ * in screen coordinates
+ */
+ public void pan(final int dX, final int dY) {
+
+ // Panning needs a panning coursor
+ if (getCursor() != SwingUtil.PANNING_CURSOR) {
+ setCursor(SwingUtil.PANNING_CURSOR);
+
+ // While panning, we deactivate the rendering. So the tasks are
+ // ready to start when the panning is finished.
+ if (bgExecuter != null && bgExecuter.isRunning())
+ bgExecuter.cancelTask();
+ if (localExecuter.isRunning())
+ localExecuter.cancelTask();
+ }
+ //
+ // if (lastPos.x > 0 && lastPos.y > 0) {
+ // final int dx = event.getX() - lastPos.x;
+ // final int dy = event.getY() - lastPos.y;
+
+ // TODO Stop dragging when the drag would not be valid...
+ // boolean dragValid = true;
+ // // check if this panning results in a valid mapArea
+ // {
+ // Rectangle winBounds = xMapPane.getBounds();
+ // winBounds.translate(xMapPane.imageOrigin.x,
+ // -xMapPane.imageOrigin.y);
+ // Envelope newMapAreaBefore = xMapPane.tranformWindowToGeo(
+ // winBounds.x, winBounds.y, winBounds.x
+ // + winBounds.width, winBounds.y
+ // + winBounds.height);
+ //
+ //
+ // winBounds = xMapPane.getBounds();
+ // Point testIng = new Point(xMapPane.imageOrigin);
+ // testIng.translate(dx, dy);
+ // winBounds.translate(testIng.x, -testIng.y);
+ // Envelope newMapAreaAfter = xMapPane.tranformWindowToGeo(
+ // winBounds.x, winBounds.y, winBounds.x
+ // + winBounds.width, winBounds.y
+ // + winBounds.height);
+ //
+ // // If the last drag doesn't change the MapArea anymore cancel
+ // it.
+ // if (xMapPane.bestAllowedMapArea(newMapAreaAfter).equals(
+ // xMapPane.bestAllowedMapArea(newMapAreaBefore))){
+ // dragValid = false;
+ // return;
+ // }
+ // }
+
+ getImageOrigin().translate(dX, dY);
+ updateFinalImage();
+ repaint();
+ // }
+
+ // } else if ((getState() == XMapPane.ZOOM_IN)
+ // || (getState() == XMapPane.ZOOM_OUT)
+ // || (getState() == XMapPane.SELECT_ALL)
+ // || (getState() == XMapPane.SELECT_TOP)) {
+ //
+ // // Draws a rectangle
+ // final Graphics2D graphics = (Graphics2D) getGraphics();
+ // drawRectangle(graphics, startPos, event.getPoint());
+ // if ((lastPos.x > 0) && (lastPos.y > 0))
+ // drawRectangle(graphics, startPos, lastPos);
+ // graphics.dispose();
+ // }
+ }
+
+ /**
+ * Called by the {@link RenderingExecutor} when rendering was cancelled.
+ */
+ public void onRenderingCancelled() {
+ // LOGGER.debug("Rendering cancelled");
+ repaintTimer.stop();
+
+ // Inform listeners that rendering has completed if have no requests to
+ // start again
+ if (!requestStartRendering)
+ fireMapPaneEvent(new MapRenderingStateEvent(this,
+ RenderingState.ON_HOLD));
+ }
+
+ /**
+ * Called by the {@link RenderingExecutor} when rendering has been
+ * completed.
+ *
+ * @param l
+ * long ms the rendering took
+ */
+ public void onRenderingCompleted(final long l) {
+ lastRenderingDuration = (lastRenderingDuration + l) / 2;
+ // LOGGER
+ // .debug("complete rendering after " + lastRenderingDuration
+ // + "ms");
+
+ repaintTimer.stop();
+
+ // We "forget" about an exception every time we complete a rendering
+ // thread successfully
+ if (renderingErrors.size() > 0)
+ renderingErrors.remove(0);
+
+ updateFinalImage();
+ repaint();
+
+ // Inform listeners that rendering has completed if have no requests to
+ // start again
+ if (!requestStartRendering)
+ fireMapPaneEvent(new MapRenderingStateEvent(this,
+ RenderingState.ON_HOLD));
+ }
+
+ /**
+ * Called by the {@linkplain XMapPane.RenderingTask} when rendering failed.
+ * Publishes a {@linkplain XMapPaneEvent} of type {@code
+ * MapPaneEvent.Type.RENDERING_STOPPED} to listeners.
+ *
+ * @param renderingError
+ * The error that occured during rendering
+ *
+ * @see MapPaneListener#onRenderingStopped(org.geotools.swing.event.MapPaneEvent)
+ */
+ public void onRenderingFailed(final Exception renderingError) {
+
+ // Store the exceptions so we can show it to the user:
+ if (!(renderingError instanceof java.lang.IllegalArgumentException && renderingError
+ .getMessage().equals(
+ "Argument \"sourceCRS\" should not be null.")))
+ this.renderingErrors.add(renderingError);
+ if (renderingErrors.size() > 3)
+ renderingErrors.remove(0);
+
+ repaintTimer.stop();
+
+ LOGGER.warn("Rendering failed", renderingError);
+ updateFinalImage();
+ repaint();
+
+ // Inform listeners that rendering has completed if have no requests to
+ // start again
+ if (!requestStartRendering)
+ fireMapPaneEvent(new MapRenderingStateEvent(this,
+ RenderingState.ON_HOLD));
+ }
+
+ @Override
+ protected void paintComponent(final Graphics g) {
+
+ // Maybe update the cursor and maybe stop the repainting timer
+ updateCursor();
+
+ if (!acceptsRepaintCalls)
+ return;
+
+ if (!isWellDefined())
+ return;
+ //
+ // if (paneResized) {
+ // // ((Graphics2D) g).setBackground(getMapBackgroundColor());
+ // // g.clearRect(0, 0, getVisibleRect().width,
+ // getVisibleRect().height);
+ // return;
+ // }
+
+ // super.paintComponent(g); // candidate for removal
+
+ boolean paintedSomething = false;
+
+ if (mapImageInvalid) { /* if the map changed then redraw */
+
+ mapImageInvalid = false; // Reset for next round
+
+ // If the new mapArea and the oldMapArea intersect, we can draw some
+ // quick scaled preview to make the user feel that something is
+ // happening.
+ if (lastRenderingDuration > PRESCALE_MINTIME && mapAreaChanged
+ && oldMapArea != null
+ && getMapArea().intersects(oldMapArea)
+ && !getMapArea().equals(oldMapArea) && !paneResized) {
+
+ mapAreaChanged = false;
+
+ // if (getMapArea().covers(oldMapArea)) {
+ // // quickPreviewHint = ZOOM_OUT;
+ // paintedSomething = drawScaledPreviewImage_Zoom((Graphics2D)
+ // g);
+ // } else if (oldMapArea.covers(getMapArea())) {
+ // quickPreviewHint = ZOOM_IN;
+ paintedSomething = drawScaledPreviewImage_Zoom((Graphics2D) g);
+ // }
+ }
+ }
+
+ if (!paintedSomething) {
+
+ g.drawImage(getFinalImage(), 0, 0, null);
+
+ blink((Graphics2D) g);
+
+ paintedSomething = true; // cand. for removal
+ }
+
+ }
+
+ /**
+ * If {@link #blinkRenderer} is not <code>null</code>, the blinking features
+ * are rendered into the {@link Graphics2D}
+ */
+ private void blink(Graphics2D g2d) {
+ if (blinkRenderer != null) {
+ g2d.translate(getImageOrigin().x, getImageOrigin().y);
+ blinkRenderer.paint(g2d, getVisibleRect(), getMapArea());
+ }
+ }
+
+ /**
+ * Heavily works on releasing all resources related to the four
+ * {@link Image}s used to cache the results of the different renderers.<br>
+ * In November 2009 i had some memory leaking problems with {@link XMapPane}
+ * . The resources of the buffered images were never released. It seem to be
+ * important to call the GC right after flushing the images.<br>
+ * Hence this method may take a while, because it calls the GC up to four
+ * times.
+ */
+ private void disposeImages() {
+
+ // System.out.println("vorher = "
+ // + new MbDecimalFormatter().format(LangUtil.gcTotal()));
+ // bi.flush();
+ // return bi = null;
+ // System.out.println("nacher = "
+ // + new MbDecimalFormatter().format(LangUtil.gcTotal()));
+ //
+ // System.out.println("\n");
+
+ if (preFinalImage != null) {
+ preFinalImage.flush();
+ preFinalImage = null;
+ LangUtil.gc();
+ }
+ if (finalImage != null) {
+ finalImage.flush();
+ finalImage = null;
+ LangUtil.gc();
+ }
+ if (localImage != null) {
+ localImage.flush();
+ localImage = null;
+ LangUtil.gc();
+ }
+ if (bgImage != null) {
+ bgImage.flush();
+ bgImage = null;
+ LangUtil.gc();
+ }
+
+ }
+
+ //
+ // /**
+ // * Performs a {@value #PAN} action. During panning, the displacement is
+ // * stored in {@link #imageOrigin} object. Calling {@link #performPan()}
+ // will
+ // * reset the offset and call {@link #setMapArea(Envelope)}.
+ // */
+ // public void performPan() {
+ //
+ // final Rectangle winBounds = getVisibleRect();
+ //
+ // winBounds.translate(-imageOrigin.x, -imageOrigin.y);
+ // final Envelope newMapArea = tranformWindowToGeo(winBounds.x,
+ // winBounds.y, winBounds.x + winBounds.width, winBounds.y
+ // + winBounds.height);
+ //
+ // imageOrigin.x = 0;
+ // imageOrigin.y = 0;
+ //
+ // if (!setMapArea(newMapArea)) {
+ // /**
+ // * If setMapArea returns true, the finalImage is updated anyways.
+ // * This if-case exists to ensure that we repaint a correct image
+ // * even if the new panning area has been denied.
+ // */
+ // updateFinalImage();
+ // repaint();
+ // }
+ //
+ // if (getCursor() == SwingUtil.PANNING_CURSOR)
+ // setCursor(SwingUtil.PAN_CURSOR);
+ // }
+
+ /**
+ * Entfernt einen Listener von der Map.
+ *
+ * @param l
+ * zu entfernender Listener
+ */
+ public void removeMapPaneListener(final JMapPaneListener l) {
+ mapPaneListeners.remove(l);
+ }
+
+ /**
+ * Cancels all running renderers and sets the flag to start new ones. <br>
+ *
+ * @see #startRenderThreadsTimer
+ */
+ private void requestStartRendering() {
+ if (bgExecuter != null)
+ bgExecuter.cancelTask();
+
+ localExecuter.cancelTask();
+
+ mapImageInvalid = true;
+ if (paneResized) {
+ paneResized = false;
+ disposeImages();
+ }
+ requestStartRendering = true;
+
+ }
+
+ /**
+ * Calculate the affine transforms used to convert between world and pixel
+ * coordinates. The calculations here are very basic and assume a cartesian
+ * reference system.
+ * <p>
+ * Tne transform is calculated such that {@code envelope} will be centred in
+ * the display
+ *
+ * @param envelope
+ * the current map extent (world coordinates)
+ * @param paintArea
+ * the current map pane extent (screen units)
+ */
+ private void resetTransforms() {
+ // System.out
+ // .println("paintArea in resetTeansofrms = " + getVisibleRect());
+ if (!isWellDefined())
+ return;
+
+ if (mapArea == null)
+ return;
+
+ final ReferencedEnvelope refMapEnv = new ReferencedEnvelope(mapArea,
+ getMapContext().getCoordinateReferenceSystem());
+
+ worldToScreen = RendererUtilities.worldToScreenTransform(refMapEnv,
+ getVisibleRect());
+
+ try {
+ screenToWorld = worldToScreen.createInverse();
+
+ } catch (final NoninvertibleTransformException ex) {
+ LOGGER
+ .error("can't invert worldToScreen to get screenToWorld!",
+ ex);
+ }
+ }
+
+ public void setBgContext(final MapContext context) {
+
+ // Remove the default listener from the old context
+ if (this.bgContext != null) {
+ this.bgContext.removeMapLayerListListener(bgContextListener);
+
+ // adding listener to all layers
+ for (final MapLayer mapLayer : bgContext.getLayers()) {
+ mapLayer.removeMapLayerListener(bgMapLayerListener);
+ }
+ }
+
+ this.bgContext = context;
+
+ if (context != null) {
+ // setMapArea(bgContext.getAreaOfInterest());
+
+ this.bgContext.addMapLayerListListener(bgContextListener);
+
+ // adding listener to all layers
+ for (final MapLayer mapLayer : bgContext.getLayers()) {
+ mapLayer.addMapLayerListener(bgMapLayerListener);
+ }
+ }
+
+ requestStartRendering();
+ }
+
+ public void setJava2dHints(final RenderingHints java2dHints) {
+ this.java2dHints = java2dHints;
+ }
+
+ public void setLocalContext(final MapContext context) {
+ // Remove the default listener from the old context
+ if (this.localContext != null) {
+ this.localContext.removeMapLayerListListener(localContextListener);
+
+ // adding listener to all layers
+ for (final MapLayer mapLayer : localContext.getLayers()) {
+ mapLayer.removeMapLayerListener(localMapLayerListener);
+ }
+ }
+
+ this.localContext = context;
+
+ if (context != null) {
+
+ // setMapArea(localContext.getAreaOfInterest());
+
+ getLocalRenderer().setContext(localContext);
+
+ this.localContext.addMapLayerListListener(localContextListener);
+
+ // adding listener to all layers
+ for (final MapLayer mapLayer : localContext.getLayers()) {
+ mapLayer.addMapLayerListener(localMapLayerListener);
+ }
+ }
+
+ requestStartRendering();
+
+ }
+
+ public void setBorder(final Border b) {
+ super.setBorder(b);
+ }
+
+ /**
+ * Triggers to repaint (fast) and re-render (slow) the JMapPane.
+ */
+ public void refresh() {
+ mapImageInvalid = true;
+ repaint();
+ }
+
+ // /**
+ // * Triggers to use new {@link GTRenderer} and refresh the map. Should be
+ // * called after {@link Style}s have been changed because GTRenderer is
+ // * otherwise not working well.
+ // */
+ // public void refreshRenderers() {
+ // localRenderer = GTUtil.createGTRenderer();
+ // setLocalContext(getMapContext());
+ // mapImageInvalid = true;
+ // repaint();
+ // }
+
+ /**
+ * Set the new map area.
+ *
+ * @param newMapArea
+ * @return <code>true</code> if the mapArea has been changed and a repaint
+ * has been triggered.
+ */
+ public boolean setMapArea(final Envelope newMapArea) {
+ if (newMapArea == null)
+ return false;
+ if (getMapContext().getCoordinateReferenceSystem() == null)
+ return false;
+ return setMapArea(new ReferencedEnvelope(newMapArea, getMapContext()
+ .getCoordinateReferenceSystem()));
+ }
+
+ /**
+ * Set the new map area.
+ *
+ * @param newMapArea
+ * @return <code>true</code> if the mapArea has been changed and a repaint
+ * has been triggered.
+ */
+ public boolean setMapArea(final ReferencedEnvelope newMapArea) {
+
+ if (newMapArea == null
+ || bestAllowedMapArea(newMapArea).equals(mapArea)) {
+ // No change.. no need to repaint
+ return false;
+ }
+
+ // Testing, whether NaN or Infinity are used in the newMapArea
+ if (newMapArea.isNull() || Double.isInfinite(newMapArea.getMaxX())
+ || Double.isInfinite(newMapArea.getMaxY())
+ || Double.isInfinite(newMapArea.getMinX())
+ || Double.isInfinite(newMapArea.getMinY())) {
+ // No change.. ugly new values
+ LOGGER.warn("setMapArea has been called with newArea = "
+ + newMapArea);
+ return false;
+ }
+
+ final Envelope candNew = bestAllowedMapArea(newMapArea);
+
+ // Testing, whether the difference if just minimal
+ if (mapArea != null) {
+ final double tolX = mapArea.getWidth() / 1000.;
+ final double tolY = mapArea.getHeight() / 1000.;
+ if ((candNew.getMinX() - tolX < mapArea.getMinX())
+ && (mapArea.getMinX() < candNew.getMinX() + tolX)
+ && (candNew.getMaxX() - tolX < mapArea.getMaxX())
+ && (mapArea.getMaxX() < candNew.getMaxX() + tolX)
+
+ && (candNew.getMinY() - tolY < mapArea.getMinY())
+ && (mapArea.getMinY() < candNew.getMinY() + tolY)
+ && (candNew.getMaxY() - tolY < mapArea.getMaxY())
+ && (mapArea.getMaxY() < candNew.getMaxY() + tolY)
+
+ ) {
+ // The two mapAreas only differ my 1/1000th.. ignore
+
+ return false;
+ }
+ }
+
+ // New map are is accepted:
+ oldMapArea = mapArea;
+ mapArea = candNew;
+ resetTransforms();
+
+ if (localContext != null) {
+ localContext.setAreaOfInterest(mapArea, localContext
+ .getCoordinateReferenceSystem());
+ }
+ if (bgContext != null) {
+ bgContext.setAreaOfInterest(mapArea, localContext
+ .getCoordinateReferenceSystem());
+ }
+
+ mapAreaChanged = true;
+
+ repaint(200); // Do not remove it!
+
+ requestStartRendering();
+
+ return true;
+ }
+
+ /**
+ * Set the background color of the map.
+ *
+ * @param if <code>null</code>, white is used.
+ */
+ public void setMapBackgroundColor(final Color bgColor) {
+ this.mapBackgroundColor = bgColor;
+ }
+
+ /**
+ * Set the BufferedImage to use as a flaoting icon in the lower right corner
+ *
+ * @param mapImageIcon
+ * <code>null</code> is allowed and deactivates this icon.
+ */
+ public void setMapImage(final BufferedImage mapImage) {
+ this.mapImage = mapImage;
+ }
+
+ /**
+ * Sets whether a layer is regarded or ignored on {@link #SELECT_TOP},
+ * {@link #SELECT_ALL} and {@link #SELECT_ONE_FROM_TOP} actions.
+ *
+ * @param layer
+ * a layer
+ * @param selectable
+ * if {@code false} the layer is ignored during the upper
+ * mentioned actions. If <code>null</code>, the default (true)
+ * will be used.
+ */
+ public void setMapLayerSelectable(final MapLayer layer,
+ final Boolean selectable) {
+ if (selectable == null)
+ mapLayerSelectable.remove(layer);
+ else
+ mapLayerSelectable.put(layer, selectable);
+ }
+
+ /**
+ * Defines an evelope of the viwable area. The JMapPane will never show
+ * anything outside of this extend.
+ *
+ * @param maxExtend
+ * <code>null</code> to not have this restriction.
+ */
+ public void setMaxExtend(final Envelope maxExtend) {
+ this.maxExtend = maxExtend;
+ }
+
+ /**
+ * Set the maximum allowed zoom scale. This is the smaller number value of
+ * the two. If <code>null</code> is passed, Double.MINVALUE are used which
+ * mean there is no restriction.
+ *
+ * @author <a href="mailto:skpublic at wikisquare.de">Stefan Alfons
+ * Krüger</a>
+ */
+ public void setMaxZoomScale(final Double maxZoomScale) {
+ this.maxZoomScale = maxZoomScale == null ? Double.MIN_VALUE
+ : maxZoomScale;
+ }
+
+ // /** Stored the time used for the last real rendering in ms. **/
+ private long lastRenderingDuration = 1000;
+ private XMapPaneTool tool = null;
+
+ private Timer stopBlinkTimer;
+
+ private StreamingRenderer blinkRenderer;
+
+ /**
+ * Set the minimum (nearest) allowed zoom scale. This is the bigger number
+ * value of the two. If <code>null</code> is passed, Double.MAXVALUE are
+ * used which mean there is no restriction.
+ *
+ *
+ * @author <a href="mailto:skpublic at wikisquare.de">Stefan Alfons
+ * Krüger</a>
+ */
+ public void setMinZoomScale(final Double minZoomScale) {
+ this.minZoomScale = minZoomScale == null ? Double.MAX_VALUE
+ : minZoomScale;
+ }
+
+ /**
+ * If <code>true</code>, allow the {@link XMapPane} to process #repaint()
+ * requests. Otherwise the map will not paint anything and not start any
+ * rendering {@link Thread}s.
+ */
+ public void setPainting(final boolean b) {
+ acceptsRepaintCalls = b;
+ if (acceptsRepaintCalls == true)
+ repaint();
+ }
+
+ private void setRendererHints(final Map<Object, Object> rendererHints) {
+ if (rendererHints != null)
+ this.rendererHints = rendererHints;
+ }
+
+ // @Deprecated
+ // public void setState(final int state) {
+ // this.state = state;
+ //
+ // // throw new RuntimeException("Old concept.. migrate to new concept!");
+ //
+ // // xMapPaneMouseListener.setEnabled((state == ZOOM_IN
+ // // || state == ZOOM_OUT || state == PAN));
+ //
+ // // Je nach Aktion den Cursor umsetzen
+ // updateCursor();
+ // }
+
+ public void configureMouse(MouseInputType type, XMapPaneAction action) {
+ xMapPaneMouseListener.putAction(type, action);
+ }
+
+ /**
+ * Configure the {@link XMapPaneTool} that active on the map. Passing
+ * <code>null</code> will set the NO_ACTION tool.
+ */
+ public void setTool(XMapPaneTool tool) {
+ if (tool == null)
+ tool = XMapPaneTool.NO_ACTION;
+ this.tool = tool;
+ xMapPaneMouseListener.configure(tool);
+ setCursor(tool.getCursor());
+ }
+
+ // /**
+ // * Standardmaessig wird der Cursor automatisch je nach MapPane-Aktion
+ // (Zoom,
+ // * Auswahl, ...) gesetzt. Mit dieser Methode kann ein statischer Cursor
+ // * gesetzt werden, der unabhaengig von der aktuellen MapPanes-Aktion
+ // * beibehalten wird. Um diesen statischen Cursor wieder zu entfernen, kann
+ // * {@code null} als Parameter uebergeben werden
+ // *
+ // * @param cursor
+ // * Cursor
+ // */
+ // public void setStaticCursor(final Cursor cursor) {
+ // this.staticCursor = cursor;
+ // if (cursor != null)
+ // super.setCursor(cursor);
+ // }
+
+ /**
+ * Starts rendering on one or two threads
+ */
+ private void startRendering() {
+
+ if (!isWellDefined() || !acceptsRepaintCalls) {
+ // if we are not ready to start rendering, try it again the next
+ // time the timer is chacking the flag.
+ requestStartRendering = true;
+ return;
+ }
+
+ if (bgExecuter != null) {
+ // Stop all renderers
+ bgExecuter.cancelTask();
+ }
+
+ localExecuter.cancelTask();
+
+ // Inform listeners that rendering has completed if have no requests to
+ // start again
+ if (!requestStartRendering)
+ fireMapPaneEvent(new MapRenderingStateEvent(this,
+ RenderingState.RENDERING));
+
+ final Rectangle curPaintArea = getVisibleRect();
+
+ /**
+ * We have to set new renderer
+ */
+
+ if (getBgContext() != null) {
+ bgRenderer.setJava2DHints(getJava2dHints());
+ bgRenderer.setRendererHints(getRendererHints());
+
+ // bgExecuter = new RenderingExecutor();
+ // LOGGER.debug("starting bg renderer:");
+ // // /* System.out.println("rendering"); */
+ // final GTRenderer createGTRenderer = GTUtil.createGTRenderer(
+ // bgContext, getRendererHints());
+ // createGTRenderer.setJava2DHints(getJava2dHints());
+ // bgExecuter.submit(getBgContext().getAreaOfInterest(),
+ // curPaintArea,
+ // (Graphics2D) getBgImage().getGraphics(), createGTRenderer);
+ }
+
+ if (getMapContext() != null) {
+ // localExecuter = new RenderingExecutor(this, 150l);
+ // LOGGER.debug("starting local renderer:");
+
+ getLocalRenderer().setJava2DHints(getJava2dHints());
+ getLocalRenderer().setRendererHints(getRendererHints());
+
+ final boolean submitted = localExecuter.submit(getMapArea(),
+ curPaintArea, (Graphics2D) getLocalImage().getGraphics(),
+ getLocalRenderer());
+ if (submitted)
+ repaintTimer.restart();
+ else
+ requestStartRendering = true; // Try to start rendering
+ // again in
+ // a moment
+ }
+
+ updateCursor();
+ }
+
+ private RenderingHints getJava2dHints() {
+ return java2dHints;
+ }
+
+ /**
+ * Transformiert einen Geo-Koordinaten-Bereich in Fenster-Koordinaten.
+ *
+ * @param ox
+ * X-Koordinate der VON-Position
+ * @param oy
+ * Y-Koordinate der VON-Position
+ * @param px
+ * X-Koordinate der BIS-Position
+ * @param py
+ * Y-Koordinate der BIS-Position
+ */
+ public Envelope tranformGeoToWindow(final double ox, final double oy,
+ final double px, final double py) {
+ final AffineTransform at = getWorldToScreenTransform();
+ Point2D geoO;
+ // try {
+ geoO = at.transform(new Point2D.Double(ox, oy), null);
+ final Point2D geoP = at.transform(new Point2D.Double(px, py), null);
+ return new Envelope(geoO.getX(), geoP.getX(), geoO.getY(), geoP.getY());
+ // } catch (final NoninvertibleTransformException e) {
+ // LOGGER.error(e);
+ // return new Envelope(ox, oy, px, py);
+ // }
+ }
+
+ /**
+ * Transformiert einen Geo-Koordinate in eine Fenster-Koordinaten.
+ *
+ * @param x
+ * X-Koordinate der VON-Position
+ * @param y
+ * Y-Koordinate der VON-Position
+ */
+ public Point2D tranformGeoToWindow(final double x, final double y) {
+ return getWorldToScreenTransform().transform(new Point2D.Double(x, y),
+ null);
+ }
+
+ /**
+ * Transformiert einen Fenster-Koordinaten-Bereich in Geo-Koordinaten.
+ *
+ * @param ox
+ * X-Koordinate der VON-Position
+ * @param oy
+ * Y-Koordinate der VON-Position
+ * @param px
+ * X-Koordinate der BIS-Position
+ * @param py
+ * Y-Koordinate der BIS-Position
+ */
+ public Envelope tranformWindowToGeo(final int ox, final int oy,
+ final int px, final int py) {
+ final AffineTransform at = getScreenToWorld();
+ final Point2D geoO = at.transform(new Point2D.Double(ox, oy), null);
+ final Point2D geoP = at.transform(new Point2D.Double(px, py), null);
+
+ // Mmmmm... don't really understand why its x,x,y,y
+ // return new Envelope(geoO.getX(), geoP.getX(), geoO.getY(),
+ // geoP.getY());
+ return new Envelope(new Coordinate(geoO.getX(), geoO.getY()),
+ new Coordinate(geoP.getX(), geoP.getY()));
+ }
+
+ /**
+ * Will update the cursor. If all rendering is finished also stops the
+ * {@link #repaintTimer}
+ */
+ public void updateCursor() {
+
+ // if the renderers have stopped, also stop the timer that is updating
+ // the final image
+ if (bgExecuter != null && bgExecuter.isRunning()
+ || localExecuter.isRunning()) {
+ setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
+ return;
+ } else {
+ // Allow one last rendering
+ if (repaintTimer.isRunning()) {
+ // System.out.println("one last rendering....");
+ repaintTimer.stop();
+ updateFinalImage();
+ repaint();
+ }
+ }
+ //
+ // //
+ // // wenn manueller Cursor gesetzt ist, dann diesen verwenden
+ // (unabhaengig
+ // // von der aktuellen Aktion
+ // if (this.staticCursor != null) {
+ // setCursor(staticCursor);
+ // return;
+ // }
+ //
+ if (getCursor() == SwingUtil.PANNING_CURSOR) {
+ // This cursor will reset itself
+ return;
+ }
+
+ setCursor(tool.getCursor());
+
+ //
+ // // Set the cursor depending on what tool is in use...
+ // switch (state) {
+ // case SELECT_TOP:
+ // case SELECT_ONE_FROM_TOP:
+ // case SELECT_ALL:
+ // setCursor(SwingUtil.CROSSHAIR_CURSOR);
+ // break;
+ // case ZOOM_IN:
+ // setCursor(SwingUtil.ZOOMIN_CURSOR);
+ // break;
+ // case ZOOM_OUT:
+ // setCursor(SwingUtil.ZOOMOUT_CURSOR);
+ // break;
+ // case PAN:
+ // setCursor(SwingUtil.PAN_CURSOR);
+ // break;
+ // default:
+ // setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
+ // break;
+ // }
+ }
+
+ /**
+ * The renderers are all rendering into their own {@link Image}s. This
+ * method combines all images to one {@link #finalImage}. The
+ * {@link #repaintTimer} is calling this method regularely to update the
+ * {@link #finalImage} even if the renderers are still working.
+ */
+ synchronized protected Image updateFinalImage() {
+
+ // Render the two map images first, into the preFinalImage
+ if (bgExecuter != null) {
+ final Graphics2D preFinalG = (Graphics2D) getPreFinalImage()
+ .getGraphics();
+ preFinalG.setBackground(getMapBackgroundColor());
+
+ preFinalG.drawImage(getBgImage(), 0, 0, getMapBackgroundColor(),
+ null);
+
+ // // Draw the local layers image
+ preFinalG.drawImage(getLocalImage(), 0, 0, null);
+ preFinalG.dispose();
+
+ } else {
+ preFinalImage = getLocalImage();
+ }
+
+ final Graphics2D finalG = getFinalImage().createGraphics();
+ finalG.setBackground(getMapBackgroundColor());
+ finalG.drawImage(getPreFinalImage(), getImageOrigin().x,
+ getImageOrigin().y, getMapBackgroundColor(), null);
+
+ // When panning, we have to clear the area around the image
+ final Rectangle painedArea = new Rectangle(getImageOrigin().x,
+ getImageOrigin().y, getFinalImage().getWidth(), getFinalImage()
+ .getHeight());
+ SwingUtil.clearAround(finalG, painedArea, getVisibleRect(),
+ getMapBackgroundColor());
+
+ addGadgets(finalG, false);
+
+ finalG.dispose();
+
+ return finalImage;
+ }
+
+ /**
+ * Paints some optional stuff into the given {@link Graphics2D}. Usually
+ * called as the last layer when {@link #updateFinalImage()}
+ *
+ * @param forceWait
+ * if <code>true</code>, a Wait-message will be painted even
+ * though the rendering threads may not yet have started. If
+ * <code>false</code>, it will only depend on
+ * {@link #localExecuter.isRunning} and #bgExecuter.isRunning
+ */
+ private void addGadgets(final Graphics2D graphics, final boolean forceWait) {
+
+ // Paint a logo to the bottom right if available
+ if (mapImage != null) {
+ final Rectangle visibleRect = getVisibleRect();
+ graphics.drawImage(mapImage, visibleRect.width
+ - mapImage.getWidth() - 10, getVisibleRect().height
+ - mapImage.getHeight() - 10, null);
+ }
+
+ int y = 17;
+
+ // If the rendering process is still running, indicate this is the image
+ if (forceWait || bgExecuter != null && bgExecuter.isRunning()
+ || localExecuter.isRunning()) {
+
+ y += 8;
+
+ final Color c = graphics.getColor();
+ graphics.setFont(waitFont);
+
+ graphics.setColor(getMapBackgroundColor());
+ graphics.drawString(waitMsg, 5, y);
+ graphics.setColor(getMapBackgroundColor());
+ graphics.drawString(waitMsg, 7, y + 2);
+ graphics.setColor(Color.BLACK);
+ graphics.drawString(waitMsg, 6, y + 1);
+
+ graphics.setColor(c);
+
+ y += 21;
+ }
+
+ if (!renderingErrors.isEmpty() && isShowExceptions()) {
+
+ final Color c = graphics.getColor();
+ graphics.setFont(errorFont);
+
+ for (final Exception ex : renderingErrors) {
+
+ String errStr = ex.getLocalizedMessage();
+
+ if (errStr == null)
+ errStr = ex.getMessage();
+ if (errStr == null)
+ errStr = "unknown error: " + ex.getClass().getSimpleName();
+
+ graphics.setColor(getMapBackgroundColor());
+ graphics.drawString(errStr, 5, y);
+ graphics.setColor(Color.RED);
+ graphics.drawString(errStr, 6, y + 1);
+
+ y += 19;
+ }
+
+ graphics.setColor(c);
+ }
+
+ }
+
+ /**
+ * Sets the {@link #mapArea} to best possibly present the given features. If
+ * only one single point is given, the window is moved over the point.
+ *
+ * @param features
+ * if <code>null</code> or size==0, the function doesn nothing.
+ *
+ * @return <code>true</code> if the {@link #mapArea} has changed and
+ * rendering has been triggered.
+ */
+ public boolean zoomTo(
+ final FeatureCollection<SimpleFeatureType, SimpleFeature> features) {
+
+ // if (!isWellDefined()) return;
+
+ final CoordinateReferenceSystem mapCRS = getMapContext()
+ .getCoordinateReferenceSystem();
+ final CoordinateReferenceSystem fCRS = features.getSchema()
+ .getCoordinateReferenceSystem();
+
+ ReferencedEnvelope _mapArea;
+ if (mapArea == null)
+ _mapArea = features.getBounds();
+ else
+ _mapArea = getMapArea();
+ double width = _mapArea.getWidth();
+ double height = _mapArea.getHeight();
+ final double ratio = height / width;
+
+ if (features == null || features.size() == 0) {
+ // feature count == 0 Zoom to the full extend
+ return false;
+ } else if (features.size() == 1) {
+
+ // feature count == 1 Just move the window to the point and zoom 'a
+ // bit'
+ final SimpleFeature singleFeature = features.iterator().next();
+
+ if (((Geometry) singleFeature.getDefaultGeometry())
+ .getCoordinates().length > 1) {
+ // System.out.println("Zoomed to only pne poylgon");
+ // Poly
+ // TODO max width vs. height
+ width = features.getBounds().getWidth() * 3;
+ height = ratio * width;
+ } else {
+ // System.out.println("Zoomed in a bit becasue only one point");
+ // width *= .9;
+ // height *= .9;
+ }
+
+ Coordinate centre = features.getBounds().centre();
+ if (!mapCRS.equals(fCRS)) {
+ // only to calculations if the CRS differ
+ try {
+ MathTransform fToMap;
+ fToMap = CRS.findMathTransform(fCRS, mapCRS);
+ // centre is transformed to the mapCRS
+ centre = JTS.transform(centre, null, fToMap);
+ } catch (final FactoryException e) {
+ LOGGER.error("Looking for a Math transform", e);
+ } catch (final TransformException e) {
+ LOGGER.error("Looking for a Math transform", e);
+ }
+ }
+
+ final Coordinate newLeftBottom = new Coordinate(centre.x - width
+ / 2., centre.y - height / 2.);
+ final Coordinate newTopRight = new Coordinate(
+ centre.x + width / 2., centre.y + height / 2.);
+
+ final Envelope newMapArea = new Envelope(newLeftBottom, newTopRight);
+
+ return setMapArea(newMapArea);
+
+ } else {
+ final ReferencedEnvelope fBounds = features.getBounds();
+
+ ReferencedEnvelope bounds;
+ if (!mapCRS.equals(fCRS)) {
+ bounds = JTSUtil.transformEnvelope(fBounds, mapCRS);
+ } else {
+ bounds = fBounds;
+ }
+ // BB umrechnen von Layer-CRS in Map-CRS
+
+ // Expand a bit
+ addDefaultMargin(bounds);
+
+ return setMapArea(bounds);
+ }
+ }
+
+ private ReferencedEnvelope addDefaultMargin(ReferencedEnvelope bounds) {
+ return JTSUtil.expandEnvelope(bounds, Math.max(0,
+ defaultMaxMapExtendMode));
+ }
+
+ private Envelope addDefaultMargin(Envelope bounds) {
+ return JTSUtil.expandEnvelope(bounds, Math.max(0,
+ defaultMaxMapExtendMode));
+ }
+
+ /**
+ * Zooms towards a point.
+ *
+ * @param center
+ * position in window coordinates
+ * @param zoomFactor
+ * > 1 for zoom in, < 1 for zoom out. Default is 1.33
+ */
+ public void zoomTo(final Point center) {
+ zoomTo(center, null);
+ }
+
+ /**
+ * Zooms towards a point.
+ *
+ * @param center
+ * position in window coordinates
+ * @param zoomFaktor
+ * > 1 for zoom out, < 1 for zoom in. Default is .5
+ * @retun <code>true</code> if {@link #mapArea} has changed and a repaint is
+ * triggered
+ */
+ public boolean zoomTo(Point center, Double zoomFaktor) {
+ if (zoomFaktor == null || zoomFaktor == 0.)
+ zoomFaktor = .5;
+
+ final Point2D gcenter = getScreenToWorld().transform(center, null);
+ center = null;
+
+ if (Double.isNaN(gcenter.getX()) || Double.isNaN(gcenter.getY())
+ || Double.isInfinite(gcenter.getX())
+ || Double.isInfinite(gcenter.getY())
+
+ ) {
+ // Not inside valid CRS area! cancel
+ return false;
+ }
+
+ final Envelope mapArea = getMapArea();
+
+ final Envelope newMapArea = new Envelope(mapArea);
+ newMapArea.expandBy((mapArea.getWidth() * zoomFaktor - mapArea
+ .getWidth()) / 2., (mapArea.getHeight() * zoomFaktor - mapArea
+ .getHeight()) / 2.);
+
+ // // Move the newMapArea above the new center if we zoom in:
+ newMapArea.translate(gcenter.getX() - mapArea.centre().x, gcenter
+ .getY()
+ - mapArea.centre().y);
+
+ return setMapArea(newMapArea);
+ }
+
+ /**
+ * Zooms in or out in a way, that the given {@link Point} on the map stays
+ * at the same positino in screen coordinates.
+ *
+ * @param point
+ * fixed {@link Point} that will be at the same screen poistion
+ * after zoom.
+ */
+ public boolean zoomTowards(Point point, Double zFactor) {
+ // int units = wheelEvt.getUnitsToScroll();
+ //
+ // Negativer Wert --> Zoom out --> Faktir > 1
+
+ // SK: 9.9.2007 zoom jetzt wie bei GoogleEarth
+ // double zFactor = units > 0 ? 1.3 : 1 / 1.3;
+ // vorher double zFactor = units > 0 ? 1/1.2 : 1.2;
+
+ // Fenster-Koordinaten zu Karten-Koordinaten transformieren
+ // Point2D mapCoord = XMapPane.getMapCoordinatesFromEvent(wheelEvt);
+ // Relative Position des Mauszeigers zum Kartenausschnitt
+ // -> Nach Zoom soll dieselbe Kartenposition unterhalb des Mauszeigers
+ // erscheinen, wie vor dem Zoom
+ final Point2D mapCoord = getScreenToWorld().transform(point, null);
+
+ double relX = (mapCoord.getX() - getMapArea().getMinX())
+ / getMapArea().getWidth();
+ double relY = (mapCoord.getY() - getMapArea().getMinY())
+ / getMapArea().getHeight();
+
+ // Neuen Karten-Ausschnitt berechnen
+ Coordinate ll = new Coordinate(mapCoord.getX()
+ - getMapArea().getWidth() * relX * zFactor, mapCoord.getY()
+ - getMapArea().getHeight() * relY * zFactor);
+ Coordinate ur = new Coordinate(mapCoord.getX()
+ + getMapArea().getWidth() * (1 - relX) * zFactor, mapCoord
+ .getY()
+ + getMapArea().getHeight() * (1 - relY) * zFactor);
+
+ return setMapArea(new Envelope(ll, ur));
+ }
+
+ /**
+ * Shall non-fatal rendering exceptions be reported in the mappane or be
+ * dropped quitely.
+ */
+ public void setShowExceptions(final boolean showExceptions) {
+ this.showExceptions = showExceptions;
+ }
+
+ /**
+ * Shall exceptions be reported in the mappane?
+ */
+ public boolean isShowExceptions() {
+ return showExceptions;
+ }
+
+ public GTRenderer getLocalRenderer() {
+ return localRenderer;
+ }
+
+ /**
+ * Setzt den Kartenausschnitt auf die Ausdehnung eines bestimmten Layers.
+ * Macht nichts, wenn {@code null} uebergeben wird.
+ *
+ * <br>
+ *
+ * @param layer
+ * ein Layer
+ */
+ public void zoomToLayer(MapLayer layer) {
+ if (layer == null)
+ return;
+ try {
+
+ // BB umrechnen von Layer-CRS in Map-CRS
+ final CoordinateReferenceSystem targetCRS = getMapContext()
+ .getCoordinateReferenceSystem();
+ final CoordinateReferenceSystem sourceCRS = layer
+ .getFeatureSource().getSchema()
+ .getCoordinateReferenceSystem();
+
+ Envelope mapAreaNew;
+ if (!CRS.equalsIgnoreMetadata(sourceCRS, targetCRS)) {
+ mapAreaNew = JTSUtil.transformEnvelope(layer.getFeatureSource()
+ .getBounds(), sourceCRS, targetCRS);
+ } else {
+ try {
+ mapAreaNew = layer.getFeatureSource().getBounds();
+ } catch (java.lang.IllegalArgumentException e) {
+ LOGGER.error("Can't calc layers bounds...", e);
+ mapAreaNew = null;
+
+ /**
+ *
+ 23.10.2009 11:20:50
+ * org.geotools.data.shapefile.shp.PolygonHandler read
+ * WARNUNG: only one hole in this polygon record ERROR
+ * JMapPane zoomToLayer Zoom to layer did not terminate
+ * correctly java.lang.IllegalArgumentException: Points of
+ * LinearRing do not form a closed linestring at
+ * com.vividsolutions
+ * .jts.geom.LinearRing.validateConstruction
+ * (LinearRing.java:105) at
+ * com.vividsolutions.jts.geom.LinearRing
+ * .<init>(LinearRing.java:100) at
+ * com.vividsolutions.jts.geom
+ * .GeometryFactory.createLinearRing
+ * (GeometryFactory.java:339) at
+ * org.geotools.data.shapefile.
+ * shp.PolygonHandler.read(PolygonHandler.java:188) at
+ * org.geotools
+ * .data.shapefile.shp.ShapefileReader$Record.shape
+ * (ShapefileReader.java:106) at
+ * org.geotools.data.shapefile.
+ * ShapefileAttributeReader.next(
+ * ShapefileAttributeReader.java:157) at
+ * org.geotools.data.shapefile
+ * .indexed.IndexedShapefileAttributeReader
+ * .next(IndexedShapefileAttributeReader.java:122) at
+ * org.geotools
+ * .data.FIDFeatureReader.next(FIDFeatureReader.java:96) at
+ * org.geotools.data.FIDFeatureReader.next(FIDFeatureReader.
+ * java:55) at org.geotools.data.MaxFeatureReader.next(
+ * MaxFeatureReader.java:61) at
+ * org.geotools.data.MaxFeatureReader
+ * .next(MaxFeatureReader.java:61)
+ **/
+ }
+ }
+
+ // Kartenbereich um 10% vergroessern, damit z.B. auch ein
+ // Punkt-Layer,
+ // welches nur aus 2 Punnkten besteht, sichtbar ist (Punkte liegen
+ // sonst
+ // genau auf dem Rand der angezeigten Flaeche)
+
+ if (mapAreaNew != null) {
+
+ mapAreaNew = addDefaultMargin(mapAreaNew);
+ setMapArea(mapAreaNew);
+ } else {
+ LOGGER
+ .warn("Couldn't transformEnvelope when zooming to the layer");
+ }
+ } catch (Exception err) {
+ LOGGER.error("Zoom to layer did not terminate correctly", err);
+ }
+ }
+
+ /**
+ * Zooms the {@link SelectableXMapPane} to the {@link Envelope} of a layer.
+ *
+ * <br>
+ * A refresh of the map is not done automatically
+ *
+ * @param index
+ * Index of the {@link MapLayer} in the {@link MapContext} (from
+ * back to top)
+ *
+ * @author <a href="mailto:skpublic at wikisquare.de">Stefan Alfons
+ * Krüger</a>
+ */
+ public void zoomToLayer(int index) {
+ final MapContext context = getMapContext();
+ if (context != null)
+ zoomToLayer(context.getLayer(index));
+ }
+
+ /**
+ * Zooms the {@link SelectableXMapPane} to the {@link Envelope} of the
+ * selected layer. The layer is selected by the idx, counting from front to
+ * back, like humans would expect in a {@link JList}
+ *
+ * <br>
+ * A refresh of the map is not done automatically
+ *
+ *
+ *
+ * @param index
+ * Reverse index of the {@link MapLayer} in the
+ * {@link MapContext}
+ *
+ * @author <a href="mailto:skpublic at wikisquare.de">Stefan Alfons
+ * Krüger</a>
+ */
+ public void zoomToLayerIdxReverse(int index) {
+ zoomToLayer(getMapContext().getLayerCount() - 1 - index);
+ }
+
+ /**
+ * Aktiviert oder deaktiviert das AntiAliasing for diese
+ * {@link SelectableXMapPane}. AntiALiasing ist besonders fuer
+ * Textbeschriftung sehr schoen, verbraucht aber auch mehr Performance.
+ *
+ * @author <a href="mailto:skpublic at wikisquare.de">Stefan Alfons
+ * Krüger</a>
+ */
+ public void setAntiAliasing(final boolean aa) {
+ // LOGGER.info("Setting AntiAliasing for this JMapPane to " + aa);
+ RenderingHints java2DHints = java2dHints;
+ if (java2DHints == null) {
+ java2DHints = GeoTools.getDefaultHints();
+ }
+
+ java2DHints.put(RenderingHints.KEY_ANTIALIASING,
+ aa ? RenderingHints.VALUE_ANTIALIAS_ON
+ : RenderingHints.VALUE_ANTIALIAS_OFF);
+ java2DHints.put(RenderingHints.KEY_TEXT_ANTIALIASING,
+ aa ? RenderingHints.VALUE_TEXT_ANTIALIAS_ON
+ : RenderingHints.VALUE_TEXT_ANTIALIAS_OFF);
+ java2DHints.put(RenderingHints.KEY_RENDERING,
+ aa ? RenderingHints.VALUE_RENDER_QUALITY
+ : RenderingHints.VALUE_RENDER_SPEED);
+
+ }
+
+ public Point getImageOrigin() {
+ return imageOrigin;
+ }
+
+ /**
+ * If {@link #maxExtend} is <code>null</code> the following rules are used
+ * to create a default maximum.
+ * <ul>
+ * <li>Values < 0 : don't grow to fit the monitors aspect ratio, no
+ * margin</li>
+ * <li>Values 0 : grow to fit the monitors aspect ratio, no margin</li>
+ * <li>Values > 0 : grow to fit the monitors aspect ratio, and add a
+ * relative margin</li>
+ * </ul>
+ * **/
+ public void setDefaultMaxMapExtendMode(double defaultMaxMapExtendMode) {
+ this.defaultMaxMapExtendMode = defaultMaxMapExtendMode;
+ }
+
+ /**
+ * If {@link #maxExtend} is <code>null</code> the following rules are used
+ * to create a default maximum.
+ * <ul>
+ * <li>Values < 0 : don't grow to fit the monitors aspect ratio, no
+ * margin</li>
+ * <li>Values 0 : grow to fit the monitors aspect ratio, no margin</li>
+ * <li>Values > 0 : grow to fit the monitors aspect ratio, and add a
+ * relative margin</li>
+ * </ul>
+ * **/
+ public double getDefaultMaxMapExtendMode() {
+ return defaultMaxMapExtendMode;
+ }
+
+ final static int BLINK_TIMER_DEPLAY = 800;
+
+ /**
+ * The job of the BlinkTimer is to remove the features painted in BLINK
+ * style again.
+ */
+ private Timer initBlinkTimer() {
+ Timer timer = new Timer(BLINK_TIMER_DEPLAY, new ActionListener() {
+
+ @Override
+ public void actionPerformed(ActionEvent e) {
+ blinkRenderer = null;
+ XMapPane.this.repaint(300);
+ }
+ });
+ timer.setDelay(BLINK_TIMER_DEPLAY);
+ timer.setRepeats(false);
+ return timer;
+ }
+
+ /**
+ * Makes the given {@link SimpleFeature} bink in the map for a moment
+ */
+ public void blink(SimpleFeature feature) {
+ MemoryFeatureCollection memoryFeatureCollection = new MemoryFeatureCollection(
+ feature.getFeatureType());
+ memoryFeatureCollection.add(feature);
+ blink(memoryFeatureCollection);
+ }
+
+ /**
+ * Makes the given {@link FeatureCollection} bink in the map for a moment
+ */
+ public void blink(
+ FeatureCollection<SimpleFeatureType, SimpleFeature> features) {
+ {
+ if (stopBlinkTimer != null)
+ stopBlinkTimer.stop();
+ repaint();
+ stopBlinkTimer = initBlinkTimer();
+
+ DefaultMapContext mc = new DefaultMapContext(getMapContext()
+ .getCoordinateReferenceSystem());
+
+ Style style = StylingUtil.STYLE_FACTORY.createStyle();
+ style.featureTypeStyles().add(
+ StylingUtil.createBlinkFeatureTypeStyle(features));
+
+ // style = StylingUtil.createStyleSimple(features, Color.pink,
+ // Color.WHITE);
+
+ DefaultMapLayer dml = new DefaultMapLayer(features, style);
+ mc.addLayer(dml);
+
+ blinkRenderer = new StreamingRenderer();
+
+ blinkRenderer.setJava2DHints(getJava2dHints());
+
+ blinkRenderer.setContext(mc);
+
+ stopBlinkTimer.start();
+
+ }
+
+ }
+
+}
Copied: trunk/src/schmitzm/geotools/gui/XMapPaneAction.java (from rev 736, trunk/src/skrueger/geotools/XMapPaneAction.java)
===================================================================
--- trunk/src/skrueger/geotools/XMapPaneAction.java 2010-03-02 16:22:12 UTC (rev 736)
+++ trunk/src/schmitzm/geotools/gui/XMapPaneAction.java 2010-03-03 10:32:14 UTC (rev 740)
@@ -0,0 +1,162 @@
+/*******************************************************************************
+ * Copyright (c) 2009 Martin O. J. Schmitz.
+ *
+ * This file is part of the SCHMITZM library - a collection of utility
+ * classes based on Java 1.6, focusing (not only) on Java Swing
+ * and the Geotools library.
+ *
+ * The SCHMITZM project is hosted at:
+ * http://wald.intevation.org/projects/schmitzm/
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 3
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License (license.txt)
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * or try this link: http://www.gnu.org/licenses/lgpl.html
+ *
+ * Contributors:
+ * Martin O. J. Schmitz - initial API and implementation
+ * Stefan A. Krüger - additional utility classes
+ ******************************************************************************/
+package schmitzm.geotools.gui;
+
+import java.awt.Point;
+import java.awt.event.MouseEvent;
+import java.awt.event.MouseWheelEvent;
+
+import org.opengis.geometry.DirectPosition;
+
+import schmitzm.swing.event.MouseInputType;
+
+/**
+ * Defines an action (e.g. Zoom in, zoom out, drag) when a click, drag or window
+ * selection is performed on a {@link XMapPane}.
+ *
+ * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a>
+ * (University of Bonn/Germany)
+ */
+public interface XMapPaneAction {
+
+ /**
+ * This action can be assigned to any {@link MouseInputType} to perform
+ * zoom-in
+ **/
+ public static XMapPaneAction_Zoom ZOOM_IN = new XMapPaneAction_Zoom.In();
+
+ /**
+ * This action can be assigned to any {@link MouseInputType} to perform
+ * zoom-out
+ **/
+ public static XMapPaneAction_Zoom ZOOM_OUT = new XMapPaneAction_Zoom.Out();
+
+ /**
+ * This action can be assigned to any {@link MouseInputType} to perform
+ * panning on a Map
+ **/
+ public static XMapPaneAction_Pan PAN = new XMapPaneAction_Pan();
+
+ /**
+ * This action can be assigned to fire events for any number of feature from all layers.
+ **/
+ public static XMapPaneAction_Select.All SELECT_ALL = new XMapPaneAction_Select.All();
+
+ /**
+ * This action can be assigned to fire selection events for one feature from the top layer.
+ **/
+ public static XMapPaneAction_Select.OneFromTop SELECT_ONE_FROM_TOP = new XMapPaneAction_Select.OneFromTop();
+
+ /**
+ * This action can be assigned to fire events for any number of feature from the top layer.
+ **/
+ public static XMapPaneAction_Select.Top SELECT_TOP = new XMapPaneAction_Select.Top();
+
+ /**
+ * Defines the action in case of a single click on the map. Called by ###
+ * XMapPaneMouseAdapter ### on {@link MouseInputType#LClick} and
+ * {@link MouseInputType#RClick}.
+ *
+ * @param mapPane
+ * map pane the action should be performed on
+ * @param ev
+ * mouse event of the action
+ * @param coord
+ * geo coordinate the click is performed on
+ */
+ public void performClick(XMapPane mapPane, MouseEvent ev,
+ DirectPosition coord);
+
+ /**
+ * Defines the action in case of a mouse drag on the map. This method is
+ * called on every mouse motion.
+ *
+ * @param mapPane
+ * map pane the action should be performed on
+ * @param ev
+ * mouse event of the action
+ * @param dragStartPos
+ * window position the drag was started (the current position can
+ * be determined from the mouse event)
+ * @param startCoord
+ * geo coordinate the drag was started
+ * @param endCoord
+ * geo coordinate the drag is currently moved over
+ */
+ public void performDragging(XMapPane mapPane, MouseEvent ev,
+ Point dragStartPos, Point dragLastPos, DirectPosition startCoord,
+ DirectPosition endCoord);
+
+ /**
+ * Defines the action in case of a window selection on the map (the moment a
+ * drag ends).
+ *
+ * @param mapPane
+ * map pane the action should be performed on
+ * @param ev
+ * mouse event of the action
+ * @param dragStartPos
+ * window position the window starts (the end position can be
+ * determined from the mouse event)
+ * @param startCoord
+ * geo coordinate the window starts
+ * @param endCoord
+ * geo coordinate the window ends
+ */
+ public void performDragged(XMapPane mapPane, MouseEvent ev,
+ Point dragStartPos, Point dragLastPos, DirectPosition startCoord,
+ DirectPosition endCoord);
+
+ /**
+ * Defines the action in case of a mouse wheel action on the map (the moment
+ * a drag ends).
+ *
+ * @param mapPane
+ * map pane the action should be performed on
+ * @param ev
+ * mouse event of the action
+ * @param coord
+ * geo coordinate the wheel is turned on
+ */
+ public void performWheel(XMapPane mapPane, MouseWheelEvent ev,
+ DirectPosition coord);
+
+ /**
+ * Defines what happens if this action has been triggered by a keyboard-key.
+ *
+ * @param mapPane
+ * map pane the action should be performed on
+ *
+ * @param param
+ * An optinal paramter that can be defined.
+ */
+ public void performKeyboard(XMapPane mapPane, Object param);
+
+}
Copied: trunk/src/schmitzm/geotools/gui/XMapPaneActionAdapter.java (from rev 736, trunk/src/skrueger/geotools/XMapPaneActionAdapter.java)
===================================================================
--- trunk/src/skrueger/geotools/XMapPaneActionAdapter.java 2010-03-02 16:22:12 UTC (rev 736)
+++ trunk/src/schmitzm/geotools/gui/XMapPaneActionAdapter.java 2010-03-03 10:32:14 UTC (rev 740)
@@ -0,0 +1,88 @@
+/*******************************************************************************
+ * Copyright (c) 2009 Martin O. J. Schmitz.
+ *
+ * This file is part of the SCHMITZM library - a collection of utility
+ * classes based on Java 1.6, focusing (not only) on Java Swing
+ * and the Geotools library.
+ *
+ * The SCHMITZM project is hosted at:
+ * http://wald.intevation.org/projects/schmitzm/
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 3
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License (license.txt)
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * or try this link: http://www.gnu.org/licenses/lgpl.html
+ *
+ * Contributors:
+ * Martin O. J. Schmitz - initial API and implementation
+ * Stefan A. Krüger - additional utility classes
+ ******************************************************************************/
+
+package schmitzm.geotools.gui;
+
+import java.awt.Point;
+import java.awt.event.MouseEvent;
+import java.awt.event.MouseWheelEvent;
+
+import org.opengis.geometry.DirectPosition;
+
+
+
+/**
+ * Empty implementation of {@link XMapPaneAction}. No method of this class
+ * does anything.
+ * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
+ */
+public class XMapPaneActionAdapter implements XMapPaneAction {
+
+ /**
+ * Implements the action on a mouse click event. Does nothing.
+ */
+ @Override
+ public void performClick(XMapPane mapPane, MouseEvent ev, DirectPosition coord) {
+ }
+
+ /**
+ * Implements the action AFTER a mouse drag has ended. Does nothing.
+ */
+ @Override
+ public void performDragged(XMapPane mapPane, MouseEvent ev,
+ Point dragStartPos, Point dragLastPos, DirectPosition startCoord,
+ DirectPosition endCoord) {
+ }
+
+ /**
+ * Implements the action DURING a mouse drag. Does nothing.
+ */
+ @Override
+ public void performDragging(XMapPane mapPane, MouseEvent ev,
+ Point dragStartPos, Point dragLastPos, DirectPosition startCoord,
+ DirectPosition endCoord) {
+ }
+
+ /**
+ * Implements the action on a keyboard stroke. Does nothing.
+ */
+ @Override
+ public void performKeyboard(XMapPane mapPane, Object param) {
+ }
+
+ /**
+ * Implements the action on mouse wheel event. Does nothing.
+ */
+ @Override
+ public void performWheel(XMapPane mapPane, MouseWheelEvent ev,
+ DirectPosition coord) {
+ }
+
+}
Copied: trunk/src/schmitzm/geotools/gui/XMapPaneAction_Pan.java (from rev 736, trunk/src/skrueger/geotools/XMapPaneAction_Pan.java)
===================================================================
--- trunk/src/skrueger/geotools/XMapPaneAction_Pan.java 2010-03-02 16:22:12 UTC (rev 736)
+++ trunk/src/schmitzm/geotools/gui/XMapPaneAction_Pan.java 2010-03-03 10:32:14 UTC (rev 740)
@@ -0,0 +1,175 @@
+/*******************************************************************************
+ * Copyright (c) 2009 Martin O. J. Schmitz.
+ *
+ * This file is part of the SCHMITZM library - a collection of utility
+ * classes based on Java 1.6, focusing (not only) on Java Swing
+ * and the Geotools library.
+ *
+ * The SCHMITZM project is hosted at:
+ * http://wald.intevation.org/projects/schmitzm/
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 3
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License (license.txt)
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * or try this link: http://www.gnu.org/licenses/lgpl.html
+ *
+ * Contributors:
+ * Martin O. J. Schmitz - initial API and implementation
+ * Stefan A. Krüger - additional utility classes
+ ******************************************************************************/
+package schmitzm.geotools.gui;
+
+import java.awt.Cursor;
+import java.awt.Point;
+import java.awt.Rectangle;
+import java.awt.event.MouseEvent;
+import java.awt.event.MouseWheelEvent;
+
+import org.opengis.geometry.DirectPosition;
+
+import schmitzm.swing.SwingUtil;
+
+import com.vividsolutions.jts.geom.Envelope;
+
+public class XMapPaneAction_Pan implements XMapPaneAction {
+
+ public static enum Direction {
+ UP, DOWN, RIGHT, LEFT
+ }
+
+ /**
+ * If this action is triggered by keyboard, defines the amount of panning in
+ * screen pixels
+ **/
+ private static final int KEYBOARD_PAN_LENGTH = 15;
+
+ /**
+ * This variable can be used to backup the active cursor of the mapPane, if
+ * the actions changes the cursor during dragging
+ */
+ public Cursor backupCursor = null;
+
+ /**
+ * Performs a pan action. During panning, the displacement is stored in
+ * {@link #imageOrigin} object. Calling {@link #performPan()} will reset the
+ * offset and call {@link #setMapArea(Envelope)}.
+ */
+ @Override
+ public void performDragged(XMapPane mapPane, MouseEvent ev,
+ Point dragStartPos, Point dragLastPos, DirectPosition startCoord,
+ DirectPosition endCoord) {
+
+ Point translation = mapPane.getImageOrigin();
+
+ doPan(mapPane, translation);
+ }
+
+ private void doPan(XMapPane mapPane, Point translation) {
+
+ final Rectangle winBounds = mapPane.getVisibleRect();
+ winBounds.translate(-translation.x, -translation.y);
+ final Envelope newMapArea = mapPane.tranformWindowToGeo(winBounds.x,
+ winBounds.y, winBounds.x + winBounds.width, winBounds.y
+ + winBounds.height);
+
+ translation.x = 0;
+ translation.y = 0;
+
+ if (!mapPane.setMapArea(newMapArea)) {
+ /**
+ * If setMapArea returns true, the finalImage is updated anyways.
+ * This if-case exists to ensure that we repaint a correct image
+ * even if the new panning area has been denied.
+ */
+ mapPane.updateFinalImage();
+ mapPane.repaint();
+ }
+
+ if (mapPane.getCursor() == SwingUtil.PANNING_CURSOR) {
+ mapPane.setCursor(backupCursor);
+ }
+ }
+
+ /**
+ * TODO: Stop dragging if the expected map area would not be valid.
+ */
+ @Override
+ public void performDragging(XMapPane mapPane, MouseEvent ev,
+ Point dragStartPos, Point dragLastPos, DirectPosition startCoord,
+ DirectPosition endCoord) {
+
+ if (mapPane.getCursor() != SwingUtil.PANNING_CURSOR) {
+ backupCursor = mapPane.getCursor();
+ mapPane.setCursor(SwingUtil.PANNING_CURSOR);
+ }
+
+ // Variables for the translation in screen pixels
+ int dX;
+ int dY;
+
+ if (dragLastPos == null) {
+ dX = ev.getPoint().x - dragStartPos.x;
+ dY = ev.getPoint().y - dragStartPos.y;
+ } else {
+ dX = ev.getPoint().x - dragLastPos.x;
+ dY = ev.getPoint().y - dragLastPos.y;
+ }
+
+ if (dX != 0 && dY != 0)
+ mapPane.pan(dX, dY);
+
+ }
+
+ @Override
+ public void performWheel(XMapPane mapPane, MouseWheelEvent ev,
+ DirectPosition coord) {
+ }
+
+ @Override
+ public void performClick(XMapPane mapPane, MouseEvent ev,
+ DirectPosition coord) {
+ }
+
+ @Override
+ public void performKeyboard(XMapPane mapPane, Object param) {
+ if (param == null)
+ return;
+
+ if (!(param instanceof Direction)) {
+ throw new IllegalArgumentException("param = " + param
+ + " is of expected type XMapPaneAction_Pan.Direction");
+ }
+
+ // Variables for the translation in screen pixels
+ int dX = 0;
+ int dY = 0;
+
+ switch ((Direction) param) {
+ case DOWN:
+ dY = KEYBOARD_PAN_LENGTH;
+ break;
+ case UP:
+ dY = -KEYBOARD_PAN_LENGTH;
+ break;
+ case LEFT:
+ dX = -KEYBOARD_PAN_LENGTH;
+ break;
+ case RIGHT:
+ dX = KEYBOARD_PAN_LENGTH;
+ break;
+ }
+
+ doPan(mapPane, new Point(dX, dY));
+ }
+
+}
Property changes on: trunk/src/schmitzm/geotools/gui/XMapPaneAction_Pan.java
___________________________________________________________________
Name: svn:mime-type
+ text/plain
Name: svn:keywords
+ Id URL
Name: svn:eol-style
+ native
Copied: trunk/src/schmitzm/geotools/gui/XMapPaneAction_Select.java (from rev 736, trunk/src/skrueger/geotools/XMapPaneAction_Select.java)
===================================================================
--- trunk/src/skrueger/geotools/XMapPaneAction_Select.java 2010-03-02 16:22:12 UTC (rev 736)
+++ trunk/src/schmitzm/geotools/gui/XMapPaneAction_Select.java 2010-03-03 10:32:14 UTC (rev 740)
@@ -0,0 +1,215 @@
+package schmitzm.geotools.gui;
+
+import java.awt.Color;
+import java.awt.Point;
+import java.awt.event.MouseEvent;
+import java.awt.event.MouseWheelEvent;
+import java.awt.geom.Point2D;
+import java.util.Enumeration;
+import java.util.Hashtable;
+import java.util.Iterator;
+
+import org.geotools.data.memory.MemoryFeatureCollection;
+import org.geotools.feature.FeatureCollection;
+import org.geotools.map.MapLayer;
+import org.opengis.feature.simple.SimpleFeature;
+import org.opengis.feature.simple.SimpleFeatureType;
+import org.opengis.geometry.DirectPosition;
+
+import schmitzm.geotools.map.event.FeatureSelectedEvent;
+import skrueger.geotools.GeomFilterGenerator;
+import skrueger.geotools.GeomFilterGenerator.PointFilterGenerator;
+
+import com.vividsolutions.jts.geom.Coordinate;
+import com.vividsolutions.jts.geom.Envelope;
+import com.vividsolutions.jts.geom.Geometry;
+import com.vividsolutions.jts.geom.GeometryFactory;
+
+public abstract class XMapPaneAction_Select implements XMapPaneAction {
+ //
+ // /**
+ // * Flag fuer Modus "SimpleFeature-Auswahl auf allen (sichtbaren) Layern".
+ // *
+ // * @see #setState(int)
+ // * @see #setState(int)
+ // */
+ // public static enum SelMode {
+ // SELECT_ALL
+ // }
+
+ public void performClick(XMapPane xMapPane, MouseEvent ev,
+ DirectPosition geoCoord) {
+
+ SelectableXMapPane sexMapPane = (SelectableXMapPane) xMapPane;
+
+ // calculate a circle radius around the mouse position
+ double radius = DEFAULT_DISTANCE_FRACTION
+ * (xMapPane.getMapArea().getWidth() + xMapPane.getMapArea()
+ .getHeight()) / 2;
+
+ // Fenster-Koordinate in Geo-Koordinate umwandelt
+ Point2D geoPoint = xMapPane.getScreenToWorld().transform(ev.getPoint(),
+ null);
+
+ PointFilterGenerator filterGenerator = new PointFilterGenerator(
+ geoCoord, radius);
+ Hashtable<MapLayer, FeatureCollection<SimpleFeatureType, SimpleFeature>> result = sexMapPane
+ .findVisibleFeatures(filterGenerator, getSelectionMode(),
+ new Envelope(geoPoint.getX(), geoPoint.getX(), geoPoint
+ .getY(), geoPoint.getY()));
+
+ // Ein Event auslösen für das jeweils nächste Feature pro Layer
+ for (Enumeration<MapLayer> element = result.keys(); element
+ .hasMoreElements();) {
+
+ MapLayer layer = element.nextElement();
+ FeatureCollection<SimpleFeatureType, SimpleFeature> fc = result
+ .get(layer);
+ FeatureCollection<SimpleFeatureType, SimpleFeature> fcOne;
+
+ if (fc != null && !fc.isEmpty()) {
+
+ if (fc.size() > 1) {
+ // If the result contains more that one feature, we only
+ // return the nearest one.
+
+ SimpleFeature nearestFeature = null;
+ Double nearestDist = 0.0;
+
+ Iterator<SimpleFeature> fcIt = fc.iterator();
+ try {
+ com.vividsolutions.jts.geom.Point mousePoint = new GeometryFactory()
+ .createPoint(new Coordinate(geoPoint.getX(),
+ geoPoint.getY()));
+
+ while (fcIt.hasNext()) {
+ SimpleFeature f = fcIt.next();
+ Geometry obj = (Geometry) f
+ .getDefaultGeometryProperty().getValue();
+
+ // TODO Hier muss doch irgendwie noch CRS
+ // umgewrechnet werden...
+
+ Geometry featureGeometry = (Geometry) obj;
+
+ double distance = featureGeometry
+ .distance(mousePoint);
+
+ if ((nearestFeature == null)
+ || (distance < nearestDist)) {
+ nearestFeature = f;
+ nearestDist = distance;
+ }
+
+ }
+
+ } finally {
+ fc.close(fcIt);
+ }
+
+ fcOne = new MemoryFeatureCollection(fc.getSchema());
+ fc.clear();
+ fcOne.add(nearestFeature);
+ } else {
+ fcOne = fc;
+ }
+
+ // Fire the event with the one selected feature
+ sexMapPane.fireMapPaneEvent(new FeatureSelectedEvent(
+ sexMapPane, layer, fcOne.getBounds(), fcOne));
+ }
+ }
+
+ // If no vector features were found, or we are in SELECT_ALL mode, we
+ // check the raster layers now
+ if (getSelectionMode() == SelectableXMapPane.SELECT_ALL || result.isEmpty()) {
+ sexMapPane.findGridCoverageValuesAndFireEvents(geoPoint,
+ getSelectionMode());
+ }
+ }
+
+ /**
+ * Does nothing if initiated by keyboard.
+ *
+ * TODO select all features should be assignable to Strg-A
+ */
+ @Override
+ public void performKeyboard(XMapPane mapPane, Object param) {
+ }
+
+ /**
+ * Default distance fraction used with line and point features. When the
+ * user clicks on the map, this tool searches for features within a
+ * rectangle of width w centered on the mouse location, where w is the
+ * average map side length multiplied by the value of this constant.
+ */
+ public static final double DEFAULT_DISTANCE_FRACTION = 0.01d;
+
+ // @Override
+ // public void performClick(XMapPane xMapPane, MouseEvent ev,
+ // DirectPosition geoCoord) {
+ //
+ // performSelectionClick(xMapPane, ev, geoCoord, XMapPane.SELECT_ALL);
+ // }
+
+ @Override
+ public void performDragged(XMapPane mapPane, MouseEvent ev,
+ Point dragStartPos, Point dragLastPos, DirectPosition startCoord,
+ DirectPosition endCoord) {
+
+ SelectableXMapPane sexMapPane = (SelectableXMapPane) mapPane;
+
+ Point mp = ev.getPoint();
+
+ // Ist es eine wirkliche Selektion, oder etwas nur ein Klick?
+ if (dragStartPos.x != mp.x && dragStartPos.y != mp.y) {
+ sexMapPane.drawRectangle(sexMapPane.getGraphics(), dragStartPos, ev
+ .getPoint(), Color.BLUE.brighter(), true);
+ }
+
+ // SELECTION!
+ sexMapPane.performSelectionEvent(dragStartPos.x, dragStartPos.y, mp.x,
+ mp.y, getSelectionMode());
+ }
+
+ abstract int getSelectionMode();
+
+ @Override
+ public void performDragging(XMapPane mapPane, MouseEvent ev,
+ Point dragStartPos, Point dragLastPos, DirectPosition startCoord,
+ DirectPosition endCoord) {
+ if (dragLastPos != null)
+ mapPane.drawRectangle(mapPane.getGraphics(), dragStartPos,
+ dragLastPos, Color.BLUE.brighter(), true);
+
+ mapPane.drawRectangle(mapPane.getGraphics(), dragStartPos, ev
+ .getPoint(), Color.BLUE.brighter(), true);
+ }
+
+ @Override
+ public void performWheel(XMapPane mapPane, MouseWheelEvent ev,
+ DirectPosition coord) {
+ }
+
+ public static class All extends XMapPaneAction_Select {
+
+ int getSelectionMode() {
+ return SelectableXMapPane.SELECT_ALL;
+ }
+ }
+
+ public static class OneFromTop extends XMapPaneAction_Select {
+
+ int getSelectionMode() {
+ return SelectableXMapPane.SELECT_ONE_FROM_TOP;
+ }
+ }
+
+ public static class Top extends XMapPaneAction_Select {
+
+ int getSelectionMode() {
+ return SelectableXMapPane.SELECT_TOP;
+ }
+ }
+
+}
Property changes on: trunk/src/schmitzm/geotools/gui/XMapPaneAction_Select.java
___________________________________________________________________
Name: svn:mime-type
+ text/plain
Name: svn:keywords
+ Id URL
Name: svn:eol-style
+ native
Copied: trunk/src/schmitzm/geotools/gui/XMapPaneAction_Zoom.java (from rev 736, trunk/src/skrueger/geotools/XMapPaneAction_Zoom.java)
===================================================================
--- trunk/src/skrueger/geotools/XMapPaneAction_Zoom.java 2010-03-02 16:22:12 UTC (rev 736)
+++ trunk/src/schmitzm/geotools/gui/XMapPaneAction_Zoom.java 2010-03-03 10:32:14 UTC (rev 740)
@@ -0,0 +1,240 @@
+package schmitzm.geotools.gui;
+
+import java.awt.Point;
+import java.awt.Rectangle;
+import java.awt.event.MouseEvent;
+import java.awt.event.MouseWheelEvent;
+
+import org.opengis.geometry.DirectPosition;
+
+import schmitzm.geotools.JTSUtil;
+
+import com.vividsolutions.jts.geom.Coordinate;
+import com.vividsolutions.jts.geom.Envelope;
+
+public abstract class XMapPaneAction_Zoom implements XMapPaneAction {
+
+ @Override
+ public void performDragging(XMapPane mapPane, MouseEvent ev,
+ Point dragStartPos, Point dragLastPos,
+ DirectPosition startCoord, DirectPosition endCoord) {
+
+ if (dragLastPos != null)
+ mapPane.drawRectangle(mapPane.getGraphics(), dragStartPos,
+ dragLastPos);
+
+ mapPane.drawRectangle(mapPane.getGraphics(), dragStartPos, ev
+ .getPoint());
+ }
+
+ public static class In extends XMapPaneAction_Zoom {
+
+ @Override
+ public void performClick(XMapPane mapPane, MouseEvent ev,
+ DirectPosition coord) {
+
+// mapPane.zoomTo(ev.getPoint(), 1 / 2.);
+
+ mapPane.zoomTowards(ev.getPoint(), 1/1.3);
+ }
+
+ @Override
+ public void performWheel(XMapPane mapPane, MouseWheelEvent wheelEvt,
+ DirectPosition coord) {
+
+ double zFactor = wheelEvt.getUnitsToScroll() > 0 ? 1.3 : 1 / 1.3;
+ mapPane.zoomTowards(wheelEvt.getPoint(), zFactor);
+
+// // vorher double zFactor = units > 0 ? 1/1.2 : 1.2;
+//
+// // Fenster-Koordinaten zu Karten-Koordinaten transformieren
+// Point2D mapCoord = XMapPane.getMapCoordinatesFromEvent(wheelEvt);
+// // Relative Position des Mauszeigers zum Kartenausschnitt
+// // -> Nach Zoom soll dieselbe Kartenposition unterhalb des Mauszeigers
+// // erscheinen, wie vor dem Zoom
+// double relX = (mapCoord.getX() - mapPane.getMapArea().getMinX())
+// / mapPane.getMapArea().getWidth();
+// double relY = (mapCoord.getY() - mapPane.getMapArea().getMinY())
+// / mapPane.getMapArea().getHeight();
+//
+// // Neuen Karten-Ausschnitt berechnen
+// Coordinate ll = new Coordinate(mapCoord.getX()
+// - mapPane.getMapArea().getWidth() * relX * zFactor, mapCoord.getY()
+// - mapPane.getMapArea().getHeight() * relY * zFactor);
+// Coordinate ur = new Coordinate(mapCoord.getX()
+// + mapPane.getMapArea().getWidth() * (1 - relX) * zFactor, mapCoord
+// .getY()
+// + mapPane.getMapArea().getHeight() * (1 - relY) * zFactor);
+// mapPane.setMapArea(new Envelope(ll, ur));
+ }
+
+ @Override
+ public void performDragged(XMapPane mapPane, MouseEvent ev,
+ Point dragStartPos, Point dragLastPos,
+ DirectPosition startCoord, DirectPosition endCoord) {
+
+ if (dragLastPos != null)
+ mapPane.drawRectangle(mapPane.getGraphics(), dragStartPos,
+ dragLastPos);
+
+ // If this is similar to a click, let mouseClicked handle it!
+ if ((Math.abs(dragStartPos.x - ev.getPoint().x) * Math.abs(ev
+ .getPoint().y
+ - dragStartPos.y)) < 160) {
+ // performClick(mapPane, ev, coord)
+ return;
+ }
+
+ final Rectangle bounds = mapPane.getBounds();
+
+ Envelope mapArea = mapPane.getMapArea();
+
+ // Replace with transform and translate
+ final double mapWidth = mapArea.getWidth();
+ final double mapHeight = mapArea.getHeight();
+
+ final double startX = ((dragStartPos.x * mapWidth) / (double) bounds.width)
+ + mapArea.getMinX();
+ final double startY = (((bounds.getHeight() - dragStartPos.y) * mapHeight) / (double) bounds.height)
+ + mapArea.getMinY();
+ final double endX = ((ev.getPoint().x * mapWidth) / (double) bounds.width)
+ + mapArea.getMinX();
+ final double endY = (((bounds.getHeight() - ev.getPoint().y) * mapHeight) / (double) bounds.height)
+ + mapArea.getMinY();
+
+ final double left = Math.min(startX, endX);
+ final double right = Math.max(startX, endX);
+ final double bottom = Math.min(startY, endY);
+ final double top = Math.max(startY, endY);
+ final Coordinate ll = new Coordinate(left, bottom);
+ final Coordinate ur = new Coordinate(right, top);
+
+ mapPane.setMapArea(new Envelope(ll, ur));
+
+ }
+
+ /**
+ * @param param is ignored
+ */
+ @Override
+ public void performKeyboard(XMapPane mapPane, Object param) {
+ mapPane.setMapArea( JTSUtil.expandEnvelope(mapPane.getMapArea(), -.10) );
+ }
+
+ }
+
+ public static class Out extends XMapPaneAction_Zoom {
+
+ /**
+ * @param param is ignored
+ */
+ @Override
+ public void performKeyboard(XMapPane mapPane, Object param) {
+ mapPane.setMapArea( JTSUtil.expandEnvelope(mapPane.getMapArea(), .10) );
+ }
+
+ @Override
+ public void performClick(XMapPane mapPane, MouseEvent ev,
+ DirectPosition coord) {
+
+// mapPane.zoomTo(ev.getPoint(), 2.);
+
+ mapPane.zoomTowards(ev.getPoint(), 1.3);
+ }
+
+ @Override
+ public void performWheel(XMapPane mapPane, MouseWheelEvent wheelEvt,
+ DirectPosition coord) {
+
+ double zFactor = wheelEvt.getUnitsToScroll() > 0 ? 1.3 : 1 / 1.3;
+ mapPane.zoomTowards(wheelEvt.getPoint(), zFactor);
+
+// int units = wheelEvt.getUnitsToScroll();
+// // Positiver Wert --> Zoom in --> Faktor < 1
+// // Negativer Wert --> Zoom out --> Faktir > 1
+//
+// // SK: 9.9.2007 zoom jetzt wie bei GoogleEarth
+// double zFactor = units > 0 ? 1.3 : 1 / 1.3;
+// // vorher double zFactor = units > 0 ? 1/1.2 : 1.2;
+//
+// // Fenster-Koordinaten zu Karten-Koordinaten transformieren
+// Point2D mapCoord = XMapPane.getMapCoordinatesFromEvent(wheelEvt);
+// // Relative Position des Mauszeigers zum Kartenausschnitt
+// // -> Nach Zoom soll dieselbe Kartenposition unterhalb des Mauszeigers
+// // erscheinen, wie vor dem Zoom
+// double relX = (mapCoord.getX() - mapPane.getMapArea().getMinX())
+// / mapPane.getMapArea().getWidth();
+// double relY = (mapCoord.getY() - mapPane.getMapArea().getMinY())
+// / mapPane.getMapArea().getHeight();
+//
+// // Neuen Karten-Ausschnitt berechnen
+// Coordinate ll = new Coordinate(mapCoord.getX()
+// - mapPane.getMapArea().getWidth() * relX * zFactor, mapCoord.getY()
+// - mapPane.getMapArea().getHeight() * relY * zFactor);
+// Coordinate ur = new Coordinate(mapCoord.getX()
+// + mapPane.getMapArea().getWidth() * (1 - relX) * zFactor, mapCoord
+// .getY()
+// + mapPane.getMapArea().getHeight() * (1 - relY) * zFactor);
+// mapPane.setMapArea(new Envelope(ll, ur));
+ }
+
+
+ @Override
+ public void performDragged(XMapPane mapPane, MouseEvent ev,
+ Point dragStartPos, Point dragLastPos,
+ DirectPosition startCoord, DirectPosition endCoord) {
+
+ if (dragLastPos != null)
+ mapPane.drawRectangle(mapPane.getGraphics(), dragStartPos,
+ dragLastPos);
+
+ // If this is similar to a click, let mouseClicked handle it!
+ if ((Math.abs(dragStartPos.x - ev.getPoint().x) * Math.abs(ev
+ .getPoint().y
+ - dragStartPos.y)) < 160) {
+ // performClick(mapPane, ev, coord)
+ return;
+ }
+
+ final Rectangle bounds = mapPane.getBounds();
+
+ Envelope mapArea = mapPane.getMapArea();
+
+ // Replace with transform and translate
+ final double mapWidth = mapArea.getWidth();
+ final double mapHeight = mapArea.getHeight();
+
+ final double startX = ((dragStartPos.x * mapWidth) / (double) bounds.width)
+ + mapArea.getMinX();
+ final double startY = (((bounds.getHeight() - dragStartPos.y) * mapHeight) / (double) bounds.height)
+ + mapArea.getMinY();
+ final double endX = ((ev.getPoint().x * mapWidth) / (double) bounds.width)
+ + mapArea.getMinX();
+ final double endY = (((bounds.getHeight() - ev.getPoint().y) * mapHeight) / (double) bounds.height)
+ + mapArea.getMinY();
+
+ // make the dragged rectangle in screen coords the new map size?
+ final double left = Math.min(startX, endX);
+ final double right = Math.max(startX, endX);
+ final double bottom = Math.min(startY, endY);
+ final double top = Math.max(startY, endY);
+ final double nWidth = (mapWidth * mapWidth) / (right - left);
+ final double nHeight = (mapHeight * mapHeight) / (top - bottom);
+ final double deltaX1 = left - mapArea.getMinX();
+ final double nDeltaX1 = (deltaX1 * nWidth) / mapWidth;
+ final double deltaY1 = bottom - mapArea.getMinY();
+ final double nDeltaY1 = (deltaY1 * nHeight) / mapHeight;
+ final Coordinate ll = new Coordinate(mapArea.getMinX() - nDeltaX1,
+ mapArea.getMinY() - nDeltaY1);
+ final double deltaX2 = mapArea.getMaxX() - right;
+ final double nDeltaX2 = (deltaX2 * nWidth) / mapWidth;
+ final double deltaY2 = mapArea.getMaxY() - top;
+ final double nDeltaY2 = (deltaY2 * nHeight) / mapHeight;
+ final Coordinate ur = new Coordinate(mapArea.getMaxX() + nDeltaX2,
+ mapArea.getMaxY() + nDeltaY2);
+
+ mapPane.setMapArea(new Envelope(ll, ur));
+
+ }
+ }
+}
\ No newline at end of file
Property changes on: trunk/src/schmitzm/geotools/gui/XMapPaneAction_Zoom.java
___________________________________________________________________
Name: svn:mime-type
+ text/plain
Name: svn:keywords
+ Id URL
Name: svn:eol-style
+ native
Copied: trunk/src/schmitzm/geotools/gui/XMapPaneEvent.java (from rev 736, trunk/src/schmitzm/geotools/map/event/MapPaneEvent.java)
===================================================================
--- trunk/src/schmitzm/geotools/map/event/MapPaneEvent.java 2010-03-02 16:22:12 UTC (rev 736)
+++ trunk/src/schmitzm/geotools/gui/XMapPaneEvent.java 2010-03-03 10:32:14 UTC (rev 740)
@@ -0,0 +1,77 @@
+/*******************************************************************************
+ * Copyright (c) 2009 Martin O. J. Schmitz.
+ *
+ * This file is part of the SCHMITZM library - a collection of utility
+ * classes based on Java 1.6, focusing (not only) on Java Swing
+ * and the Geotools library.
+ *
+ * The SCHMITZM project is hosted at:
+ * http://wald.intevation.org/projects/schmitzm/
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 3
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License (license.txt)
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * or try this link: http://www.gnu.org/licenses/lgpl.html
+ *
+ * Contributors:
+ * Martin O. J. Schmitz - initial API and implementation
+ * Stefan A. Krüger - additional utility classes
+ ******************************************************************************/
+package schmitzm.geotools.gui;
+
+
+/**
+ * Diese Klasse stellt ein Ereignis dar, das von einem {@link XMapPane}
+ * ausgeloest wurde (z.B. Aenderung der Aufloesung).
+ * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
+ * @version 1.0
+ */
+public abstract class XMapPaneEvent {
+ /** Beinhaltet das {@link XMapPane}, das das Ereignis ausgeloest hat */
+ protected XMapPane source = null;
+ /** Beinhaltet ein Objekt, das das Ereignis initiiert hat */
+ protected Object sourceObject = null;
+
+ /**
+ * Erzeugt ein neues Ereignis.
+ * @param source {@link XMapPane}, das das Ereignis ausgeloest hat
+ * @param sourceObject Objeckt, das das Ereignis initiiert hat (wenn {@code null},
+ * wird das MapPane als Ausloeser gesetzt)
+ */
+ public XMapPaneEvent(XMapPane source, Object sourceObject) {
+ this.source = source;
+ this.sourceObject = (sourceObject != null) ? sourceObject : source;
+ }
+
+ /**
+ * Erzeugt ein neues Ereignis.
+ * @param source2 {@link XMapPane}, das das Ereignis ausgeloest hat
+ */
+ public XMapPaneEvent(XMapPane source2) {
+ this(source2,null);
+ }
+
+ /**
+ * Liefert das {@link XMapPane}, das das Ereignis ausgeloest hat.
+ */
+ public XMapPane getSource() {
+ return source;
+ }
+
+ /**
+ * Liefert das Object, das das Ereignis initiiert hat.
+ */
+ public Object getSourceObject() {
+ return sourceObject;
+ }
+}
Copied: trunk/src/schmitzm/geotools/gui/XMapPaneMouseListener.java (from rev 736, trunk/src/skrueger/geotools/XMapPaneMouseListener.java)
===================================================================
--- trunk/src/skrueger/geotools/XMapPaneMouseListener.java 2010-03-02 16:22:12 UTC (rev 736)
+++ trunk/src/schmitzm/geotools/gui/XMapPaneMouseListener.java 2010-03-03 10:32:14 UTC (rev 740)
@@ -0,0 +1,191 @@
+package schmitzm.geotools.gui;
+
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.awt.event.MouseEvent;
+import java.awt.event.MouseWheelEvent;
+import java.awt.geom.AffineTransform;
+import java.awt.geom.Point2D;
+import java.util.HashMap;
+import java.util.Map;
+
+import javax.swing.JComponent;
+import javax.swing.KeyStroke;
+
+import org.geotools.geometry.DirectPosition2D;
+
+import schmitzm.swing.event.MouseInputType;
+import schmitzm.swing.event.SelectiveMouseAdapter;
+
+public class XMapPaneMouseListener extends SelectiveMouseAdapter {
+
+ /**
+ * Holds the configuration of which {@link XMapPaneAction} is associated
+ * with which {@link MouseInputType}
+ **/
+ Map<MouseInputType, XMapPaneAction> actions = new HashMap<MouseInputType, XMapPaneAction>(
+ MouseInputType.values().length);
+
+ public void putAction(MouseInputType type, XMapPaneAction action) {
+ actions.put(type, action);
+ }
+
+ /**
+ * A reference to the {@link XMapPane} that the {@link XMapPaneAction}s will
+ * be performed on.
+ */
+ private final XMapPane xMapPane;
+
+ public XMapPaneMouseListener(XMapPane xMapPane) {
+ this.xMapPane = xMapPane;
+ }
+
+ /**
+ * Configures the instance with definitions from a {@link XMapPaneTool}
+ */
+ public void configure(final XMapPaneTool tool) {
+ actions = tool.mouseActions;
+
+ // TODO Remove any KEYSrokes registered previously
+
+ // Adding configured keyboard actions
+ for (final KeyStroke stroke : tool.keyAction.keySet()) {
+ xMapPane.registerKeyboardAction(new ActionListener() {
+
+ public void actionPerformed(final ActionEvent e) {
+ XMapPaneAction action = tool.keyAction.get(stroke);
+ action.performKeyboard(xMapPane, tool.keyActionParams
+ .get(stroke));
+ }
+
+ }, stroke, JComponent.WHEN_IN_FOCUSED_WINDOW);
+ }
+ }
+
+ @Override
+ public void performMouseClicked(MouseEvent mEv) {
+
+ MouseInputType key = null;
+
+ switch (mEv.getButton()) {
+ case MouseEvent.BUTTON1:
+ key = MouseInputType.LClick;
+ break;
+ case MouseEvent.BUTTON3:
+ key = MouseInputType.RClick;
+ break;
+ default:
+ return;
+ }
+
+ XMapPaneAction action = actions.get(key);
+
+ if (action == null) {
+ // No action has been defined for this - no problem
+ return;
+ }
+
+ // Calculate the coordinates in the map's CRS
+ DirectPosition2D coord = XMapPane.getMapCoordinatesFromEvent(mEv);
+
+ /** Call the XMapPaneAction */
+ if (coord != null)
+ action.performClick(xMapPane, mEv, coord);
+ }
+
+ @Override
+ public void performMouseDragged(MouseEvent mEv) {
+
+ MouseInputType key = null;
+
+ switch (dragButton) {
+ case MouseEvent.BUTTON1:
+ key = MouseInputType.LDrag;
+ break;
+ case MouseEvent.BUTTON3:
+ key = MouseInputType.RDrag;
+ break;
+ default:
+ return;
+ }
+
+ XMapPaneAction action = actions.get(key);
+
+ if (action == null) {
+ // No action has been defined for this - no problem
+ return;
+ }
+
+ // Calculate the coordinates in the map's CRS
+ DirectPosition2D endCoord = XMapPane.getMapCoordinatesFromEvent(mEv);
+
+ DirectPosition2D startCoord = getDragStartCoord();
+
+ /** Call the XMapPaneAction */
+ if (startCoord != null && endCoord != null)
+ action.performDragging(xMapPane, mEv, dragStartPos, dragLastPos,
+ startCoord, endCoord);
+ }
+
+ @Override
+ public void performMouseWheelMoved(MouseWheelEvent mEv) {
+
+ XMapPaneAction action = actions.get(MouseInputType.Wheel);
+
+ if (action == null)
+ return;
+
+ // Calculate the coordinates in the map's CRS
+ DirectPosition2D coord = XMapPane.getMapCoordinatesFromEvent(mEv);
+
+ /** Call the XMapPaneAction */
+ if (coord != null)
+ action.performWheel(xMapPane, mEv, coord);
+ }
+
+ public void performMouseReleased(MouseEvent mEv) {
+ MouseInputType key;
+ switch (mEv.getButton()) {
+ case MouseEvent.BUTTON1:
+ key = MouseInputType.LDrag;
+ break;
+ case MouseEvent.BUTTON3:
+ key = MouseInputType.RDrag;
+ break;
+ default:
+ return;
+ }
+
+ XMapPaneAction action = actions.get(key);
+
+ if (action == null)
+ return;
+
+ // Transform window coordinates to MapContext coordinates
+
+ // Calculate the coordinates in the map's CRS
+ DirectPosition2D endCoord = XMapPane.getMapCoordinatesFromEvent(mEv);
+ if (endCoord == null)
+ return;
+
+ action.performDragged(xMapPane, mEv, dragStartPos, dragLastPos,
+ getDragStartCoord(), endCoord);
+ }
+
+ /**
+ * Returns the drag position in map CRS
+ */
+ public DirectPosition2D getDragStartCoord() {
+
+ final AffineTransform at = xMapPane.getScreenToWorld();
+ if (at == null)
+ return null;
+
+ Point2D transformed = at.transform(dragStartPos, null);
+ DirectPosition2D startCoord = new DirectPosition2D(xMapPane
+ .getMapContext().getCoordinateReferenceSystem(), transformed
+ .getX(), transformed.getY());
+ return startCoord;
+ }
+
+}
Property changes on: trunk/src/schmitzm/geotools/gui/XMapPaneMouseListener.java
___________________________________________________________________
Name: svn:mime-type
+ text/plain
Name: svn:keywords
+ Id URL
Name: svn:eol-style
+ native
Copied: trunk/src/schmitzm/geotools/gui/XMapPaneTool.java (from rev 736, trunk/src/skrueger/geotools/XMapPaneTool.java)
===================================================================
--- trunk/src/skrueger/geotools/XMapPaneTool.java 2010-03-02 16:22:12 UTC (rev 736)
+++ trunk/src/schmitzm/geotools/gui/XMapPaneTool.java 2010-03-03 10:32:14 UTC (rev 740)
@@ -0,0 +1,467 @@
+package schmitzm.geotools.gui;
+
+import java.awt.Cursor;
+import java.awt.event.InputEvent;
+import java.awt.event.KeyEvent;
+import java.util.HashMap;
+import java.util.Locale;
+import java.util.Map;
+
+import javax.swing.Icon;
+import javax.swing.ImageIcon;
+import javax.swing.KeyStroke;
+
+import schmitzm.lang.LangUtil;
+import schmitzm.lang.ResourceProvider;
+import schmitzm.swing.SwingUtil;
+import schmitzm.swing.event.MouseInputType;
+import skrueger.geotools.Copyable;
+import skrueger.geotools.MapPaneToolBar;
+import skrueger.geotools.MapView;
+
+/**
+ * This class combines the mapping of mouse-inputs and keyboard inputs to
+ * {@link XMapPaneAction}s and provides a tool icon and a default mouse cursor.
+ */
+public class XMapPaneTool implements Copyable<XMapPaneTool> {
+ public static ResourceProvider RESOURCE = new ResourceProvider(
+ LangUtil.extendPackagePath(MapPaneToolBar.class,
+ "resource.locales.mapPaneToolbar"),
+ Locale.ENGLISH);
+ public static String R(String key, Object... values) {
+ return RESOURCE.getString(key, values);
+ }
+
+ /** The cursor of the mouse if the tool is active **/
+ private Cursor cursor = null;
+
+ /** A tool-tip for the tool , optional **/
+ private String toolTip = null;
+
+ /** The icon for the button **/
+ private Icon icon = null;
+
+ /**
+ * Defines which {@link XMapPaneAction} should be should be called when a
+ * {@link MouseInputType} is triggered
+ **/
+ Map<MouseInputType, XMapPaneAction> mouseActions = new HashMap<MouseInputType, XMapPaneAction>();
+
+ /**
+ * Defines which {@link XMapPaneAction#performKeyboard(XMapPane, Object)}
+ * should be called when a {@link KeyStroke} is triggered
+ **/
+ Map<KeyStroke, XMapPaneAction> keyAction = new HashMap<KeyStroke, XMapPaneAction>();
+
+ /**
+ * Defines which optional parameter should be passed to
+ * {@link XMapPaneAction#performKeyboard(XMapPane, Object)} if a
+ * {@link KeyStroke} is triggered
+ **/
+ Map<KeyStroke, Object> keyActionParams = new HashMap<KeyStroke, Object>();
+
+ /**
+ * The default constructor sets some default keyboard settings
+ */
+ public XMapPaneTool() {
+ initTool();
+ }
+
+ /**
+ * Called by the constructor. Initializes the tool actions by defining default
+ * keyboard actions.
+ */
+ protected void initTool() {
+ // + and - keys zoom
+ keyAction.put(KeyStroke.getKeyStroke(KeyEvent.VK_PLUS, 0),
+ XMapPaneAction.ZOOM_IN);
+ keyAction.put(KeyStroke.getKeyStroke(KeyEvent.VK_MINUS, 0),
+ XMapPaneAction.ZOOM_OUT);
+
+ KeyStroke keyStroke;
+ for (int modifier : new int[] { InputEvent.ALT_DOWN_MASK,
+ InputEvent.ALT_GRAPH_DOWN_MASK,
+ InputEvent.CTRL_DOWN_MASK,
+ InputEvent.SHIFT_DOWN_MASK,
+ InputEvent.META_DOWN_MASK }) {
+ // RIGHT button pan
+ keyStroke = KeyStroke.getKeyStroke(KeyEvent.VK_LEFT, modifier);
+ keyAction.put(keyStroke, XMapPaneAction.PAN);
+ keyActionParams.put(keyStroke, XMapPaneAction_Pan.Direction.RIGHT);
+
+ // LEFT button pan
+ keyStroke = KeyStroke.getKeyStroke(KeyEvent.VK_RIGHT, modifier);
+ keyAction.put(keyStroke, XMapPaneAction.PAN);
+ keyActionParams.put(keyStroke, XMapPaneAction_Pan.Direction.LEFT);
+
+ // UP button pan
+ keyStroke = KeyStroke.getKeyStroke(KeyEvent.VK_DOWN, modifier);
+ keyAction.put(keyStroke, XMapPaneAction.PAN);
+ keyActionParams.put(keyStroke, XMapPaneAction_Pan.Direction.UP);
+
+ // DOWN button pan
+ keyStroke = KeyStroke.getKeyStroke(KeyEvent.VK_UP, modifier);
+ keyAction.put(keyStroke, XMapPaneAction.PAN);
+ keyActionParams.put(keyStroke, XMapPaneAction_Pan.Direction.DOWN);
+ }
+ }
+
+ /**
+ * Returns a copy of the tool to derive other tools.
+ */
+ public XMapPaneTool copy() {
+ return copyTo(null);
+ }
+
+ /**
+ * Copies all actions of this tool to another.
+ * @param tool tool to copy the actions to (if {@code null} a new
+ * tool is created)
+ * @return the modified or created tool
+ */
+ public XMapPaneTool copyTo(XMapPaneTool tool) {
+ if ( tool == null )
+ tool = new XMapPaneTool();
+
+ tool.setCursor( getCursor() );
+ tool.setIcon( getIcon() );
+ tool.setToolTip( getToolTip() );
+ for ( MouseInputType type : mouseActions.keySet() )
+ tool.setMouseAction(type, getMouseAction(type));
+ for ( KeyStroke stroke : keyAction.keySet() )
+ tool.setKeyAction(stroke, getKeyAction(stroke));
+ for ( KeyStroke stroke : keyActionParams.keySet() )
+ tool.setKeyActionParam(stroke, getKeyActionParam(stroke));
+
+ return tool;
+ }
+
+ /**
+ * @return the {@link Cursor} that shall be set as the default mouse cursor
+ * (when no button is clicked)
+ */
+ public Cursor getCursor() {
+ return cursor;
+ }
+
+ /**
+ * @return the {@link Cursor} that shall be set as the default mouse cursor
+ * (when no button is clicked)
+ */
+ public void setCursor(Cursor cursor) {
+ this.cursor = cursor;
+ }
+
+ public String getToolTip() {
+ return toolTip;
+ }
+
+ public void setToolTip(String toolTip) {
+ this.toolTip = toolTip;
+ }
+
+ /**
+ * An icon to use if the tool is associated with a button. May be
+ * <code>null</code>.
+ */
+ public Icon getIcon() {
+ return icon;
+ }
+
+ /**
+ * An icon to use if the tool is associated with a button. May be
+ * <code>null</code>.
+ */
+ public void setIcon(Icon icon) {
+ this.icon = icon;
+ }
+
+ /**
+ * @return The {@link XMapPaneAction} associated with a given
+ * {@link MouseInputType}
+ */
+ public XMapPaneAction getMouseAction(MouseInputType type) {
+ return mouseActions.get(type);
+ }
+
+ /**
+ * Sets the {@link XMapPaneAction} for a given {@link MouseInputType}
+ */
+ public void setMouseAction(MouseInputType type, XMapPaneAction mouseAction) {
+ this.mouseActions.put(type, mouseAction);
+ }
+
+ /**
+ * @return The {@link XMapPaneAction} associated with a {@link KeyStroke}
+ */
+ public XMapPaneAction getKeyAction(KeyStroke keyStroke) {
+ return keyAction.get(keyStroke);
+ }
+
+ /**
+ * Set the {@link XMapPaneAction} for a {@link KeyStroke}
+ */
+ public void setKeyAction(KeyStroke keyStroke, XMapPaneAction keyAction) {
+ this.keyAction.put(keyStroke, keyAction);
+ }
+
+ /**
+ * Get the optional parameter for a{@link XMapPaneAction} when triggered by
+ * {@link KeyStroke}
+ */
+ public Object getKeyActionParam(KeyStroke keyStroke) {
+ return keyActionParams.get(keyStroke);
+ }
+
+ /**
+ * Set the optional parameter for a{@link XMapPaneAction} when triggered by
+ * {@link KeyStroke}
+ */
+ public void setKeyActionParam(KeyStroke keyStroke, Object param) {
+ this.keyActionParams.put(keyStroke, param);
+ }
+
+ /** This {@link XMapPaneTool} does nothing **/
+ public static XMapPaneTool NO_ACTION = new XMapPaneTool();
+ static {
+ // Remove the keyboard mapping that are defined by the default
+ // constructor
+ NO_ACTION.keyAction.clear();
+ NO_ACTION.keyActionParams.clear();
+ }
+
+ /** The configuration of the default ZOOM IN {@link XMapPaneTool} **/
+ public static XMapPaneTool ZOOM_IN = new XMapPaneTool();
+ static {
+ ZOOM_IN.icon = new ImageIcon(
+ MapView.class.getResource("resource/icons/zoom_in.png"));
+ ZOOM_IN.toolTip = R("MapPaneButtons.ZoomIn.TT");
+ ZOOM_IN.cursor = SwingUtil.ZOOMIN_CURSOR;
+
+ // Left mouse click & drag zoom in
+ ZOOM_IN.mouseActions.put(MouseInputType.LClick, XMapPaneAction.ZOOM_IN);
+ ZOOM_IN.mouseActions.put(MouseInputType.LDrag, XMapPaneAction.ZOOM_IN);
+
+ // Right mouse click & drag zoom out
+ ZOOM_IN.mouseActions.put(MouseInputType.RClick, XMapPaneAction.ZOOM_OUT);
+ ZOOM_IN.mouseActions.put(MouseInputType.RDrag, XMapPaneAction.PAN);
+
+ // Mousewheel can zoom too
+ ZOOM_IN.mouseActions.put(MouseInputType.Wheel, XMapPaneAction.ZOOM_IN);
+ }
+
+ /** The configuration of the default ZOOM IN {@link XMapPaneTool} **/
+ public static XMapPaneTool ZOOM_OUT = new XMapPaneTool();
+ static {
+ ZOOM_OUT.icon = new ImageIcon(
+ MapView.class.getResource("resource/icons/zoom_out.png"));
+ ZOOM_OUT.toolTip = R("MapPaneButtons.ZoomOut.TT");
+ ZOOM_OUT.cursor = SwingUtil.ZOOMOUT_CURSOR;
+
+ // Left mouse click & drag zoom in
+ ZOOM_OUT.mouseActions.put(MouseInputType.LClick, XMapPaneAction.ZOOM_OUT);
+ ZOOM_OUT.mouseActions.put(MouseInputType.LDrag, XMapPaneAction.ZOOM_OUT);
+
+ // Right mouse click & drag zoom out
+ ZOOM_OUT.mouseActions.put(MouseInputType.RClick, XMapPaneAction.ZOOM_IN);
+ ZOOM_OUT.mouseActions.put(MouseInputType.RDrag, XMapPaneAction.PAN);
+
+ // Mousewheel can zoom
+ ZOOM_OUT.mouseActions.put(MouseInputType.Wheel, XMapPaneAction.ZOOM_IN);
+
+ }
+
+ /** The configuration of the PAN {@link XMapPaneTool} **/
+ public static final XMapPaneTool PAN = new XMapPaneTool();
+ static {
+ PAN.icon = new ImageIcon(
+ MapView.class.getResource("resource/icons/pan.png"));
+ PAN.toolTip = R("MapPaneButtons.Pan.TT");
+ PAN.cursor = SwingUtil.PAN_CURSOR;
+
+ // Left mouse click & drag zoom in
+ PAN.mouseActions.put(MouseInputType.LClick, XMapPaneAction.PAN);
+ PAN.mouseActions.put(MouseInputType.LDrag, XMapPaneAction.PAN);
+
+ // Right mouse click & drag zoom out
+ PAN.mouseActions.put(MouseInputType.RClick, XMapPaneAction.PAN);
+ PAN.mouseActions.put(MouseInputType.RDrag, XMapPaneAction.PAN);
+
+ // Mousewheel can zoom
+ PAN.mouseActions.put(MouseInputType.Wheel, XMapPaneAction.ZOOM_IN);
+
+ }
+
+ /** A tool that will do a select_top action on the left mouse button **/
+ public static final XMapPaneTool SELECTION_TOP_LAYER = new XMapPaneTool();
+ static {
+ SELECTION_TOP_LAYER.icon = new ImageIcon(
+ MapView.class.getResource("resource/icons/selection_set.png"));
+
+ SELECTION_TOP_LAYER.cursor = SwingUtil.SELECTION_SET_CURSOR;
+
+ // Left mouse click & drag zoom in
+ SELECTION_TOP_LAYER.mouseActions.put(MouseInputType.LClick,
+ XMapPaneAction.SELECT_TOP);
+ SELECTION_TOP_LAYER.mouseActions.put(MouseInputType.LDrag,
+ XMapPaneAction.SELECT_TOP);
+
+ SELECTION_TOP_LAYER.mouseActions.put(MouseInputType.RDrag,
+ XMapPaneAction.PAN);
+
+ // Mousewheel can zoom
+ SELECTION_TOP_LAYER.mouseActions.put(MouseInputType.Wheel,
+ XMapPaneAction.ZOOM_IN);
+
+ // TODO Strg-A shoud select all
+ }
+
+ /** A tool that will do a select_top action on the left mouse button **/
+ public static final XMapPaneTool SELECTION_ONE_FROM_TOP_LAYER = new XMapPaneTool();
+ static {
+ SELECTION_ONE_FROM_TOP_LAYER.icon = new ImageIcon(
+ MapView.class.getResource("resource/icons/selection_set.png"));
+
+ SELECTION_ONE_FROM_TOP_LAYER.cursor = SwingUtil.SELECTION_SET_CURSOR;
+
+ // Left mouse click & drag zoom in
+ SELECTION_ONE_FROM_TOP_LAYER.mouseActions.put(
+ MouseInputType.LClick,
+ XMapPaneAction.SELECT_ONE_FROM_TOP);
+ SELECTION_ONE_FROM_TOP_LAYER.mouseActions.put(
+ MouseInputType.LDrag,
+ XMapPaneAction.SELECT_ONE_FROM_TOP);
+
+ SELECTION_ONE_FROM_TOP_LAYER.mouseActions.put(MouseInputType.RDrag,
+ XMapPaneAction.PAN);
+
+ // Mousewheel can zoom
+ SELECTION_ONE_FROM_TOP_LAYER.mouseActions.put(MouseInputType.Wheel,
+ XMapPaneAction.ZOOM_IN);
+
+ // TODO Strg-A shoud select all
+ }
+
+ /** A tool that will do a select_top action on the left mouse button **/
+ public static final XMapPaneTool SELECTION_ALL_LAYERS = new XMapPaneTool();
+ static {
+ SELECTION_ALL_LAYERS.icon = new ImageIcon(
+ MapView.class.getResource("resource/icons/selection_set.png"));
+
+ SELECTION_ALL_LAYERS.cursor = SwingUtil.SELECTION_SET_CURSOR;
+
+ // Left mouse click & drag zoom in
+ SELECTION_ALL_LAYERS.mouseActions.put(MouseInputType.LClick,
+ XMapPaneAction.SELECT_ALL);
+ SELECTION_ALL_LAYERS.mouseActions.put(MouseInputType.LDrag,
+ XMapPaneAction.SELECT_ALL);
+
+ SELECTION_ALL_LAYERS.mouseActions.put(MouseInputType.RDrag,
+ XMapPaneAction.PAN);
+
+ // Mousewheel can zoom
+ SELECTION_ALL_LAYERS.mouseActions.put(MouseInputType.Wheel,
+ XMapPaneAction.ZOOM_IN);
+
+ // TODO Strg-A shoud select all
+ }
+
+ /** The configuration of the INFO {@link XMapPaneTool} **/
+ public static final XMapPaneTool INFO = new XMapPaneTool();
+
+ static {
+ INFO.icon = new ImageIcon(
+ MapView.class.getResource("resource/icons/info.png"));
+ INFO.toolTip = R("MapPaneButtons.Info.TT");
+ INFO.cursor = SwingUtil.INFO_CURSOR;
+
+ // Left mouse click & drag zoom in
+ INFO.mouseActions.put(MouseInputType.LClick,
+ XMapPaneAction.SELECT_ONE_FROM_TOP);
+ // INFO.mouseActions.put(MouseInputType.LDrag,
+ // XMapPaneAction.SELECT_ONE_FROM_TOP);
+
+ INFO.mouseActions.put(MouseInputType.RDrag, XMapPaneAction.PAN);
+
+ // Mousewheel can zoom
+ INFO.mouseActions.put(MouseInputType.Wheel, XMapPaneAction.ZOOM_IN);
+
+ }
+
+ public static final XMapPaneTool SELECTION_ADD = new XMapPaneTool();
+ static {
+ SELECTION_ADD.icon = new ImageIcon(
+ MapView.class.getResource("resource/icons/selection_add.png"));
+ SELECTION_ADD.toolTip = R("MapPaneButtons.Selection.AddSelection.TT"); // TODO
+ // move
+ // to
+ // schmitzm
+
+ SELECTION_ADD.cursor = SwingUtil.SELECTION_ADD_CURSOR;
+
+ // Left mouse click & drag zoom in
+ SELECTION_ADD.mouseActions.put(MouseInputType.LClick,
+ XMapPaneAction.SELECT_ALL);
+ SELECTION_ADD.mouseActions.put(MouseInputType.LDrag,
+ XMapPaneAction.SELECT_ALL);
+
+ SELECTION_ADD.mouseActions.put(MouseInputType.RDrag, XMapPaneAction.PAN);
+
+ // Mousewheel can zoom
+ SELECTION_ADD.mouseActions.put(MouseInputType.Wheel, XMapPaneAction.ZOOM_IN);
+
+ // TODO Strg-A shoud select all
+ }
+
+ public static final XMapPaneTool SELECTION_REMOVE = new XMapPaneTool();
+ static {
+ SELECTION_REMOVE.icon = new ImageIcon(
+ MapView.class.getResource("resource/icons/selection_remove.png"));
+ SELECTION_REMOVE.toolTip = R("MapPaneButtons.Selection.RemoveSelection.TT"); // TODO
+ // move
+ // to
+ // schmitzm
+
+ SELECTION_REMOVE.cursor = SwingUtil.SELECTION_REMOVE_CURSOR;
+
+ // Left mouse click & drag zoom in
+ SELECTION_REMOVE.mouseActions.put(MouseInputType.LClick,
+ XMapPaneAction.SELECT_ALL);
+ SELECTION_REMOVE.mouseActions.put(MouseInputType.LDrag,
+ XMapPaneAction.SELECT_ALL);
+
+ SELECTION_REMOVE.mouseActions.put(MouseInputType.RDrag, XMapPaneAction.PAN);
+
+ // Mousewheel can zoom
+ SELECTION_REMOVE.mouseActions.put(MouseInputType.Wheel,
+ XMapPaneAction.ZOOM_IN);
+
+ // TODO Strg-A shoud select all
+ }
+
+ public static final XMapPaneTool SELECTION_SET = new XMapPaneTool();
+ static {
+ SELECTION_SET.icon = new ImageIcon(
+ MapView.class.getResource("resource/icons/selection_set.png"));
+ SELECTION_SET.toolTip = R("MapPaneButtons.Selection.SetSelection.TT"); // TODO
+ // move
+ // to
+ // schmitzm
+
+ SELECTION_SET.cursor = SwingUtil.SELECTION_SET_CURSOR;
+
+ // Left mouse click & drag zoom in
+ SELECTION_SET.mouseActions.put(MouseInputType.LClick,
+ XMapPaneAction.SELECT_ALL);
+ SELECTION_SET.mouseActions.put(MouseInputType.LDrag,
+ XMapPaneAction.SELECT_ALL);
+
+ SELECTION_SET.mouseActions.put(MouseInputType.RDrag, XMapPaneAction.PAN);
+
+ // Mousewheel can zoom
+ SELECTION_SET.mouseActions.put(MouseInputType.Wheel, XMapPaneAction.ZOOM_IN);
+
+ // TODO Strg-A shoud select all
+ }
+
+}
Property changes on: trunk/src/schmitzm/geotools/gui/XMapPaneTool.java
___________________________________________________________________
Name: svn:mime-type
+ text/plain
Name: svn:keywords
+ Id URL
Name: svn:eol-style
+ native
Modified: trunk/src/schmitzm/geotools/map/event/FeatureSelectedEvent.java
===================================================================
--- trunk/src/schmitzm/geotools/map/event/FeatureSelectedEvent.java 2010-03-03 01:48:43 UTC (rev 739)
+++ trunk/src/schmitzm/geotools/map/event/FeatureSelectedEvent.java 2010-03-03 10:32:14 UTC (rev 740)
@@ -33,7 +33,7 @@
import org.geotools.map.MapLayer;
import schmitzm.geotools.gui.SelectableXMapPane;
-import skrueger.geotools.XMapPane;
+import schmitzm.geotools.gui.XMapPane;
import com.vividsolutions.jts.geom.Envelope;
Modified: trunk/src/schmitzm/geotools/map/event/GeneralSelectionEvent.java
===================================================================
--- trunk/src/schmitzm/geotools/map/event/GeneralSelectionEvent.java 2010-03-03 01:48:43 UTC (rev 739)
+++ trunk/src/schmitzm/geotools/map/event/GeneralSelectionEvent.java 2010-03-03 10:32:14 UTC (rev 740)
@@ -30,6 +30,7 @@
package schmitzm.geotools.map.event;
import schmitzm.geotools.gui.SelectableXMapPane;
+import schmitzm.geotools.gui.XMapPaneEvent;
import com.vividsolutions.jts.geom.Envelope;
@@ -40,7 +41,7 @@
* @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
* @version 1.0
*/
-public class GeneralSelectionEvent extends MapPaneEvent {
+public class GeneralSelectionEvent extends XMapPaneEvent {
/** Bereich der selektiert wurde. */
protected Envelope envelope = null;
Modified: trunk/src/schmitzm/geotools/map/event/GridCoverageSelectedEvent.java
===================================================================
--- trunk/src/schmitzm/geotools/map/event/GridCoverageSelectedEvent.java 2010-03-03 01:48:43 UTC (rev 739)
+++ trunk/src/schmitzm/geotools/map/event/GridCoverageSelectedEvent.java 2010-03-03 10:32:14 UTC (rev 740)
@@ -33,7 +33,7 @@
import org.geotools.map.MapLayer;
import schmitzm.geotools.gui.SelectableXMapPane;
-import skrueger.geotools.XMapPane;
+import schmitzm.geotools.gui.XMapPane;
import com.vividsolutions.jts.geom.Envelope;
Modified: trunk/src/schmitzm/geotools/map/event/JEditorPaneEvent.java
===================================================================
--- trunk/src/schmitzm/geotools/map/event/JEditorPaneEvent.java 2010-03-03 01:48:43 UTC (rev 739)
+++ trunk/src/schmitzm/geotools/map/event/JEditorPaneEvent.java 2010-03-03 10:32:14 UTC (rev 740)
@@ -32,6 +32,7 @@
import org.geotools.map.MapLayer;
import schmitzm.geotools.gui.JMapEditorPane;
+import schmitzm.geotools.gui.XMapPaneEvent;
import schmitzm.geotools.gui.JMapEditorPane.EditorMode;
/**
@@ -40,7 +41,7 @@
* @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
* @version 1.0
*/
-public abstract class JEditorPaneEvent extends MapPaneEvent {
+public abstract class JEditorPaneEvent extends XMapPaneEvent {
/** Das bearbeitete Layer. */
protected MapLayer layer = null;
/** Bearbeitungs-Modus (zum Zeitpunkt des Events) */
Modified: trunk/src/schmitzm/geotools/map/event/JMapPaneListener.java
===================================================================
--- trunk/src/schmitzm/geotools/map/event/JMapPaneListener.java 2010-03-03 01:48:43 UTC (rev 739)
+++ trunk/src/schmitzm/geotools/map/event/JMapPaneListener.java 2010-03-03 10:32:14 UTC (rev 740)
@@ -31,11 +31,12 @@
// fuer Doku
import schmitzm.geotools.gui.SelectableXMapPane;
+import schmitzm.geotools.gui.XMapPaneEvent;
/**
* Diese Klasse stellt einen Listener fuer Ereignisse des {@link SelectableXMapPane}
* dar (z.B. Aenderung der Aufloesung).
- * @see MapPaneEvent
+ * @see XMapPaneEvent
* @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
* @version 1.0
*/
@@ -44,5 +45,5 @@
* Verarbeitet ein JMapPane-Ereignis.
* @param e Ereignis
*/
- public void performMapPaneEvent(MapPaneEvent e);
+ public void performMapPaneEvent(XMapPaneEvent e);
}
Modified: trunk/src/schmitzm/geotools/map/event/MapAreaChangedEvent.java
===================================================================
--- trunk/src/schmitzm/geotools/map/event/MapAreaChangedEvent.java 2010-03-03 01:48:43 UTC (rev 739)
+++ trunk/src/schmitzm/geotools/map/event/MapAreaChangedEvent.java 2010-03-03 10:32:14 UTC (rev 740)
@@ -30,6 +30,7 @@
package schmitzm.geotools.map.event;
import schmitzm.geotools.gui.SelectableXMapPane;
+import schmitzm.geotools.gui.XMapPaneEvent;
import com.vividsolutions.jts.geom.Envelope;
@@ -39,7 +40,7 @@
* @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
* @version 1.0
*/
-public class MapAreaChangedEvent extends MapPaneEvent {
+public class MapAreaChangedEvent extends XMapPaneEvent {
private Envelope oldEnvelope = null;
private Envelope newEnvelope = null;
Deleted: trunk/src/schmitzm/geotools/map/event/MapPaneEvent.java
===================================================================
--- trunk/src/schmitzm/geotools/map/event/MapPaneEvent.java 2010-03-03 01:48:43 UTC (rev 739)
+++ trunk/src/schmitzm/geotools/map/event/MapPaneEvent.java 2010-03-03 10:32:14 UTC (rev 740)
@@ -1,79 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2009 Martin O. J. Schmitz.
- *
- * This file is part of the SCHMITZM library - a collection of utility
- * classes based on Java 1.6, focusing (not only) on Java Swing
- * and the Geotools library.
- *
- * The SCHMITZM project is hosted at:
- * http://wald.intevation.org/projects/schmitzm/
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public License
- * as published by the Free Software Foundation; either version 3
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License (license.txt)
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- * or try this link: http://www.gnu.org/licenses/lgpl.html
- *
- * Contributors:
- * Martin O. J. Schmitz - initial API and implementation
- * Stefan A. Krüger - additional utility classes
- ******************************************************************************/
-package schmitzm.geotools.map.event;
-
-import schmitzm.geotools.gui.SelectableXMapPane;
-import skrueger.geotools.XMapPane;
-
-/**
- * Diese Klasse stellt ein Ereignis dar, das von einem {@link SelectableXMapPane}
- * ausgeloest wurde (z.B. Aenderung der Aufloesung).
- * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
- * @version 1.0
- */
-public abstract class MapPaneEvent {
- /** Beinhaltet das {@link XMapPane}, das das Ereignis ausgeloest hat */
- protected XMapPane source = null;
- /** Beinhaltet ein Objekt, das das Ereignis initiiert hat */
- protected Object sourceObject = null;
-
- /**
- * Erzeugt ein neues Ereignis.
- * @param source {@link XMapPane}, das das Ereignis ausgeloest hat
- * @param sourceObject Objeckt, das das Ereignis initiiert hat (wenn {@code null},
- * wird das MapPane als Ausloeser gesetzt)
- */
- public MapPaneEvent(XMapPane source, Object sourceObject) {
- this.source = source;
- this.sourceObject = (sourceObject != null) ? sourceObject : source;
- }
-
- /**
- * Erzeugt ein neues Ereignis.
- * @param source2 {@link XMapPane}, das das Ereignis ausgeloest hat
- */
- public MapPaneEvent(XMapPane source2) {
- this(source2,null);
- }
-
- /**
- * Liefert das {@link XMapPane}, das das Ereignis ausgeloest hat.
- */
- public XMapPane getSource() {
- return source;
- }
-
- /**
- * Liefert das Object, das das Ereignis initiiert hat.
- */
- public Object getSourceObject() {
- return sourceObject;
- }
-}
Deleted: trunk/src/schmitzm/geotools/map/event/MapRenderingStateEvent.java
===================================================================
--- trunk/src/schmitzm/geotools/map/event/MapRenderingStateEvent.java 2010-03-03 01:48:43 UTC (rev 739)
+++ trunk/src/schmitzm/geotools/map/event/MapRenderingStateEvent.java 2010-03-03 10:32:14 UTC (rev 740)
@@ -1,27 +0,0 @@
-package schmitzm.geotools.map.event;
-
-import org.opengis.display.canvas.RenderingState;
-
-import skrueger.geotools.XMapPane;
-
-/**
- * Events of this Class are fired, when rendering starts and stops. Cancels and
- * Errors are fired as Stops.
- *
- * @author stefan
- *
- */
-public class MapRenderingStateEvent extends MapPaneEvent {
-
- private final RenderingState state;
-
- public MapRenderingStateEvent(XMapPane source, RenderingState state) {
- super(source);
- this.state = state;
- }
-
- public RenderingState getState() {
- return state;
- }
-
-}
Modified: trunk/src/schmitzm/geotools/map/event/ObjectSelectionEvent.java
===================================================================
--- trunk/src/schmitzm/geotools/map/event/ObjectSelectionEvent.java 2010-03-03 01:48:43 UTC (rev 739)
+++ trunk/src/schmitzm/geotools/map/event/ObjectSelectionEvent.java 2010-03-03 10:32:14 UTC (rev 740)
@@ -32,7 +32,7 @@
import org.geotools.map.MapLayer;
import schmitzm.geotools.gui.SelectableXMapPane;
-import skrueger.geotools.XMapPane;
+import schmitzm.geotools.gui.XMapPane;
import com.vividsolutions.jts.geom.Envelope;
Modified: trunk/src/schmitzm/geotools/map/event/ScaleChangedEvent.java
===================================================================
--- trunk/src/schmitzm/geotools/map/event/ScaleChangedEvent.java 2010-03-03 01:48:43 UTC (rev 739)
+++ trunk/src/schmitzm/geotools/map/event/ScaleChangedEvent.java 2010-03-03 10:32:14 UTC (rev 740)
@@ -30,6 +30,7 @@
package schmitzm.geotools.map.event;
import schmitzm.geotools.gui.SelectableXMapPane;
+import schmitzm.geotools.gui.XMapPaneEvent;
/**
* Diese Klasse stellt ein Ereignis dar, das ein {@link SelectableXMapPane} ausloest,
@@ -37,7 +38,7 @@
* @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
* @version 1.0
*/
-public class ScaleChangedEvent extends MapPaneEvent {
+public class ScaleChangedEvent extends XMapPaneEvent {
private double oldScale = 0;
private double newScale = 0;
Modified: trunk/src/schmitzm/geotools/styling/StylingUtil.java
===================================================================
--- trunk/src/schmitzm/geotools/styling/StylingUtil.java 2010-03-03 01:48:43 UTC (rev 739)
+++ trunk/src/schmitzm/geotools/styling/StylingUtil.java 2010-03-03 10:32:14 UTC (rev 740)
@@ -129,11 +129,11 @@
import schmitzm.geotools.feature.FeatureUtil;
import schmitzm.geotools.feature.FeatureUtil.GeometryForm;
import schmitzm.geotools.grid.GridUtil;
+import schmitzm.geotools.gui.XMapPane;
import schmitzm.io.IOUtil;
import schmitzm.lang.LangUtil;
import skrueger.geotools.StyledFeaturesInterface;
import skrueger.geotools.StyledRasterInterface;
-import skrueger.geotools.XMapPane;
import skrueger.geotools.selection.FeatureMapLayerSelectionSynchronizer;
import com.vividsolutions.jts.geom.Geometry;
Modified: trunk/src/skrueger/geotools/MapPaneToolBar.java
===================================================================
--- trunk/src/skrueger/geotools/MapPaneToolBar.java 2010-03-03 01:48:43 UTC (rev 739)
+++ trunk/src/skrueger/geotools/MapPaneToolBar.java 2010-03-03 10:32:14 UTC (rev 740)
@@ -53,9 +53,10 @@
import org.apache.log4j.Logger;
import schmitzm.geotools.gui.SelectableXMapPane;
+import schmitzm.geotools.gui.XMapPaneEvent;
+import schmitzm.geotools.gui.XMapPaneTool;
import schmitzm.geotools.map.event.JMapPaneListener;
import schmitzm.geotools.map.event.MapAreaChangedEvent;
-import schmitzm.geotools.map.event.MapPaneEvent;
import schmitzm.lang.LangUtil;
import schmitzm.lang.ResourceProvider;
import schmitzm.swing.ButtonGroup;
@@ -208,7 +209,7 @@
// Create a Listener to listen to the zooms on the JMapPane
this.mapPaneListener = new JMapPaneListener() {
- public void performMapPaneEvent(MapPaneEvent e) {
+ public void performMapPaneEvent(XMapPaneEvent e) {
if (!(e instanceof MapAreaChangedEvent))
return;
Modified: trunk/src/skrueger/geotools/RenderingExecutor.java
===================================================================
--- trunk/src/skrueger/geotools/RenderingExecutor.java 2010-03-03 01:48:43 UTC (rev 739)
+++ trunk/src/skrueger/geotools/RenderingExecutor.java 2010-03-03 10:32:14 UTC (rev 740)
@@ -10,11 +10,13 @@
import org.geotools.renderer.RenderListener;
import org.opengis.feature.simple.SimpleFeature;
+import schmitzm.geotools.gui.XMapPane;
+
/**
* This class is used by {@link XMapPane} to start and stop the rendering a
* {@link Thread} for rendering.
*/
-class RenderingExecutor {
+public class RenderingExecutor {
private final static Logger LOGGER = Logger.getLogger(RenderingExecutor.class);
/**
* Instance to a {@link RenderThread} doing any work. It's volatile so the
Deleted: trunk/src/skrueger/geotools/XMapPane.java
===================================================================
--- trunk/src/skrueger/geotools/XMapPane.java 2010-03-03 01:48:43 UTC (rev 739)
+++ trunk/src/skrueger/geotools/XMapPane.java 2010-03-03 10:32:14 UTC (rev 740)
@@ -1,2954 +0,0 @@
-package skrueger.geotools;
-
-import java.awt.Color;
-import java.awt.Cursor;
-import java.awt.Font;
-import java.awt.Graphics;
-import java.awt.Graphics2D;
-import java.awt.Image;
-import java.awt.Point;
-import java.awt.Rectangle;
-import java.awt.RenderingHints;
-import java.awt.event.ActionEvent;
-import java.awt.event.ActionListener;
-import java.awt.event.ComponentAdapter;
-import java.awt.event.ComponentEvent;
-import java.awt.event.MouseEvent;
-import java.awt.event.MouseListener;
-import java.awt.geom.AffineTransform;
-import java.awt.geom.NoninvertibleTransformException;
-import java.awt.geom.Point2D;
-import java.awt.image.BufferedImage;
-import java.io.IOException;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.Map;
-import java.util.Vector;
-
-import javax.swing.JList;
-import javax.swing.Timer;
-import javax.swing.border.Border;
-
-import org.apache.log4j.Logger;
-import org.geotools.data.FeatureSource;
-import org.geotools.data.memory.MemoryFeatureCollection;
-import org.geotools.factory.GeoTools;
-import org.geotools.feature.FeatureCollection;
-import org.geotools.geometry.DirectPosition2D;
-import org.geotools.geometry.jts.JTS;
-import org.geotools.geometry.jts.ReferencedEnvelope;
-import org.geotools.map.DefaultMapContext;
-import org.geotools.map.DefaultMapLayer;
-import org.geotools.map.MapContext;
-import org.geotools.map.MapLayer;
-import org.geotools.map.event.MapLayerEvent;
-import org.geotools.map.event.MapLayerListEvent;
-import org.geotools.map.event.MapLayerListListener;
-import org.geotools.map.event.MapLayerListener;
-import org.geotools.referencing.CRS;
-import org.geotools.renderer.GTRenderer;
-import org.geotools.renderer.label.LabelCacheImpl;
-import org.geotools.renderer.lite.LabelCache;
-import org.geotools.renderer.lite.RendererUtilities;
-import org.geotools.renderer.lite.StreamingRenderer;
-import org.geotools.resources.image.ImageUtilities;
-import org.geotools.styling.Style;
-import org.geotools.swing.JMapPane;
-import org.geotools.swing.event.MapMouseEvent;
-import org.geotools.swing.event.MapPaneListener;
-import org.opengis.display.canvas.RenderingState;
-import org.opengis.feature.simple.SimpleFeature;
-import org.opengis.feature.simple.SimpleFeatureType;
-import org.opengis.referencing.FactoryException;
-import org.opengis.referencing.crs.CoordinateReferenceSystem;
-import org.opengis.referencing.operation.MathTransform;
-import org.opengis.referencing.operation.TransformException;
-
-import schmitzm.geotools.GTUtil;
-import schmitzm.geotools.JTSUtil;
-import schmitzm.geotools.gui.SelectableXMapPane;
-import schmitzm.geotools.io.GeoImportUtil;
-import schmitzm.geotools.map.event.JMapPaneListener;
-import schmitzm.geotools.map.event.MapLayerAdapter;
-import schmitzm.geotools.map.event.MapPaneEvent;
-import schmitzm.geotools.map.event.MapRenderingStateEvent;
-import schmitzm.geotools.styling.StylingUtil;
-import schmitzm.lang.LangUtil;
-import schmitzm.swing.JPanel;
-import schmitzm.swing.SwingUtil;
-import schmitzm.swing.event.MouseInputType;
-
-import com.vividsolutions.jts.geom.Coordinate;
-import com.vividsolutions.jts.geom.Envelope;
-import com.vividsolutions.jts.geom.Geometry;
-
-/**
- * The {@link XMapPane} class uses a Geotools {@link GTRenderer} to paint up to
- * two {@link MapContext}s: a "local" {@link MapContext} and a "background"
- * {@link MapContext}. The idea is, that rendering a background layer made up of
- * e.g. OSM data, may take much longer than rendering local data.<br>
- * Every {@link MapContext} is rendered on a {@link Thread} of it's own.
- * Starting/ cancelling these threads is done by the {@link RenderingExecutor}.<br>
- * <br>
- * While the renderers are rending the map, a <br>
- * The {@link XMapPane} is based on schmitzm {@link JPanel}, so
- * {@link #print(Graphics)} will automatically set the background of components
- * to pure white.
- *
- * The XMapPane has a {@link MouseListener} that manages zooming.<br>
- * A logo/icon to float in the lower left corner may be set with
- * {@link #setMapImage(BufferedImage)}<br>
- *
- * @see SelectableXMapPane - an extension of {@link XMapPane} that supports
- * selecting features.
- *
- * @author stefan
- *
- */
-public class XMapPane extends JPanel {
-
- /**
- * If {@link #maxExtend} is <code>null</code> the following rules are used
- * to create a default maximum.
- * <ul>
- * <li>Values < 0 : don't grow to fit the monitors aspect ratio, no
- * margin</li>
- * <li>Values 0 : grow to fit the monitors aspect ratio, no margin</li>
- * <li>Values > 0 : grow to fit the monitors aspect ratio, and add a
- * relative margin</li>
- * </ul>
- * **/
- private double defaultMaxMapExtendMode = .05;
-
- // private static final int IMAGETYPE = BufferedImage.TYPE_INT_RGB;
- // private static final int IMAGETYPE_withAlpha =
- // BufferedImage.TYPE_INT_ARGB;
- private static final int IMAGETYPE = BufferedImage.TYPE_3BYTE_BGR;
-
- public XMapPaneTool getTool() {
- return tool;
- }
-
- /**
- * If the {@link JPanel} is disabled, it shows nothing and the images are
- * disposed.
- */
- @Override
- public void setEnabled(boolean enabled) {
- super.setEnabled(enabled);
- if (enabled == false)
- disposeImages();
- else
- requestStartRendering();
- }
-
- private static final int IMAGETYPE_withAlpha = BufferedImage.TYPE_4BYTE_ABGR;
-
- private final static Logger LOGGER = Logger.getLogger(XMapPane.class);
-
- /**
- * A flag indicating whether the {@link XMapPane} is accepting repaints from
- * the EDT. @see {@link XMapPane#setPainting(boolean))
- **/
- private boolean acceptsRepaintCalls = true;
-
- /**
- * Main {@link MapContext} that holds all layers that are rendered into the
- * {@link #localImage} by the {@link #localRenderer}
- */
- MapContext localContext;
-
- /**
- * {@link MapContext} holding the background layers. Use it for layers that
- * CAN take very long for rendering, like layer from the Internet: WMS, WFS,
- * OSM...<br>
- * <code>null</code> by default.
- *
- * @see #setBgContext(MapContext)
- * @see #getBgContext()
- */
- MapContext bgContext;
-
- /**
- * While threads are working, calls {@link XMapPane#updateFinalImage()}
- * regularly and {@link #repaint()}. This {@link Timer} is stopped when all
- * renderers have finished.
- *
- * @see INITIAL_REPAINT_DELAYAL
- * @see #REPEATING_REPAINT_DELAY
- */
- final private Timer repaintTimer;
-
- /**
- * The initial delay in milliseconds until the {@link #finalImage} is
- * updated the first time.
- */
- public static final int INITIAL_REPAINT_DELAY = 900;
-
- /**
- * While the {@link #bgExecuter} and {@link #localExecuter} are rendering,
- * the {@link #repaintTimer} is regularly updating the {@link #finalImage}
- * with previews.
- */
- public static final int REPEATING_REPAINT_DELAY = 500;
-
- /**
- * Default delay (milliseconds) before the map will be redrawn when resizing
- * the pane. This is to avoid flickering while drag-resizing.
- *
- * @see #resizeTimer
- */
- public static final int DEFAULT_RESIZING_PAINT_DELAY = 600;
-
- /**
- * This not-repeating {@link Timer} is re-started whenever the component is
- * resized. That means => only if the component is not resizing for
- * {@link #DEFAULT_RESIZING_PAINT_DELAY} milliseconds, does the
- * {@link XMapPane} react.
- */
- private final Timer resizeTimer;
-
- /**
- * Flag for no-tool.
- */
- public static final int NONE = -123;
- //
- // /**
- // * Flag fuer Modus "Kartenausschnitt bewegen". Nicht fuer Window-Auswahl
- // * moeglich!
- // *
- // * @see #setState(int)
- // */
- // public static final int PAN = 1;
- //
- // /**
- // * Flag fuer Modus "Heran zoomen".
- // *
- // * @see #setState(int)
- // * @see #setState(int)
- // */
- // public static final int ZOOM_IN = 2;
- //
- // /**
- // * Flag fuer Modus "Heraus zoomen". Nicht fuer Window-Auswahl moeglich!
- // *
- // * @see #setState(int)
- // */
- // public static final int ZOOM_OUT = 3;
-
- /**
- * {@link Font} used to paint the wait messages into the map
- *
- * @see #addGadgets(Graphics2D, boolean)
- */
- final static Font waitFont = new Font("Arial", Font.BOLD, 28);
-
- /**
- * {@link Font} used to paint error messages into the map
- *
- * @see #addGadgets(Graphics2D, boolean)
- */
- final static Font errorFont = new Font("Arial", Font.BOLD, 13);
-
- /**
- * If last average last two renderings took more than that many ms, show the
- * user a scaled preview
- **/
- private static final long PRESCALE_MINTIME = 230;
-
- /**
- * The wait message painted into the map while rendering is going on on
- * another thread.
- *
- * @see #addGadgets(Graphics2D, boolean)
- */
- final String waitMsg = SwingUtil.R("WaitMess");
-
- /**
- * Konvertiert die Maus-Koordinaten (relativ zum <code>JMapPane</code>) in
- * Karten-Koordinaten.
- *
- * @param e
- * Maus-Ereignis
- */
- public static DirectPosition2D getMapCoordinatesFromEvent(final MouseEvent e) {
- // aktuelle Geo-Position aus GeoMouseEvent ermitteln
- if (e != null && e instanceof MapMouseEvent)
- try {
- return ((MapMouseEvent) e).getMapPosition();
- } catch (final Exception err) {
- LOGGER
- .error(
- "return ((GeoMouseEvent) e).getMapCoordinate(null).toPoint2D();",
- err);
- }
-
- // aktuelle Geo-Position ueber Transformation des JMapPane berechnen
- if (e != null && e.getSource() instanceof XMapPane) {
-
- final XMapPane xMapPane = (XMapPane) e.getSource();
-
- if (!xMapPane.isWellDefined())
- return null;
-
- final AffineTransform at = xMapPane.getScreenToWorld();
- if (at != null) {
- Point2D transformed = at.transform(e.getPoint(), null);
- return new DirectPosition2D(xMapPane.getMapContext()
- .getCoordinateReferenceSystem(), transformed.getX(),
- transformed.getY());
- }
- return null;
- }
- throw new IllegalArgumentException(
- "MouseEvent has to be of instance MapMouseEvent or come from an XMapPane");
- }
-
- /**
- * Listens to changes of the "background" {@link MapContext} and triggers
- * repaints where needed.
- */
- private final MapLayerListListener bgContextListener = new MapLayerListListener() {
-
- @Override
- public void layerAdded(final MapLayerListEvent event) {
- final MapLayer layer = event.getLayer();
- layer.addMapLayerListener(bgMapLayerListener);
- requestStartRendering();
- }
-
- @Override
- public void layerChanged(final MapLayerListEvent event) {
- requestStartRendering();
- }
-
- @Override
- public void layerMoved(final MapLayerListEvent event) {
- requestStartRendering();
- }
-
- @Override
- public void layerRemoved(final MapLayerListEvent event) {
- if (event.getLayer() != null)
- event.getLayer().removeMapLayerListener(bgMapLayerListener);
- requestStartRendering();
- }
- };
-
- /**
- * This {@link RenderingExecutor} manages the creation and cancellation of
- * up to one {@link Thread} for rendering the {@link #localContext}.
- */
- private final RenderingExecutor localExecuter = new RenderingExecutor(this);
-
- /**
- * This {@link RenderingExecutor} manages the creation and cancellation of
- * up to one {@link Thread} for rendering the {@link #bgContext}.
- */
- protected RenderingExecutor bgExecuter;
-
- /**
- * The {@link #localRenderer} for the {@link #localContext} uses this
- * {@link Image}.
- */
- private BufferedImage localImage;
-
- /**
- * The {@link #bgRenderer} for the {@link #bgContext} uses this
- * {@link Image}.
- */
- private BufferedImage bgImage;
-
- /**
- * This {@link Image} is a merge of the {@link #bgImage},
- * {@link #localImage} and {@link #addGadgets(Graphics2D, boolean)}. It is
- * updated with {@link #updateFinalImage()} and used for painting in
- * {@link #paintComponent(Graphics)}
- */
- private BufferedImage finalImage;
-
- /**
- * Optionally a transparent image to paint over the map in the lower right
- * corner.
- *
- * @see #addGadgets(Graphics2D)
- * @see #setMapImage(BufferedImage)
- **/
- private BufferedImage mapImage = null;
-
- /**
- * Listens to each layer in the local {@link MapContext} for changes and
- * triggers repaints.
- */
- protected MapLayerListener bgMapLayerListener = new MapLayerAdapter() {
-
- @Override
- public void layerChanged(final MapLayerEvent event) {
- requestStartRendering();
- }
-
- @Override
- public void layerHidden(final MapLayerEvent event) {
- requestStartRendering();
- }
-
- @Override
- public void layerShown(final MapLayerEvent event) {
- requestStartRendering();
- }
- };
-
- /**
- * A flag indicating if dispose() was already called. If true, then further
- * use of this {@link SelectableXMapPane} is undefined.
- */
- private boolean disposed = false;
-
- /**
- * While dragging, the {@link #updateFinalImage()} method is translating the
- * cached images while setting it together.
- **/
- private final Point imageOrigin = new Point(0, 0);
- /**
- * For every rendering thread started,
- * {@link GTUtil#createGTRenderer(MapContext)} is called to create a new
- * renderer. These Java2D rendering hints are passed to the
- * {@link GTRenderer}. The java2dHints are the same for all renderers (bg
- * and local).
- */
- private RenderingHints java2dHints;
-
- protected LabelCache labelCache = new LabelCacheImpl();
-
- /**
- * Listens to changes of the "local" {@link MapContext} and triggers
- * repaints where needed.
- */
- private final MapLayerListListener localContextListener = new MapLayerListListener() {
-
- @Override
- public void layerAdded(final MapLayerListEvent event) {
- event.getLayer().addMapLayerListener(localMapLayerListener);
-
- getLocalRenderer().setContext(getMapContext());
- requestStartRendering();
-
- }
-
- @Override
- public void layerChanged(final MapLayerListEvent event) {
- // getLocalRenderer().setContext(getMapContext()); geht doch auch
- // ohne?!?!? wow...
- requestStartRendering();
- }
-
- @Override
- public void layerMoved(final MapLayerListEvent event) {
- getLocalRenderer().setContext(getMapContext());
- requestStartRendering();
- }
-
- @Override
- public void layerRemoved(final MapLayerListEvent event) {
- if (event.getLayer() != null)
- event.getLayer().removeMapLayerListener(localMapLayerListener);
- getLocalRenderer().setContext(getMapContext());
- requestStartRendering();
- }
- };
-
- /**
- * Listens to each layer in the local {@link MapContext} for changes and
- * triggers repaints. We don't have to listen layerChanged, because that is
- * already done in {@link #localContextListener}
- */
- protected MapLayerListener localMapLayerListener = new MapLayerAdapter() {
-
- // @Override
- // public void layerChanged(final MapLayerEvent event) {
- // // getLocalRenderer().setContext(getMapContext()); // betters for SLD
- // // // changes?!
- // // requestStartRendering();
- // }
-
- @Override
- public void layerHidden(final MapLayerEvent event) {
- requestStartRendering();
- }
-
- @Override
- public void layerShown(final MapLayerEvent event) {
- requestStartRendering();
- }
- };
-
- final private GTRenderer localRenderer = GTUtil.createGTRenderer();
-
- private final GTRenderer bgRenderer = GTUtil.createGTRenderer();
-
- /**
- * the area of the map to draw
- */
- protected Envelope mapArea = null;
-
- /**
- * A flag set it {@link #setMapArea(Envelope)} to indicated the
- * {@link #paintComponent(Graphics)} method, that the image on-screen is
- * associated with {@link #oldMapArea} and may hence be scaled for a quick
- * preview.<br>
- * The flag is reset
- **/
- private boolean mapAreaChanged = false;
-
- /**
- * This color is used as the default background color when painting a map.
- */
- private Color mapBackgroundColor = null;
-
- /**
- * A flag indicating that the shown image is invalid and needs to be
- * re-rendered.
- */
- protected boolean mapImageInvalid = true;
-
- /**
- * Holds a flag for each layer, whether it is regarded or ignored on
- * {@link #SELECT_TOP}, {@link #SELECT_ALL} and {@link #SELECT_ONE_FROM_TOP}
- * actions.
- */
- final protected HashMap<MapLayer, Boolean> mapLayerSelectable = new HashMap<MapLayer, Boolean>();
-
- /**
- * List of listeners of this {@link XMapPane}
- */
- protected Vector<JMapPaneListener> mapPaneListeners = new Vector<JMapPaneListener>();
- /**
- * If not <code>null</code>, the {@link XMapPane} will not allow to zoom/pan
- * out of that area
- **/
- private Envelope maxExtend = null;
- private Double maxZoomScale = Double.MIN_VALUE;
-
- private Double minZoomScale = Double.MAX_VALUE;
-
- /**
- * We store the old mapArea for a moment to use it for the
- * "quick scaled preview" in case of ZoomOut
- **/
- protected Envelope oldMapArea = null;
-
- /**
- * We store the old transform for a moment to use it for the
- * "quick scaled preview" in case of ZoomIn
- **/
- protected AffineTransform oldScreenToWorld = null;
-
- /**
- * A flag indicating, that the image size has changed and the buffered
- * images are not big enough any more
- **/
- protected boolean paneResized = true;
-
- private BufferedImage preFinalImage;
-
- // ** if 0, no quick preview will be shown **/
- // private int quickPreviewHint = 0;
-
- private Map<Object, Object> rendererHints = GTUtil
- .getDefaultGTRendererHints(getLocalRenderer());
-
- /**
- * If set to <code>true</code>, the {@link #startRenderThreadsTimer} will
- * start rendering {@link Thread}s
- **/
- private volatile Boolean requestStartRendering = false;
-
- /**
- * Transformation zwischen Fenster-Koordinaten und Karten-Koordinaten
- * (lat/lon)
- */
- protected AffineTransform screenToWorld = null;
-
- /**
- * The flag {@link #requestStartRendering} can be set to true by events.
- * This {@link Timer} checks the flag regularly and starts one renderer
- * thread.
- */
- final private Timer startRenderThreadsTimer;
- //
- // /**
- // * The default state is ZOOM_IN, hence by default the
- // * {@link #xMapPaneMouseListener} is also enabled.
- // **/
- // private int state = ZOOM_IN;
- //
- // /**
- // * Manuell gesetzter statischer Cursor, unabhaengig von der aktuellen
- // * MapPane-Funktion
- // */
- // protected Cursor staticCursor = null;
-
- private AffineTransform worldToScreen;
-
- // /**
- // * This {@link MouseListener} is managing all zoom related tasks
- // */
- // private final ZoomXMapPaneMouseListener zoomMapPaneMouseListener = new
- // ZoomXMapPaneMouseListener(
- // this);
-
- /**
- * This {@link MouseListener} is managing all zoom related tasks
- */
- private final XMapPaneMouseListener xMapPaneMouseListener = new XMapPaneMouseListener(
- this);
-
- /** Is set if a renderer has an error **/
- protected ArrayList<Exception> renderingErrors = new ArrayList<Exception>();
-
- /**
- * If <code>true</code>, then rendering exceptions are rendererd into the
- * map pane
- **/
- private boolean showExceptions = false;
-
- public XMapPane() {
- this(null, null);
- }
-
- /**
- * full constructor extending JPanel
- *
- * @param rendererHints
- * may be <code>null</code>. Otherwise a {@link Map<Object,
- * Object>} of {@link RenderingHints} to override the default
- * from {@link GTUtil#getDefaultGTRendererHints(GTRenderer)}
- *
- * @param localContext
- * The main {@link MapContext} to use. If <code>null</code>, an
- * empty {@link DefaultMapContext} will be created.
- */
- public XMapPane(final MapContext localContext_,
- final Map<Object, Object> rendererHints) {
-
- super(true);
-
- stopBlinkTimer = initBlinkTimer();
-
- // A default setting
- RenderingHints hintsJava2d = ImageUtilities.NN_INTERPOLATION_HINT;
- setJava2dHints(hintsJava2d);
-
- setRendererHints(rendererHints);
-
- setOpaque(true);
-
- if (localContext_ != null)
- setLocalContext(localContext_);
-
- /**
- * Adding the #zoomMapPaneMouseListener
- */
- this.addMouseListener(xMapPaneMouseListener);
- this.addMouseMotionListener(xMapPaneMouseListener);
- this.addMouseWheelListener(xMapPaneMouseListener);
-
- // By default the XMapPAne uses the ZOOM_IN tool.
- setTool(XMapPaneTool.ZOOM_IN);
-
- /*
- * We use a Timer object to avoid rendering delays and flickering when
- * the user is drag-resizing the parent container of this map pane.
- *
- * Using a ComponentListener doesn't work because, unlike a JFrame, the
- * pane receives a stream of events during drag-resizing.
- */
- resizeTimer = new Timer(DEFAULT_RESIZING_PAINT_DELAY,
- new ActionListener() {
-
- public void actionPerformed(final ActionEvent e) {
- if (!isWellDefined())
- return;
-
- // LOGGER.debug("resizeTimer performed");
-
- // final Rectangle bounds = getVisibleRect();
- //
- // System.out.println("\n\ntimer performs with bounds = "
- // + bounds);
-
- // final Envelope geoMapArea = tranformWindowToGeo(
- // bounds.x, bounds.y, bounds.x + bounds.width,
- // bounds.y + bounds.height);
-
- paneResized = true;
- if (!setMapArea(getMapArea())) {
- // It's important to request new rendering here.
- // setMapArea only returns true and only calls
- // requestStartRendering if the maparea has changed.
- // But if the component is resized, the maparea
- // doesn't have to change.
- requestStartRendering();
- }
-
- }
- });
- resizeTimer.setRepeats(false);
-
- this.addComponentListener(new ComponentAdapter() {
-
- private Rectangle oldVisibleRect;
-
- @Override
- public void componentResized(final ComponentEvent e) {
-
- // Seems to be called twice with the same size..
- if (oldVisibleRect != null
- && oldVisibleRect.equals(getVisibleRect())) {
- // LOGGER.debug("skipping resize.");
- return;
- }
-
- // LOGGER.debug("resized: " + getVisibleRect());
- resizeTimer.restart();
- oldVisibleRect = getVisibleRect();
- }
-
- });
-
- /*
- * Setting up the repaintTimer. Not started automatically.
- */
- repaintTimer = new Timer(REPEATING_REPAINT_DELAY, new ActionListener() {
-
- @Override
- public void actionPerformed(final ActionEvent e) {
- if ((!localExecuter.isRunning())
- && (bgExecuter != null && !bgExecuter.isRunning())) {
- repaintTimer.stop();
- } else {
- updateFinalImage();
- XMapPane.this.repaint(100);
-
- }
- }
- });
-
- repaintTimer.setInitialDelay(INITIAL_REPAINT_DELAY);
- repaintTimer.setRepeats(true);
-
- /*
- * Setting up the startRenderThreadsTimer. This Timer starts
- * automatically.
- */
- startRenderThreadsTimer = new Timer(100, new ActionListener() {
-
- @Override
- public void actionPerformed(final ActionEvent e) {
- synchronized (requestStartRendering) {
- if (requestStartRendering && isWellDefined() && isEnabled()) {
-
- if (localExecuter.isRunning()) {
- localExecuter.cancelTask();
- } else {
- // Stupidly, but we have to recheck the
- setMapArea(getMapArea());
- requestStartRendering = false;
- startRendering();
- }
- }
- }
- }
- });
- startRenderThreadsTimer.start();
-
- }
-
- /**
- * Propagiert ein Ereignis an alle angeschlossenen Listener. Es gibt
- * verschiedene implementationen von {@link MapPaneEvent}
- *
- * @param e
- * Ereignis
- */
- public void fireMapPaneEvent(MapPaneEvent e) {
- for (JMapPaneListener l : mapPaneListeners)
- l.performMapPaneEvent(e);
- }
-
- /**
- * Fuegt der Map einen Listener hinzu.
- *
- * @param l
- * neuer Listener
- */
- public void addMapPaneListener(final JMapPaneListener l) {
- mapPaneListeners.add(l);
- }
-
- /**
- * Korrigiert den {@link Envelope} aka {@code mapArea} auf die beste
- * erlaubte Flaeche damit die Massstabsbeschaenkungen noch eingehalten
- * werden, FALLS der uebergeben Envelope nicht schon gueltig sein sollte.<br>
- * Since 21. April 09: Before thecalculation starts, the aspect ratio is
- * corrected. This change implies, that setMapArea() will most of the time
- * not allow setting to a wrong aspectRatio.
- *
- * @author <a href="mailto:skpublic at wikisquare.de">Stefan Alfons
- * Krüger</a>
- */
- public ReferencedEnvelope bestAllowedMapArea(ReferencedEnvelope env) {
-
- if (getWidth() == 0)
- return env;
-
- if (env == null)
- return null;
-
- Envelope newArea = null;
-
- /**
- * Correct the aspect Ratio before we check the rest. Otherwise we might
- * easily fail. We allow to grow here, because we don't check against
- * the maxExtend
- */
- final Rectangle curPaintArea = getVisibleRect();
-
- env = JTSUtil.fixAspectRatio(curPaintArea, env, true);
-
- final double scale = env.getWidth() / getWidth();
- final double centerX = env.getMinX() + env.getWidth() / 2.;
- final double centerY = env.getMinY() + env.getHeight() / 2.;
- double newWidth2 = 0;
- double newHeight2 = 0;
- if (scale < getMaxZoomScale()) {
- // ****************************************************************************
- // Wir zoomen weiter rein als erlaubt => Anpassen des envelope
- // ****************************************************************************
- newWidth2 = getMaxZoomScale() * getWidth() / 2.;
- newHeight2 = getMaxZoomScale() * getHeight() / 2.;
- } else if (scale > getMinZoomScale()) {
- // ****************************************************************************
- // Wir zoomen weiter raus als erlaubt => Anpassen des envelope
- // ****************************************************************************
- newWidth2 = getMinZoomScale() * getWidth() / 2.;
- newHeight2 = getMinZoomScale() * getHeight() / 2.;
- } else {
- // ****************************************************************************
- // Die mapArea / der Envelope ist ist gueltig! Keine Aenderungen
- // ****************************************************************************
- newArea = env;
- }
-
- if (newArea == null) {
-
- final Coordinate ll = new Coordinate(centerX - newWidth2, centerY
- - newHeight2);
- final Coordinate ur = new Coordinate(centerX + newWidth2, centerY
- + newHeight2);
-
- newArea = new Envelope(ll, ur);
- }
-
- final Envelope maxAllowedExtend = getMaxExtend();
-
- // This variable is used to break the loop if it runs forever...
- Envelope lastCalculatedArea = null;
- /*
- * If a maxAllowedExtend is set, we have to honour that...
- */
- while (maxAllowedExtend != null && !maxAllowedExtend.contains(newArea)
- && newArea != null && !newArea.isNull()
- && !Double.isNaN(newArea.getMinX())
- && !Double.isNaN(newArea.getMaxX())
- && !Double.isNaN(newArea.getMinY())
- && !Double.isNaN(newArea.getMaxY())) // Due to Double precision
- // problems, this may
- // iterate for ever
- {
-
- if (newArea.equals(lastCalculatedArea))
- break;
- // Check that we are not iterating for ever due to double precision
- // rounding errors
- lastCalculatedArea = newArea;
-
- // Exceeds top? Move down and maybe cut
- if (newArea.getMaxY() > maxAllowedExtend.getMaxY()) {
- final double divY = newArea.getMaxY()
- - maxAllowedExtend.getMaxY();
- // LOGGER.debug("Moving area down by " + divY);
-
- newArea = new Envelope(new Coordinate(newArea.getMinX(),
- newArea.getMinY() - divY), new Coordinate(newArea
- .getMaxX(), newArea.getMaxY() - divY));
-
- if (newArea.getMinY() < maxAllowedExtend.getMinY()) {
- // LOGGER.debug("Now it exeeds the bottom border.. cut!");
- // And cut the bottom if it moved out of the area
- newArea = new Envelope(new Coordinate(newArea.getMinX(),
- maxAllowedExtend.getMinY()), new Coordinate(newArea
- .getMaxX(), newArea.getMaxY()));
-
- // LOGGER.debug("and fix aspect ratio");
-
- newArea = JTSUtil.fixAspectRatio(getVisibleRect(),
- new ReferencedEnvelope(newArea, env
- .getCoordinateReferenceSystem()), false);
- }
- }
-
- // Exceeds bottom? Move up and maybe cut
- if (newArea.getMinY() < maxAllowedExtend.getMinY()) {
- final double divY = newArea.getMinY()
- - maxAllowedExtend.getMinY();
- // LOGGER.debug("Moving area up by " + divY);
-
- newArea = new Envelope(new Coordinate(newArea.getMinX(),
- newArea.getMinY() - divY), new Coordinate(newArea
- .getMaxX(), newArea.getMaxY() - divY));
-
- if (newArea.getMaxY() > maxAllowedExtend.getMaxY()) {
- // LOGGER.debug("Now it exeeds the top border.. cut!");
- // And cut the bottom if it moved out of the area
- newArea = new Envelope(new Coordinate(newArea.getMinX(),
- newArea.getMinY()), new Coordinate(newArea
- .getMaxX(), maxAllowedExtend.getMaxY()));
-
- // LOGGER.debug("and fix aspect ratio");
-
- newArea = JTSUtil.fixAspectRatio(getVisibleRect(),
- new ReferencedEnvelope(newArea, env
- .getCoordinateReferenceSystem()), false);
- }
- }
-
- // Exceeds to the right? move and maybe cut
- if (newArea.getMaxX() > maxAllowedExtend.getMaxX()) {
-
- // Move left..
- final double divX = newArea.getMaxX()
- - maxAllowedExtend.getMaxX();
- // LOGGER.debug("Moving area left by " + divX);
-
- newArea = new Envelope(new Coordinate(newArea.getMinX() - divX,
- newArea.getMinY()), new Coordinate(newArea.getMaxX()
- - divX, newArea.getMaxY()));
-
- if (newArea.getMinX() < maxAllowedExtend.getMinX()) {
- // LOGGER.debug("Now it exeeds the left border.. cut!");
- // And cut the left if it moved out of the area
- newArea = new Envelope(new Coordinate(maxAllowedExtend
- .getMinX(), newArea.getMinY()), new Coordinate(
- newArea.getMaxX(), newArea.getMaxY()));
-
- // LOGGER.debug("and fix aspect ratio");
-
- newArea = JTSUtil.fixAspectRatio(getVisibleRect(),
- new ReferencedEnvelope(newArea, env
- .getCoordinateReferenceSystem()), false);
- }
- }
-
- // Exceeds to the left? move and maybe cut
- if (newArea.getMinX() < maxAllowedExtend.getMinX()) {
-
- // Move right..
- final double divX = newArea.getMinX()
- - maxAllowedExtend.getMinX();
- // LOGGER.debug("Moving area right by " + divX);
-
- newArea = new Envelope(new Coordinate(newArea.getMinX() - divX,
- newArea.getMinY()), new Coordinate(newArea.getMaxX()
- - divX, newArea.getMaxY()));
-
- if (newArea.getMaxX() > maxAllowedExtend.getMaxX()) {
- // LOGGER.debug("Now it exeeds the right border.. cut!");
- // And cut the left if it moved out of the area
- newArea = new Envelope(new Coordinate(newArea.getMinX(),
- newArea.getMinY()), new Coordinate(maxAllowedExtend
- .getMaxX(), newArea.getMaxY()));
-
- // LOGGER.debug("and fix aspect ratio");
-
- newArea = JTSUtil.fixAspectRatio(getVisibleRect(),
- new ReferencedEnvelope(newArea, env
- .getCoordinateReferenceSystem()), false);
- }
- }
-
- }
-
- return new ReferencedEnvelope(newArea, env
- .getCoordinateReferenceSystem());
- }
-
- /**
- * Should be called when the {@link JMapPane} is not needed no more to help
- * the GarbageCollector
- *
- * Removes all {@link JMapPaneListener}s that are registered
- *
- * @author <a href="mailto:skpublic at wikisquare.de">Stefan Alfons
- * Krüger</a>
- */
- public void dispose() {
- if (isDisposed())
- return;
-
- setPainting(false);
-
- resizeTimer.stop();
- startRenderThreadsTimer.stop();
-
- disposed = true;
-
- if (bgExecuter != null) {
- bgExecuter.cancelTask();
- bgExecuter.dispose();
- }
-
- if (localExecuter.isRunning()) {
- int i = 0;
- localExecuter.cancelTask();
- while (i++ < 10 && localExecuter.isRunning()) {
- try {
- Thread.sleep(200);
- } catch (final InterruptedException e) {
- LOGGER
- .warn(
- "while XMapPane we are waiting for the localExcutor to stop",
- e);
- }
- }
- if (localExecuter.isRunning()) {
- LOGGER
- .warn("localExecutor Thread still running after 2s! Continuing anyways...");
- }
- localExecuter.dispose();
- }
-
- disposeImages();
-
- // Remove all mapPaneListeners that have registered with us
- mapPaneListeners.clear();
-
- removeMouseMotionListener(xMapPaneMouseListener);
- removeMouseListener(xMapPaneMouseListener);
-
- if (localContext != null)
- getMapContext().clearLayerList();
- if (bgContext != null)
- getBgContext().clearLayerList();
-
- removeAll();
- }
-
- /**
- * Draws a rectangle in XOR mode from the origin at {@link #startPos} to the
- * given point. All in screen coordinates.
- */
- protected void drawRectangle(final Graphics graphics, final Point startPos,
- final Point e) {
- drawRectangle(graphics, startPos, e, Color.WHITE, false);
- }
-
- /**
- * Draws a rectangle in XOR mode from the origin at {@link #startPos} to the
- * given point. All in screen coordinates.
- */
- protected void drawRectangle(final Graphics graphics, final Point startPos,
- final Point e, Color color, boolean fill) {
-
- if (!isWellDefined())
- return;
-
- // undraw last box/draw new box
- final int left = Math.min(startPos.x, e.x);
- final int right = Math.max(startPos.x, e.x);
- final int top = Math.max(startPos.y, e.y);
- final int bottom = Math.min(startPos.y, e.y);
- final int width = right - left;
- final int height = top - bottom;
-
- if (width == 0 && height == 0)
- return;
-
- graphics.setXORMode(color);
-
- if (fill) {
- graphics.fillRect(left, bottom, width, height);
- graphics.setXORMode(Color.WHITE);
- }
-
- graphics.drawRect(left, bottom, width, height);
- }
-
- /**
- * Diretly paints scaled preview into the {@link SelectableXMapPane}. Used
- * to give the user something to look at while we are rendering. Method
- * should be called after {@link #setMapArea(Envelope)} has been set to the
- * new mapArea and transform has been reset.<br>
- *
- * @param g
- * Graphics2D to paint the preview into
- */
- protected boolean drawScaledPreviewImage_Zoom(final Graphics2D graphics) {
-
- // if (1 == 1)return false;
- // if (quickPreviewHint == 0)
- // return false;
-
- if (oldMapArea == null)
- return false;
-
- if (getPreFinalImage() == null)
- return false;
-
- final Rectangle visibleArea = getVisibleRect();
-
- // Calculate the oldMapArea in the current WindowCoordinates:
- final Envelope oldMapWindow = tranformGeoToWindow(oldMapArea.getMinX(),
- oldMapArea.getMinY(), oldMapArea.getMaxX(), oldMapArea
- .getMaxY());
-
- final int xx1 = (int) Math.round(oldMapWindow.getMinX());
- final int yy1 = (int) Math.round(oldMapWindow.getMinY());
- final int xx2 = (int) Math.round(oldMapWindow.getMaxX());
- final int yy2 = (int) Math.round(oldMapWindow.getMaxY());
-
- graphics.setRenderingHint(RenderingHints.KEY_INTERPOLATION,
- RenderingHints.VALUE_INTERPOLATION_NEAREST_NEIGHBOR);
- graphics.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
- RenderingHints.VALUE_ANTIALIAS_OFF);
- graphics.setRenderingHint(RenderingHints.KEY_RENDERING,
- RenderingHints.VALUE_RENDER_SPEED);
-
- graphics.drawImage(getPreFinalImage(), xx1, yy1, xx2, yy2,
- (int) visibleArea.getMinX(), (int) visibleArea.getMinY(),
- (int) visibleArea.getMaxX(), (int) visibleArea.getMaxY(),
- getMapBackgroundColor(), null);
-
- final Rectangle painedArea = new Rectangle(xx1, yy1, xx2 - xx1, yy2
- - yy1);
-
- SwingUtil.clearAround(graphics, painedArea, visibleArea,
- getMapBackgroundColor());
-
- addGadgets(graphics, true);
-
- // quickPreviewHint = 0;
-
- repaintTimer.restart();
-
- // Something has been drawn
- return true;
- }
-
- public MapContext getBgContext() {
- return bgContext;
- }
-
- /**
- * Lazyly initializes a {@link BufferedImage} for the background renderer.
- */
- private Image getBgImage() {
- if (bgImage == null) {
- bgImage = new BufferedImage(getVisibleRect().width,
- getVisibleRect().height, IMAGETYPE);
- SwingUtil.clearImage(finalImage, getMapBackgroundColor());
- }
-
- return bgImage;
- }
-
- public MapContext getMapContext() {
- if (localContext == null) {
- setLocalContext(new DefaultMapContext());
- }
- return localContext;
- }
-
- private BufferedImage getFinalImage() {
- //
- if (finalImage == null) {
- // Rectangle curPaintArea = getVisibleRect();
- finalImage = new BufferedImage(getVisibleRect().width,
- getVisibleRect().height, IMAGETYPE);
- SwingUtil.clearImage(finalImage, getMapBackgroundColor());
-
- // requestStartRendering();
- }
- return finalImage;
- }
-
- /**
- * Lazyly initializes a {@link BufferedImage} for the background renderer.
- */
- private BufferedImage getLocalImage() {
-
- if (localImage == null) {
- localImage = new BufferedImage(getVisibleRect().width,
- getVisibleRect().height, IMAGETYPE_withAlpha);
- SwingUtil.clearImage(localImage, getMapBackgroundColor());
- }
-
- return localImage;
- }
-
- /**
- * Returns a copy of the mapArea
- *
- * @return
- */
- public ReferencedEnvelope getMapArea() {
- if (mapArea == null) {
- ReferencedEnvelope mapArea_ = null;
- try {
- mapArea_ = localContext.getLayerBounds();
- } catch (final Exception e) {
- LOGGER.warn("localContext.getLayerBounds()", e);
- }
-
- if (mapArea_ == null && bgContext != null) {
- try {
- mapArea_ = bgContext.getLayerBounds();
- } catch (final IOException e) {
- LOGGER.warn("bgContext.getLayerBounds()", e);
- }
- }
-
- if (mapArea_ != null) {
- mapArea = bestAllowedMapArea(mapArea_);
- requestStartRendering();
- }
- }
-
- if (mapArea == null)
- return null;
-
- // TODO is needed at all, this should go to setMapArea maybe
- if (localContext.getCoordinateReferenceSystem() == null)
- try {
- localContext.setCoordinateReferenceSystem(GeoImportUtil
- .getDefaultCRS());
- } catch (final Exception e) {
- throw new RuntimeException("setting context CRS:", e);
- }
-
- return new ReferencedEnvelope(mapArea, localContext
- .getCoordinateReferenceSystem());
- }
-
- /**
- * Returns the background {@link Color} of the map pane. If not set, the
- * methods looks for a parent component and will use its background color.
- * If no parent component is available, WHITE is returned.
- **/
- public Color getMapBackgroundColor() {
- if (mapBackgroundColor == null) {
- if (getParent() != null)
- return getParent().getBackground();
- else
- return Color.WHITE;
- }
- return mapBackgroundColor;
- }
-
- /**
- * Get the BufferedImage to use as a flaoting icon in the lower right
- * corner.
- *
- * @return <code>null</code> if the feature is deactivated.
- */
- public BufferedImage getMapImage() {
- return mapImage;
- }
-
- /**
- * Returns the evelope of the viewable area. The JMapPane will never show
- * anything outside of this extend. If this has been set to
- * <code>null</code> via {@link #setMaxExtend(Envelope)}, it tries to return
- * quickly the context's bounds. It it takes to long to determine the
- * context bounds, <code>null</code> is returned.
- *
- * @param maxExtend
- * <code>null</code> to not have this restriction.
- */
-
- public Envelope getMaxExtend() {
- if (maxExtend == null) {
-
- // The next command may take long time!
- // long start = System.currentTimeMillis();
- final ReferencedEnvelope layerBounds = getVisibleLayoutBounds(localContext);
- //
- // LOGGER.info(
- // (System.currentTimeMillis()-start)+"m to get maxExtend");
- //
- if (layerBounds == null) {
- // // TODO Last fallback could be the CRS valid area
- return null;
- }
-
- return JTSUtil.fixAspectRatio(getVisibleRect(),
- addDefaultMargin(layerBounds), true);
-
- }
- return maxExtend;
- }
-
- public static final String SPECIAL_LINES_LAYER_ID = "SPECIAL_LINES_LAYER_ID";
-
- /**
- * This method ignores sepcial layers like {@link #SPECIAL_LINES_LAYER_ID}
- */
- protected ReferencedEnvelope getVisibleLayoutBounds(MapContext context) {
- ReferencedEnvelope result = null;
- CoordinateReferenceSystem crs = context.getAreaOfInterest()
- .getCoordinateReferenceSystem();
-
- final int length = context.getLayerCount();
- MapLayer layer;
- FeatureSource<SimpleFeatureType, SimpleFeature> fs;
- ReferencedEnvelope env;
- CoordinateReferenceSystem sourceCrs;
-
- for (int i = 0; i < length; i++) {
- layer = context.getLayer(i);
-
- if (!layer.isVisible())
- continue;
-
-
- if (layer.getTitle().equals(SPECIAL_LINES_LAYER_ID))
- continue;
- /*
- * fs = layer.getFeatureSource(); sourceCrs =
- * fs.getSchema().getDefaultGeometry() .getCoordinateSystem(); env =
- * new ReferencedEnvelope(fs.getBounds(), sourceCrs);
- */
-
- env = layer.getBounds();
- if (env == null) {
- continue;
- } else {
- try {
- sourceCrs = env.getCoordinateReferenceSystem();
- if ((sourceCrs != null) && crs != null
- && !CRS.equalsIgnoreMetadata(sourceCrs, crs)) {
- env = env.transform(crs, true);
- }
-
- } catch (FactoryException e) {
- LOGGER
- .warn(
- "Data source and map context coordinate system differ, yet it was not possible to get a projected bounds estimate...",
- e);
- } catch (TransformException e) {
- LOGGER
- .warn(
- "Data source and map context coordinate system differ, yet it was not possible to get a projected bounds estimate...",
- e);
- }
-
- if (result == null) {
- result = env;
- } else {
- result.expandToInclude(env);
- }
- }
- }
-
- return result;
-
- }
-
- /**
- * Retuns the maximum allowed zoom scale. This is the smaller number value
- * of the two. Defaults to {@link Double}.MIN_VALUE
- *
- * @author <a href="mailto:skpublic at wikisquare.de">Stefan Alfons
- * Krüger</a>
- */
- public Double getMaxZoomScale() {
- return maxZoomScale;
- }
-
- /**
- * Retuns the minimum allowed zoom scale. This is the bigger number value of
- * the two. Defaults to {@link Double}.MAX_VALUE
- *
- * @author <a href="mailto:skpublic at wikisquare.de">Stefan Alfons
- * Krüger</a>
- */
- public Double getMinZoomScale() {
- return minZoomScale;
- }
-
- private Image getPreFinalImage() {
- return preFinalImage;
- }
-
- public Map<Object, Object> getRendererHints() {
- // Clear label cache
- labelCache.clear();
- rendererHints.put(StreamingRenderer.LABEL_CACHE_KEY, labelCache);
-
- return rendererHints;
- }
-
- /**
- * Liefert eine affine Transformation, um von den Fenster-Koordinaten in die
- * Karten-Koordinaten (Lat/Lon) umzurechnen.
- *
- * @return eine Kopie der aktuellen Transformation; <code>null</code> wenn
- * noch keine Karte angezeigt wird
- */
- public AffineTransform getScreenToWorld() {
- if (screenToWorld == null)
- resetTransforms();
- // nur Kopie der Transformation zurueckgeben!
- if (screenToWorld == null)
- return null;
- return new AffineTransform(screenToWorld);
- }
-
- // public int getState() {
- // return state;
- // }
- //
- // /**
- // * Liefert den statisch eingestellten Cursor, der unabhaengig von der
- // * eingestellten MapPane-Aktion (Zoom, Auswahl, ...) verwendet wird.
- // *
- // * @return {@code null}, wenn kein statischer Cursor verwendet, sondern
- // der
- // * Cursor automatisch je nach MapPane-Aktion eingestellt wird.
- // */
- // public Cursor getStaticCursor() {
- // return this.staticCursor;
- // }
-
- public AffineTransform getWorldToScreenTransform() {
- if (worldToScreen == null) {
- resetTransforms();
- }
- // nur Kopie der Transformation zurueckgeben!
- return new AffineTransform(worldToScreen);
- }
-
- /**
- * A flag indicating if dispose() has already been called. If true, then
- * further use of this {@link SelectableXMapPane} is undefined.
- */
- private boolean isDisposed() {
- return disposed;
- }
-
- /**
- * Returns whether a layer is regarded or ignored on {@link #SELECT_TOP},
- * {@link #SELECT_ALL} and {@link #SELECT_ONE_FROM_TOP} actions. Returns
- * <code>true</code> if the selectability has not been defined.
- *
- * @param layer
- * a layer
- */
- public boolean isMapLayerSelectable(final MapLayer layer) {
- final Boolean selectable = mapLayerSelectable.get(layer);
- return selectable == null ? true : selectable;
- }
-
- /**
- * Return <code>true</code> if a CRS and a {@link #mapArea} are set and the
- * {@link XMapPane} is visible and has bounds set.
- */
- public boolean isWellDefined() {
- try {
- if (getMapContext() == null)
- return false;
- if (getMapContext().getLayerCount() <= 0)
- return false;
- if (getVisibleRect().getWidth() == 0)
- return false;
- if (getVisibleRect().getHeight() == 0)
- return false;
- // if (getMapArea() == null)
- // return false;
- } catch (final Exception e) {
- return false;
- }
- return true;
- }
-
- /**
- * Usually called from {@link XMapPaneAction_Pan} to pan the image.
- *
- * @param startPos
- * in screen coordinates
- * @param lastPos
- * in screen coordinates
- */
- public void pan(final int dX, final int dY) {
-
- // Panning needs a panning coursor
- if (getCursor() != SwingUtil.PANNING_CURSOR) {
- setCursor(SwingUtil.PANNING_CURSOR);
-
- // While panning, we deactivate the rendering. So the tasks are
- // ready to start when the panning is finished.
- if (bgExecuter != null && bgExecuter.isRunning())
- bgExecuter.cancelTask();
- if (localExecuter.isRunning())
- localExecuter.cancelTask();
- }
- //
- // if (lastPos.x > 0 && lastPos.y > 0) {
- // final int dx = event.getX() - lastPos.x;
- // final int dy = event.getY() - lastPos.y;
-
- // TODO Stop dragging when the drag would not be valid...
- // boolean dragValid = true;
- // // check if this panning results in a valid mapArea
- // {
- // Rectangle winBounds = xMapPane.getBounds();
- // winBounds.translate(xMapPane.imageOrigin.x,
- // -xMapPane.imageOrigin.y);
- // Envelope newMapAreaBefore = xMapPane.tranformWindowToGeo(
- // winBounds.x, winBounds.y, winBounds.x
- // + winBounds.width, winBounds.y
- // + winBounds.height);
- //
- //
- // winBounds = xMapPane.getBounds();
- // Point testIng = new Point(xMapPane.imageOrigin);
- // testIng.translate(dx, dy);
- // winBounds.translate(testIng.x, -testIng.y);
- // Envelope newMapAreaAfter = xMapPane.tranformWindowToGeo(
- // winBounds.x, winBounds.y, winBounds.x
- // + winBounds.width, winBounds.y
- // + winBounds.height);
- //
- // // If the last drag doesn't change the MapArea anymore cancel
- // it.
- // if (xMapPane.bestAllowedMapArea(newMapAreaAfter).equals(
- // xMapPane.bestAllowedMapArea(newMapAreaBefore))){
- // dragValid = false;
- // return;
- // }
- // }
-
- getImageOrigin().translate(dX, dY);
- updateFinalImage();
- repaint();
- // }
-
- // } else if ((getState() == XMapPane.ZOOM_IN)
- // || (getState() == XMapPane.ZOOM_OUT)
- // || (getState() == XMapPane.SELECT_ALL)
- // || (getState() == XMapPane.SELECT_TOP)) {
- //
- // // Draws a rectangle
- // final Graphics2D graphics = (Graphics2D) getGraphics();
- // drawRectangle(graphics, startPos, event.getPoint());
- // if ((lastPos.x > 0) && (lastPos.y > 0))
- // drawRectangle(graphics, startPos, lastPos);
- // graphics.dispose();
- // }
- }
-
- /**
- * Called by the {@link RenderingExecutor} when rendering was cancelled.
- */
- public void onRenderingCancelled() {
- // LOGGER.debug("Rendering cancelled");
- repaintTimer.stop();
-
- // Inform listeners that rendering has completed if have no requests to
- // start again
- if (!requestStartRendering)
- fireMapPaneEvent(new MapRenderingStateEvent(this,
- RenderingState.ON_HOLD));
- }
-
- /**
- * Called by the {@link RenderingExecutor} when rendering has been
- * completed.
- *
- * @param l
- * long ms the rendering took
- */
- public void onRenderingCompleted(final long l) {
- lastRenderingDuration = (lastRenderingDuration + l) / 2;
- // LOGGER
- // .debug("complete rendering after " + lastRenderingDuration
- // + "ms");
-
- repaintTimer.stop();
-
- // We "forget" about an exception every time we complete a rendering
- // thread successfully
- if (renderingErrors.size() > 0)
- renderingErrors.remove(0);
-
- updateFinalImage();
- repaint();
-
- // Inform listeners that rendering has completed if have no requests to
- // start again
- if (!requestStartRendering)
- fireMapPaneEvent(new MapRenderingStateEvent(this,
- RenderingState.ON_HOLD));
- }
-
- /**
- * Called by the {@linkplain XMapPane.RenderingTask} when rendering failed.
- * Publishes a {@linkplain MapPaneEvent} of type {@code
- * MapPaneEvent.Type.RENDERING_STOPPED} to listeners.
- *
- * @param renderingError
- * The error that occured during rendering
- *
- * @see MapPaneListener#onRenderingStopped(org.geotools.swing.event.MapPaneEvent)
- */
- public void onRenderingFailed(final Exception renderingError) {
-
- // Store the exceptions so we can show it to the user:
- if (!(renderingError instanceof java.lang.IllegalArgumentException && renderingError
- .getMessage().equals(
- "Argument \"sourceCRS\" should not be null.")))
- this.renderingErrors.add(renderingError);
- if (renderingErrors.size() > 3)
- renderingErrors.remove(0);
-
- repaintTimer.stop();
-
- LOGGER.warn("Rendering failed", renderingError);
- updateFinalImage();
- repaint();
-
- // Inform listeners that rendering has completed if have no requests to
- // start again
- if (!requestStartRendering)
- fireMapPaneEvent(new MapRenderingStateEvent(this,
- RenderingState.ON_HOLD));
- }
-
- @Override
- protected void paintComponent(final Graphics g) {
-
- // Maybe update the cursor and maybe stop the repainting timer
- updateCursor();
-
- if (!acceptsRepaintCalls)
- return;
-
- if (!isWellDefined())
- return;
- //
- // if (paneResized) {
- // // ((Graphics2D) g).setBackground(getMapBackgroundColor());
- // // g.clearRect(0, 0, getVisibleRect().width,
- // getVisibleRect().height);
- // return;
- // }
-
- // super.paintComponent(g); // candidate for removal
-
- boolean paintedSomething = false;
-
- if (mapImageInvalid) { /* if the map changed then redraw */
-
- mapImageInvalid = false; // Reset for next round
-
- // If the new mapArea and the oldMapArea intersect, we can draw some
- // quick scaled preview to make the user feel that something is
- // happening.
- if (lastRenderingDuration > PRESCALE_MINTIME && mapAreaChanged
- && oldMapArea != null
- && getMapArea().intersects(oldMapArea)
- && !getMapArea().equals(oldMapArea) && !paneResized) {
-
- mapAreaChanged = false;
-
- // if (getMapArea().covers(oldMapArea)) {
- // // quickPreviewHint = ZOOM_OUT;
- // paintedSomething = drawScaledPreviewImage_Zoom((Graphics2D)
- // g);
- // } else if (oldMapArea.covers(getMapArea())) {
- // quickPreviewHint = ZOOM_IN;
- paintedSomething = drawScaledPreviewImage_Zoom((Graphics2D) g);
- // }
- }
- }
-
- if (!paintedSomething) {
-
- g.drawImage(getFinalImage(), 0, 0, null);
-
- blink((Graphics2D) g);
-
- paintedSomething = true; // cand. for removal
- }
-
- }
-
- /**
- * If {@link #blinkRenderer} is not <code>null</code>, the blinking features
- * are rendered into the {@link Graphics2D}
- */
- private void blink(Graphics2D g2d) {
- if (blinkRenderer != null) {
- g2d.translate(getImageOrigin().x, getImageOrigin().y);
- blinkRenderer.paint(g2d, getVisibleRect(), getMapArea());
- }
- }
-
- /**
- * Heavily works on releasing all resources related to the four
- * {@link Image}s used to cache the results of the different renderers.<br>
- * In November 2009 i had some memory leaking problems with {@link XMapPane}
- * . The resources of the buffered images were never released. It seem to be
- * important to call the GC right after flushing the images.<br>
- * Hence this method may take a while, because it calls the GC up to four
- * times.
- */
- private void disposeImages() {
-
- // System.out.println("vorher = "
- // + new MbDecimalFormatter().format(LangUtil.gcTotal()));
- // bi.flush();
- // return bi = null;
- // System.out.println("nacher = "
- // + new MbDecimalFormatter().format(LangUtil.gcTotal()));
- //
- // System.out.println("\n");
-
- if (preFinalImage != null) {
- preFinalImage.flush();
- preFinalImage = null;
- LangUtil.gc();
- }
- if (finalImage != null) {
- finalImage.flush();
- finalImage = null;
- LangUtil.gc();
- }
- if (localImage != null) {
- localImage.flush();
- localImage = null;
- LangUtil.gc();
- }
- if (bgImage != null) {
- bgImage.flush();
- bgImage = null;
- LangUtil.gc();
- }
-
- }
-
- //
- // /**
- // * Performs a {@value #PAN} action. During panning, the displacement is
- // * stored in {@link #imageOrigin} object. Calling {@link #performPan()}
- // will
- // * reset the offset and call {@link #setMapArea(Envelope)}.
- // */
- // public void performPan() {
- //
- // final Rectangle winBounds = getVisibleRect();
- //
- // winBounds.translate(-imageOrigin.x, -imageOrigin.y);
- // final Envelope newMapArea = tranformWindowToGeo(winBounds.x,
- // winBounds.y, winBounds.x + winBounds.width, winBounds.y
- // + winBounds.height);
- //
- // imageOrigin.x = 0;
- // imageOrigin.y = 0;
- //
- // if (!setMapArea(newMapArea)) {
- // /**
- // * If setMapArea returns true, the finalImage is updated anyways.
- // * This if-case exists to ensure that we repaint a correct image
- // * even if the new panning area has been denied.
- // */
- // updateFinalImage();
- // repaint();
- // }
- //
- // if (getCursor() == SwingUtil.PANNING_CURSOR)
- // setCursor(SwingUtil.PAN_CURSOR);
- // }
-
- /**
- * Entfernt einen Listener von der Map.
- *
- * @param l
- * zu entfernender Listener
- */
- public void removeMapPaneListener(final JMapPaneListener l) {
- mapPaneListeners.remove(l);
- }
-
- /**
- * Cancels all running renderers and sets the flag to start new ones. <br>
- *
- * @see #startRenderThreadsTimer
- */
- private void requestStartRendering() {
- if (bgExecuter != null)
- bgExecuter.cancelTask();
-
- localExecuter.cancelTask();
-
- mapImageInvalid = true;
- if (paneResized) {
- paneResized = false;
- disposeImages();
- }
- requestStartRendering = true;
-
- }
-
- /**
- * Calculate the affine transforms used to convert between world and pixel
- * coordinates. The calculations here are very basic and assume a cartesian
- * reference system.
- * <p>
- * Tne transform is calculated such that {@code envelope} will be centred in
- * the display
- *
- * @param envelope
- * the current map extent (world coordinates)
- * @param paintArea
- * the current map pane extent (screen units)
- */
- private void resetTransforms() {
- // System.out
- // .println("paintArea in resetTeansofrms = " + getVisibleRect());
- if (!isWellDefined())
- return;
-
- if (mapArea == null)
- return;
-
- final ReferencedEnvelope refMapEnv = new ReferencedEnvelope(mapArea,
- getMapContext().getCoordinateReferenceSystem());
-
- worldToScreen = RendererUtilities.worldToScreenTransform(refMapEnv,
- getVisibleRect());
-
- try {
- screenToWorld = worldToScreen.createInverse();
-
- } catch (final NoninvertibleTransformException ex) {
- LOGGER
- .error("can't invert worldToScreen to get screenToWorld!",
- ex);
- }
- }
-
- public void setBgContext(final MapContext context) {
-
- // Remove the default listener from the old context
- if (this.bgContext != null) {
- this.bgContext.removeMapLayerListListener(bgContextListener);
-
- // adding listener to all layers
- for (final MapLayer mapLayer : bgContext.getLayers()) {
- mapLayer.removeMapLayerListener(bgMapLayerListener);
- }
- }
-
- this.bgContext = context;
-
- if (context != null) {
- // setMapArea(bgContext.getAreaOfInterest());
-
- this.bgContext.addMapLayerListListener(bgContextListener);
-
- // adding listener to all layers
- for (final MapLayer mapLayer : bgContext.getLayers()) {
- mapLayer.addMapLayerListener(bgMapLayerListener);
- }
- }
-
- requestStartRendering();
- }
-
- public void setJava2dHints(final RenderingHints java2dHints) {
- this.java2dHints = java2dHints;
- }
-
- public void setLocalContext(final MapContext context) {
- // Remove the default listener from the old context
- if (this.localContext != null) {
- this.localContext.removeMapLayerListListener(localContextListener);
-
- // adding listener to all layers
- for (final MapLayer mapLayer : localContext.getLayers()) {
- mapLayer.removeMapLayerListener(localMapLayerListener);
- }
- }
-
- this.localContext = context;
-
- if (context != null) {
-
- // setMapArea(localContext.getAreaOfInterest());
-
- getLocalRenderer().setContext(localContext);
-
- this.localContext.addMapLayerListListener(localContextListener);
-
- // adding listener to all layers
- for (final MapLayer mapLayer : localContext.getLayers()) {
- mapLayer.addMapLayerListener(localMapLayerListener);
- }
- }
-
- requestStartRendering();
-
- }
-
- public void setBorder(final Border b) {
- super.setBorder(b);
- }
-
- /**
- * Triggers to repaint (fast) and re-render (slow) the JMapPane.
- */
- public void refresh() {
- mapImageInvalid = true;
- repaint();
- }
-
- // /**
- // * Triggers to use new {@link GTRenderer} and refresh the map. Should be
- // * called after {@link Style}s have been changed because GTRenderer is
- // * otherwise not working well.
- // */
- // public void refreshRenderers() {
- // localRenderer = GTUtil.createGTRenderer();
- // setLocalContext(getMapContext());
- // mapImageInvalid = true;
- // repaint();
- // }
-
- /**
- * Set the new map area.
- *
- * @param newMapArea
- * @return <code>true</code> if the mapArea has been changed and a repaint
- * has been triggered.
- */
- public boolean setMapArea(final Envelope newMapArea) {
- if (newMapArea == null)
- return false;
- if (getMapContext().getCoordinateReferenceSystem() == null)
- return false;
- return setMapArea(new ReferencedEnvelope(newMapArea, getMapContext()
- .getCoordinateReferenceSystem()));
- }
-
- /**
- * Set the new map area.
- *
- * @param newMapArea
- * @return <code>true</code> if the mapArea has been changed and a repaint
- * has been triggered.
- */
- public boolean setMapArea(final ReferencedEnvelope newMapArea) {
-
- if (newMapArea == null
- || bestAllowedMapArea(newMapArea).equals(mapArea)) {
- // No change.. no need to repaint
- return false;
- }
-
- // Testing, whether NaN or Infinity are used in the newMapArea
- if (newMapArea.isNull() || Double.isInfinite(newMapArea.getMaxX())
- || Double.isInfinite(newMapArea.getMaxY())
- || Double.isInfinite(newMapArea.getMinX())
- || Double.isInfinite(newMapArea.getMinY())) {
- // No change.. ugly new values
- LOGGER.warn("setMapArea has been called with newArea = "
- + newMapArea);
- return false;
- }
-
- final Envelope candNew = bestAllowedMapArea(newMapArea);
-
- // Testing, whether the difference if just minimal
- if (mapArea != null) {
- final double tolX = mapArea.getWidth() / 1000.;
- final double tolY = mapArea.getHeight() / 1000.;
- if ((candNew.getMinX() - tolX < mapArea.getMinX())
- && (mapArea.getMinX() < candNew.getMinX() + tolX)
- && (candNew.getMaxX() - tolX < mapArea.getMaxX())
- && (mapArea.getMaxX() < candNew.getMaxX() + tolX)
-
- && (candNew.getMinY() - tolY < mapArea.getMinY())
- && (mapArea.getMinY() < candNew.getMinY() + tolY)
- && (candNew.getMaxY() - tolY < mapArea.getMaxY())
- && (mapArea.getMaxY() < candNew.getMaxY() + tolY)
-
- ) {
- // The two mapAreas only differ my 1/1000th.. ignore
-
- return false;
- }
- }
-
- // New map are is accepted:
- oldMapArea = mapArea;
- mapArea = candNew;
- resetTransforms();
-
- if (localContext != null) {
- localContext.setAreaOfInterest(mapArea, localContext
- .getCoordinateReferenceSystem());
- }
- if (bgContext != null) {
- bgContext.setAreaOfInterest(mapArea, localContext
- .getCoordinateReferenceSystem());
- }
-
- mapAreaChanged = true;
-
- repaint(200); // Do not remove it!
-
- requestStartRendering();
-
- return true;
- }
-
- /**
- * Set the background color of the map.
- *
- * @param if <code>null</code>, white is used.
- */
- public void setMapBackgroundColor(final Color bgColor) {
- this.mapBackgroundColor = bgColor;
- }
-
- /**
- * Set the BufferedImage to use as a flaoting icon in the lower right corner
- *
- * @param mapImageIcon
- * <code>null</code> is allowed and deactivates this icon.
- */
- public void setMapImage(final BufferedImage mapImage) {
- this.mapImage = mapImage;
- }
-
- /**
- * Sets whether a layer is regarded or ignored on {@link #SELECT_TOP},
- * {@link #SELECT_ALL} and {@link #SELECT_ONE_FROM_TOP} actions.
- *
- * @param layer
- * a layer
- * @param selectable
- * if {@code false} the layer is ignored during the upper
- * mentioned actions. If <code>null</code>, the default (true)
- * will be used.
- */
- public void setMapLayerSelectable(final MapLayer layer,
- final Boolean selectable) {
- if (selectable == null)
- mapLayerSelectable.remove(layer);
- else
- mapLayerSelectable.put(layer, selectable);
- }
-
- /**
- * Defines an evelope of the viwable area. The JMapPane will never show
- * anything outside of this extend.
- *
- * @param maxExtend
- * <code>null</code> to not have this restriction.
- */
- public void setMaxExtend(final Envelope maxExtend) {
- this.maxExtend = maxExtend;
- }
-
- /**
- * Set the maximum allowed zoom scale. This is the smaller number value of
- * the two. If <code>null</code> is passed, Double.MINVALUE are used which
- * mean there is no restriction.
- *
- * @author <a href="mailto:skpublic at wikisquare.de">Stefan Alfons
- * Krüger</a>
- */
- public void setMaxZoomScale(final Double maxZoomScale) {
- this.maxZoomScale = maxZoomScale == null ? Double.MIN_VALUE
- : maxZoomScale;
- }
-
- // /** Stored the time used for the last real rendering in ms. **/
- private long lastRenderingDuration = 1000;
- private XMapPaneTool tool = null;
-
- private Timer stopBlinkTimer;
-
- private StreamingRenderer blinkRenderer;
-
- /**
- * Set the minimum (nearest) allowed zoom scale. This is the bigger number
- * value of the two. If <code>null</code> is passed, Double.MAXVALUE are
- * used which mean there is no restriction.
- *
- *
- * @author <a href="mailto:skpublic at wikisquare.de">Stefan Alfons
- * Krüger</a>
- */
- public void setMinZoomScale(final Double minZoomScale) {
- this.minZoomScale = minZoomScale == null ? Double.MAX_VALUE
- : minZoomScale;
- }
-
- /**
- * If <code>true</code>, allow the {@link XMapPane} to process #repaint()
- * requests. Otherwise the map will not paint anything and not start any
- * rendering {@link Thread}s.
- */
- public void setPainting(final boolean b) {
- acceptsRepaintCalls = b;
- if (acceptsRepaintCalls == true)
- repaint();
- }
-
- private void setRendererHints(final Map<Object, Object> rendererHints) {
- if (rendererHints != null)
- this.rendererHints = rendererHints;
- }
-
- // @Deprecated
- // public void setState(final int state) {
- // this.state = state;
- //
- // // throw new RuntimeException("Old concept.. migrate to new concept!");
- //
- // // xMapPaneMouseListener.setEnabled((state == ZOOM_IN
- // // || state == ZOOM_OUT || state == PAN));
- //
- // // Je nach Aktion den Cursor umsetzen
- // updateCursor();
- // }
-
- public void configureMouse(MouseInputType type, XMapPaneAction action) {
- xMapPaneMouseListener.actions.put(type, action);
- }
-
- /**
- * Configure the {@link XMapPaneTool} that active on the map. Passing
- * <code>null</code> will set the NO_ACTION tool.
- */
- public void setTool(XMapPaneTool tool) {
- if (tool == null)
- tool = XMapPaneTool.NO_ACTION;
- this.tool = tool;
- xMapPaneMouseListener.configure(tool);
- setCursor(tool.getCursor());
- }
-
- // /**
- // * Standardmaessig wird der Cursor automatisch je nach MapPane-Aktion
- // (Zoom,
- // * Auswahl, ...) gesetzt. Mit dieser Methode kann ein statischer Cursor
- // * gesetzt werden, der unabhaengig von der aktuellen MapPanes-Aktion
- // * beibehalten wird. Um diesen statischen Cursor wieder zu entfernen, kann
- // * {@code null} als Parameter uebergeben werden
- // *
- // * @param cursor
- // * Cursor
- // */
- // public void setStaticCursor(final Cursor cursor) {
- // this.staticCursor = cursor;
- // if (cursor != null)
- // super.setCursor(cursor);
- // }
-
- /**
- * Starts rendering on one or two threads
- */
- private void startRendering() {
-
- if (!isWellDefined() || !acceptsRepaintCalls) {
- // if we are not ready to start rendering, try it again the next
- // time the timer is chacking the flag.
- requestStartRendering = true;
- return;
- }
-
- if (bgExecuter != null) {
- // Stop all renderers
- bgExecuter.cancelTask();
- }
-
- localExecuter.cancelTask();
-
- // Inform listeners that rendering has completed if have no requests to
- // start again
- if (!requestStartRendering)
- fireMapPaneEvent(new MapRenderingStateEvent(this,
- RenderingState.RENDERING));
-
- final Rectangle curPaintArea = getVisibleRect();
-
- /**
- * We have to set new renderer
- */
-
- if (getBgContext() != null) {
- bgRenderer.setJava2DHints(getJava2dHints());
- bgRenderer.setRendererHints(getRendererHints());
-
- // bgExecuter = new RenderingExecutor();
- // LOGGER.debug("starting bg renderer:");
- // // /* System.out.println("rendering"); */
- // final GTRenderer createGTRenderer = GTUtil.createGTRenderer(
- // bgContext, getRendererHints());
- // createGTRenderer.setJava2DHints(getJava2dHints());
- // bgExecuter.submit(getBgContext().getAreaOfInterest(),
- // curPaintArea,
- // (Graphics2D) getBgImage().getGraphics(), createGTRenderer);
- }
-
- if (getMapContext() != null) {
- // localExecuter = new RenderingExecutor(this, 150l);
- // LOGGER.debug("starting local renderer:");
-
- getLocalRenderer().setJava2DHints(getJava2dHints());
- getLocalRenderer().setRendererHints(getRendererHints());
-
- final boolean submitted = localExecuter.submit(getMapArea(),
- curPaintArea, (Graphics2D) getLocalImage().getGraphics(),
- getLocalRenderer());
- if (submitted)
- repaintTimer.restart();
- else
- requestStartRendering = true; // Try to start rendering
- // again in
- // a moment
- }
-
- updateCursor();
- }
-
- private RenderingHints getJava2dHints() {
- return java2dHints;
- }
-
- /**
- * Transformiert einen Geo-Koordinaten-Bereich in Fenster-Koordinaten.
- *
- * @param ox
- * X-Koordinate der VON-Position
- * @param oy
- * Y-Koordinate der VON-Position
- * @param px
- * X-Koordinate der BIS-Position
- * @param py
- * Y-Koordinate der BIS-Position
- */
- public Envelope tranformGeoToWindow(final double ox, final double oy,
- final double px, final double py) {
- final AffineTransform at = getWorldToScreenTransform();
- Point2D geoO;
- // try {
- geoO = at.transform(new Point2D.Double(ox, oy), null);
- final Point2D geoP = at.transform(new Point2D.Double(px, py), null);
- return new Envelope(geoO.getX(), geoP.getX(), geoO.getY(), geoP.getY());
- // } catch (final NoninvertibleTransformException e) {
- // LOGGER.error(e);
- // return new Envelope(ox, oy, px, py);
- // }
- }
-
- /**
- * Transformiert einen Geo-Koordinate in eine Fenster-Koordinaten.
- *
- * @param x
- * X-Koordinate der VON-Position
- * @param y
- * Y-Koordinate der VON-Position
- */
- public Point2D tranformGeoToWindow(final double x, final double y) {
- return getWorldToScreenTransform().transform(new Point2D.Double(x, y),
- null);
- }
-
- /**
- * Transformiert einen Fenster-Koordinaten-Bereich in Geo-Koordinaten.
- *
- * @param ox
- * X-Koordinate der VON-Position
- * @param oy
- * Y-Koordinate der VON-Position
- * @param px
- * X-Koordinate der BIS-Position
- * @param py
- * Y-Koordinate der BIS-Position
- */
- public Envelope tranformWindowToGeo(final int ox, final int oy,
- final int px, final int py) {
- final AffineTransform at = getScreenToWorld();
- final Point2D geoO = at.transform(new Point2D.Double(ox, oy), null);
- final Point2D geoP = at.transform(new Point2D.Double(px, py), null);
-
- // Mmmmm... don't really understand why its x,x,y,y
- // return new Envelope(geoO.getX(), geoP.getX(), geoO.getY(),
- // geoP.getY());
- return new Envelope(new Coordinate(geoO.getX(), geoO.getY()),
- new Coordinate(geoP.getX(), geoP.getY()));
- }
-
- /**
- * Will update the cursor. If all rendering is finished also stops the
- * {@link #repaintTimer}
- */
- public void updateCursor() {
-
- // if the renderers have stopped, also stop the timer that is updating
- // the final image
- if (bgExecuter != null && bgExecuter.isRunning()
- || localExecuter.isRunning()) {
- setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
- return;
- } else {
- // Allow one last rendering
- if (repaintTimer.isRunning()) {
- // System.out.println("one last rendering....");
- repaintTimer.stop();
- updateFinalImage();
- repaint();
- }
- }
- //
- // //
- // // wenn manueller Cursor gesetzt ist, dann diesen verwenden
- // (unabhaengig
- // // von der aktuellen Aktion
- // if (this.staticCursor != null) {
- // setCursor(staticCursor);
- // return;
- // }
- //
- if (getCursor() == SwingUtil.PANNING_CURSOR) {
- // This cursor will reset itself
- return;
- }
-
- setCursor(tool.getCursor());
-
- //
- // // Set the cursor depending on what tool is in use...
- // switch (state) {
- // case SELECT_TOP:
- // case SELECT_ONE_FROM_TOP:
- // case SELECT_ALL:
- // setCursor(SwingUtil.CROSSHAIR_CURSOR);
- // break;
- // case ZOOM_IN:
- // setCursor(SwingUtil.ZOOMIN_CURSOR);
- // break;
- // case ZOOM_OUT:
- // setCursor(SwingUtil.ZOOMOUT_CURSOR);
- // break;
- // case PAN:
- // setCursor(SwingUtil.PAN_CURSOR);
- // break;
- // default:
- // setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
- // break;
- // }
- }
-
- /**
- * The renderers are all rendering into their own {@link Image}s. This
- * method combines all images to one {@link #finalImage}. The
- * {@link #repaintTimer} is calling this method regularely to update the
- * {@link #finalImage} even if the renderers are still working.
- */
- synchronized protected Image updateFinalImage() {
-
- // Render the two map images first, into the preFinalImage
- if (bgExecuter != null) {
- final Graphics2D preFinalG = (Graphics2D) getPreFinalImage()
- .getGraphics();
- preFinalG.setBackground(getMapBackgroundColor());
-
- preFinalG.drawImage(getBgImage(), 0, 0, getMapBackgroundColor(),
- null);
-
- // // Draw the local layers image
- preFinalG.drawImage(getLocalImage(), 0, 0, null);
- preFinalG.dispose();
-
- } else {
- preFinalImage = getLocalImage();
- }
-
- final Graphics2D finalG = getFinalImage().createGraphics();
- finalG.setBackground(getMapBackgroundColor());
- finalG.drawImage(getPreFinalImage(), getImageOrigin().x,
- getImageOrigin().y, getMapBackgroundColor(), null);
-
- // When panning, we have to clear the area around the image
- final Rectangle painedArea = new Rectangle(getImageOrigin().x,
- getImageOrigin().y, getFinalImage().getWidth(), getFinalImage()
- .getHeight());
- SwingUtil.clearAround(finalG, painedArea, getVisibleRect(),
- getMapBackgroundColor());
-
- addGadgets(finalG, false);
-
- finalG.dispose();
-
- return finalImage;
- }
-
- /**
- * Paints some optional stuff into the given {@link Graphics2D}. Usually
- * called as the last layer when {@link #updateFinalImage()}
- *
- * @param forceWait
- * if <code>true</code>, a Wait-message will be painted even
- * though the rendering threads may not yet have started. If
- * <code>false</code>, it will only depend on
- * {@link #localExecuter.isRunning} and #bgExecuter.isRunning
- */
- private void addGadgets(final Graphics2D graphics, final boolean forceWait) {
-
- // Paint a logo to the bottom right if available
- if (mapImage != null) {
- final Rectangle visibleRect = getVisibleRect();
- graphics.drawImage(mapImage, visibleRect.width
- - mapImage.getWidth() - 10, getVisibleRect().height
- - mapImage.getHeight() - 10, null);
- }
-
- int y = 17;
-
- // If the rendering process is still running, indicate this is the image
- if (forceWait || bgExecuter != null && bgExecuter.isRunning()
- || localExecuter.isRunning()) {
-
- y += 8;
-
- final Color c = graphics.getColor();
- graphics.setFont(waitFont);
-
- graphics.setColor(getMapBackgroundColor());
- graphics.drawString(waitMsg, 5, y);
- graphics.setColor(getMapBackgroundColor());
- graphics.drawString(waitMsg, 7, y + 2);
- graphics.setColor(Color.BLACK);
- graphics.drawString(waitMsg, 6, y + 1);
-
- graphics.setColor(c);
-
- y += 21;
- }
-
- if (!renderingErrors.isEmpty() && isShowExceptions()) {
-
- final Color c = graphics.getColor();
- graphics.setFont(errorFont);
-
- for (final Exception ex : renderingErrors) {
-
- String errStr = ex.getLocalizedMessage();
-
- if (errStr == null)
- errStr = ex.getMessage();
- if (errStr == null)
- errStr = "unknown error: " + ex.getClass().getSimpleName();
-
- graphics.setColor(getMapBackgroundColor());
- graphics.drawString(errStr, 5, y);
- graphics.setColor(Color.RED);
- graphics.drawString(errStr, 6, y + 1);
-
- y += 19;
- }
-
- graphics.setColor(c);
- }
-
- }
-
- /**
- * Sets the {@link #mapArea} to best possibly present the given features. If
- * only one single point is given, the window is moved over the point.
- *
- * @param features
- * if <code>null</code> or size==0, the function doesn nothing.
- *
- * @return <code>true</code> if the {@link #mapArea} has changed and
- * rendering has been triggered.
- */
- public boolean zoomTo(
- final FeatureCollection<SimpleFeatureType, SimpleFeature> features) {
-
- // if (!isWellDefined()) return;
-
- final CoordinateReferenceSystem mapCRS = getMapContext()
- .getCoordinateReferenceSystem();
- final CoordinateReferenceSystem fCRS = features.getSchema()
- .getCoordinateReferenceSystem();
-
- ReferencedEnvelope _mapArea;
- if (mapArea == null)
- _mapArea = features.getBounds();
- else
- _mapArea = getMapArea();
- double width = _mapArea.getWidth();
- double height = _mapArea.getHeight();
- final double ratio = height / width;
-
- if (features == null || features.size() == 0) {
- // feature count == 0 Zoom to the full extend
- return false;
- } else if (features.size() == 1) {
-
- // feature count == 1 Just move the window to the point and zoom 'a
- // bit'
- final SimpleFeature singleFeature = features.iterator().next();
-
- if (((Geometry) singleFeature.getDefaultGeometry())
- .getCoordinates().length > 1) {
- // System.out.println("Zoomed to only pne poylgon");
- // Poly
- // TODO max width vs. height
- width = features.getBounds().getWidth() * 3;
- height = ratio * width;
- } else {
- // System.out.println("Zoomed in a bit becasue only one point");
- // width *= .9;
- // height *= .9;
- }
-
- Coordinate centre = features.getBounds().centre();
- if (!mapCRS.equals(fCRS)) {
- // only to calculations if the CRS differ
- try {
- MathTransform fToMap;
- fToMap = CRS.findMathTransform(fCRS, mapCRS);
- // centre is transformed to the mapCRS
- centre = JTS.transform(centre, null, fToMap);
- } catch (final FactoryException e) {
- LOGGER.error("Looking for a Math transform", e);
- } catch (final TransformException e) {
- LOGGER.error("Looking for a Math transform", e);
- }
- }
-
- final Coordinate newLeftBottom = new Coordinate(centre.x - width
- / 2., centre.y - height / 2.);
- final Coordinate newTopRight = new Coordinate(
- centre.x + width / 2., centre.y + height / 2.);
-
- final Envelope newMapArea = new Envelope(newLeftBottom, newTopRight);
-
- return setMapArea(newMapArea);
-
- } else {
- final ReferencedEnvelope fBounds = features.getBounds();
-
- ReferencedEnvelope bounds;
- if (!mapCRS.equals(fCRS)) {
- bounds = JTSUtil.transformEnvelope(fBounds, mapCRS);
- } else {
- bounds = fBounds;
- }
- // BB umrechnen von Layer-CRS in Map-CRS
-
- // Expand a bit
- addDefaultMargin(bounds);
-
- return setMapArea(bounds);
- }
- }
-
- private ReferencedEnvelope addDefaultMargin(ReferencedEnvelope bounds) {
- return JTSUtil.expandEnvelope(bounds, Math.max(0,
- defaultMaxMapExtendMode));
- }
-
- private Envelope addDefaultMargin(Envelope bounds) {
- return JTSUtil.expandEnvelope(bounds, Math.max(0,
- defaultMaxMapExtendMode));
- }
-
- /**
- * Zooms towards a point.
- *
- * @param center
- * position in window coordinates
- * @param zoomFactor
- * > 1 for zoom in, < 1 for zoom out. Default is 1.33
- */
- public void zoomTo(final Point center) {
- zoomTo(center, null);
- }
-
- /**
- * Zooms towards a point.
- *
- * @param center
- * position in window coordinates
- * @param zoomFaktor
- * > 1 for zoom out, < 1 for zoom in. Default is .5
- * @retun <code>true</code> if {@link #mapArea} has changed and a repaint is
- * triggered
- */
- public boolean zoomTo(Point center, Double zoomFaktor) {
- if (zoomFaktor == null || zoomFaktor == 0.)
- zoomFaktor = .5;
-
- final Point2D gcenter = getScreenToWorld().transform(center, null);
- center = null;
-
- if (Double.isNaN(gcenter.getX()) || Double.isNaN(gcenter.getY())
- || Double.isInfinite(gcenter.getX())
- || Double.isInfinite(gcenter.getY())
-
- ) {
- // Not inside valid CRS area! cancel
- return false;
- }
-
- final Envelope mapArea = getMapArea();
-
- final Envelope newMapArea = new Envelope(mapArea);
- newMapArea.expandBy((mapArea.getWidth() * zoomFaktor - mapArea
- .getWidth()) / 2., (mapArea.getHeight() * zoomFaktor - mapArea
- .getHeight()) / 2.);
-
- // // Move the newMapArea above the new center if we zoom in:
- newMapArea.translate(gcenter.getX() - mapArea.centre().x, gcenter
- .getY()
- - mapArea.centre().y);
-
- return setMapArea(newMapArea);
- }
-
- /**
- * Zooms in or out in a way, that the given {@link Point} on the map stays
- * at the same positino in screen coordinates.
- *
- * @param point
- * fixed {@link Point} that will be at the same screen poistion
- * after zoom.
- */
- public boolean zoomTowards(Point point, Double zFactor) {
- // int units = wheelEvt.getUnitsToScroll();
- //
- // Negativer Wert --> Zoom out --> Faktir > 1
-
- // SK: 9.9.2007 zoom jetzt wie bei GoogleEarth
- // double zFactor = units > 0 ? 1.3 : 1 / 1.3;
- // vorher double zFactor = units > 0 ? 1/1.2 : 1.2;
-
- // Fenster-Koordinaten zu Karten-Koordinaten transformieren
- // Point2D mapCoord = XMapPane.getMapCoordinatesFromEvent(wheelEvt);
- // Relative Position des Mauszeigers zum Kartenausschnitt
- // -> Nach Zoom soll dieselbe Kartenposition unterhalb des Mauszeigers
- // erscheinen, wie vor dem Zoom
- final Point2D mapCoord = getScreenToWorld().transform(point, null);
-
- double relX = (mapCoord.getX() - getMapArea().getMinX())
- / getMapArea().getWidth();
- double relY = (mapCoord.getY() - getMapArea().getMinY())
- / getMapArea().getHeight();
-
- // Neuen Karten-Ausschnitt berechnen
- Coordinate ll = new Coordinate(mapCoord.getX()
- - getMapArea().getWidth() * relX * zFactor, mapCoord.getY()
- - getMapArea().getHeight() * relY * zFactor);
- Coordinate ur = new Coordinate(mapCoord.getX()
- + getMapArea().getWidth() * (1 - relX) * zFactor, mapCoord
- .getY()
- + getMapArea().getHeight() * (1 - relY) * zFactor);
-
- return setMapArea(new Envelope(ll, ur));
- }
-
- /**
- * Shall non-fatal rendering exceptions be reported in the mappane or be
- * dropped quitely.
- */
- public void setShowExceptions(final boolean showExceptions) {
- this.showExceptions = showExceptions;
- }
-
- /**
- * Shall exceptions be reported in the mappane?
- */
- public boolean isShowExceptions() {
- return showExceptions;
- }
-
- public GTRenderer getLocalRenderer() {
- return localRenderer;
- }
-
- /**
- * Setzt den Kartenausschnitt auf die Ausdehnung eines bestimmten Layers.
- * Macht nichts, wenn {@code null} uebergeben wird.
- *
- * <br>
- *
- * @param layer
- * ein Layer
- */
- public void zoomToLayer(MapLayer layer) {
- if (layer == null)
- return;
- try {
-
- // BB umrechnen von Layer-CRS in Map-CRS
- final CoordinateReferenceSystem targetCRS = getMapContext()
- .getCoordinateReferenceSystem();
- final CoordinateReferenceSystem sourceCRS = layer
- .getFeatureSource().getSchema()
- .getCoordinateReferenceSystem();
-
- Envelope mapAreaNew;
- if (!CRS.equalsIgnoreMetadata(sourceCRS, targetCRS)) {
- mapAreaNew = JTSUtil.transformEnvelope(layer.getFeatureSource()
- .getBounds(), sourceCRS, targetCRS);
- } else {
- try {
- mapAreaNew = layer.getFeatureSource().getBounds();
- } catch (java.lang.IllegalArgumentException e) {
- LOGGER.error("Can't calc layers bounds...", e);
- mapAreaNew = null;
-
- /**
- *
- 23.10.2009 11:20:50
- * org.geotools.data.shapefile.shp.PolygonHandler read
- * WARNUNG: only one hole in this polygon record ERROR
- * JMapPane zoomToLayer Zoom to layer did not terminate
- * correctly java.lang.IllegalArgumentException: Points of
- * LinearRing do not form a closed linestring at
- * com.vividsolutions
- * .jts.geom.LinearRing.validateConstruction
- * (LinearRing.java:105) at
- * com.vividsolutions.jts.geom.LinearRing
- * .<init>(LinearRing.java:100) at
- * com.vividsolutions.jts.geom
- * .GeometryFactory.createLinearRing
- * (GeometryFactory.java:339) at
- * org.geotools.data.shapefile.
- * shp.PolygonHandler.read(PolygonHandler.java:188) at
- * org.geotools
- * .data.shapefile.shp.ShapefileReader$Record.shape
- * (ShapefileReader.java:106) at
- * org.geotools.data.shapefile.
- * ShapefileAttributeReader.next(
- * ShapefileAttributeReader.java:157) at
- * org.geotools.data.shapefile
- * .indexed.IndexedShapefileAttributeReader
- * .next(IndexedShapefileAttributeReader.java:122) at
- * org.geotools
- * .data.FIDFeatureReader.next(FIDFeatureReader.java:96) at
- * org.geotools.data.FIDFeatureReader.next(FIDFeatureReader.
- * java:55) at org.geotools.data.MaxFeatureReader.next(
- * MaxFeatureReader.java:61) at
- * org.geotools.data.MaxFeatureReader
- * .next(MaxFeatureReader.java:61)
- **/
- }
- }
-
- // Kartenbereich um 10% vergroessern, damit z.B. auch ein
- // Punkt-Layer,
- // welches nur aus 2 Punnkten besteht, sichtbar ist (Punkte liegen
- // sonst
- // genau auf dem Rand der angezeigten Flaeche)
-
- if (mapAreaNew != null) {
-
- mapAreaNew = addDefaultMargin(mapAreaNew);
- setMapArea(mapAreaNew);
- } else {
- LOGGER
- .warn("Couldn't transformEnvelope when zooming to the layer");
- }
- } catch (Exception err) {
- LOGGER.error("Zoom to layer did not terminate correctly", err);
- }
- }
-
- /**
- * Zooms the {@link SelectableXMapPane} to the {@link Envelope} of a layer.
- *
- * <br>
- * A refresh of the map is not done automatically
- *
- * @param index
- * Index of the {@link MapLayer} in the {@link MapContext} (from
- * back to top)
- *
- * @author <a href="mailto:skpublic at wikisquare.de">Stefan Alfons
- * Krüger</a>
- */
- public void zoomToLayer(int index) {
- final MapContext context = getMapContext();
- if (context != null)
- zoomToLayer(context.getLayer(index));
- }
-
- /**
- * Zooms the {@link SelectableXMapPane} to the {@link Envelope} of the
- * selected layer. The layer is selected by the idx, counting from front to
- * back, like humans would expect in a {@link JList}
- *
- * <br>
- * A refresh of the map is not done automatically
- *
- *
- *
- * @param index
- * Reverse index of the {@link MapLayer} in the
- * {@link MapContext}
- *
- * @author <a href="mailto:skpublic at wikisquare.de">Stefan Alfons
- * Krüger</a>
- */
- public void zoomToLayerIdxReverse(int index) {
- zoomToLayer(getMapContext().getLayerCount() - 1 - index);
- }
-
- /**
- * Aktiviert oder deaktiviert das AntiAliasing for diese
- * {@link SelectableXMapPane}. AntiALiasing ist besonders fuer
- * Textbeschriftung sehr schoen, verbraucht aber auch mehr Performance.
- *
- * @author <a href="mailto:skpublic at wikisquare.de">Stefan Alfons
- * Krüger</a>
- */
- public void setAntiAliasing(final boolean aa) {
- // LOGGER.info("Setting AntiAliasing for this JMapPane to " + aa);
- RenderingHints java2DHints = java2dHints;
- if (java2DHints == null) {
- java2DHints = GeoTools.getDefaultHints();
- }
-
- java2DHints.put(RenderingHints.KEY_ANTIALIASING,
- aa ? RenderingHints.VALUE_ANTIALIAS_ON
- : RenderingHints.VALUE_ANTIALIAS_OFF);
- java2DHints.put(RenderingHints.KEY_TEXT_ANTIALIASING,
- aa ? RenderingHints.VALUE_TEXT_ANTIALIAS_ON
- : RenderingHints.VALUE_TEXT_ANTIALIAS_OFF);
- java2DHints.put(RenderingHints.KEY_RENDERING,
- aa ? RenderingHints.VALUE_RENDER_QUALITY
- : RenderingHints.VALUE_RENDER_SPEED);
-
- }
-
- public Point getImageOrigin() {
- return imageOrigin;
- }
-
- /**
- * If {@link #maxExtend} is <code>null</code> the following rules are used
- * to create a default maximum.
- * <ul>
- * <li>Values < 0 : don't grow to fit the monitors aspect ratio, no
- * margin</li>
- * <li>Values 0 : grow to fit the monitors aspect ratio, no margin</li>
- * <li>Values > 0 : grow to fit the monitors aspect ratio, and add a
- * relative margin</li>
- * </ul>
- * **/
- public void setDefaultMaxMapExtendMode(double defaultMaxMapExtendMode) {
- this.defaultMaxMapExtendMode = defaultMaxMapExtendMode;
- }
-
- /**
- * If {@link #maxExtend} is <code>null</code> the following rules are used
- * to create a default maximum.
- * <ul>
- * <li>Values < 0 : don't grow to fit the monitors aspect ratio, no
- * margin</li>
- * <li>Values 0 : grow to fit the monitors aspect ratio, no margin</li>
- * <li>Values > 0 : grow to fit the monitors aspect ratio, and add a
- * relative margin</li>
- * </ul>
- * **/
- public double getDefaultMaxMapExtendMode() {
- return defaultMaxMapExtendMode;
- }
-
- final static int BLINK_TIMER_DEPLAY = 800;
-
- /**
- * The job of the BlinkTimer is to remove the features painted in BLINK
- * style again.
- */
- private Timer initBlinkTimer() {
- Timer timer = new Timer(BLINK_TIMER_DEPLAY, new ActionListener() {
-
- @Override
- public void actionPerformed(ActionEvent e) {
- blinkRenderer = null;
- XMapPane.this.repaint(300);
- }
- });
- timer.setDelay(BLINK_TIMER_DEPLAY);
- timer.setRepeats(false);
- return timer;
- }
-
- /**
- * Makes the given {@link SimpleFeature} bink in the map for a moment
- */
- public void blink(SimpleFeature feature) {
- MemoryFeatureCollection memoryFeatureCollection = new MemoryFeatureCollection(
- feature.getFeatureType());
- memoryFeatureCollection.add(feature);
- blink(memoryFeatureCollection);
- }
-
- /**
- * Makes the given {@link FeatureCollection} bink in the map for a moment
- */
- public void blink(
- FeatureCollection<SimpleFeatureType, SimpleFeature> features) {
- {
- if (stopBlinkTimer != null)
- stopBlinkTimer.stop();
- repaint();
- stopBlinkTimer = initBlinkTimer();
-
- DefaultMapContext mc = new DefaultMapContext(getMapContext()
- .getCoordinateReferenceSystem());
-
- Style style = StylingUtil.STYLE_FACTORY.createStyle();
- style.featureTypeStyles().add(
- StylingUtil.createBlinkFeatureTypeStyle(features));
-
- // style = StylingUtil.createStyleSimple(features, Color.pink,
- // Color.WHITE);
-
- DefaultMapLayer dml = new DefaultMapLayer(features, style);
- mc.addLayer(dml);
-
- blinkRenderer = new StreamingRenderer();
-
- blinkRenderer.setJava2DHints(getJava2dHints());
-
- blinkRenderer.setContext(mc);
-
- stopBlinkTimer.start();
-
- }
-
- }
-
-}
Deleted: trunk/src/skrueger/geotools/XMapPaneAction.java
===================================================================
--- trunk/src/skrueger/geotools/XMapPaneAction.java 2010-03-03 01:48:43 UTC (rev 739)
+++ trunk/src/skrueger/geotools/XMapPaneAction.java 2010-03-03 10:32:14 UTC (rev 740)
@@ -1,162 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2009 Martin O. J. Schmitz.
- *
- * This file is part of the SCHMITZM library - a collection of utility
- * classes based on Java 1.6, focusing (not only) on Java Swing
- * and the Geotools library.
- *
- * The SCHMITZM project is hosted at:
- * http://wald.intevation.org/projects/schmitzm/
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public License
- * as published by the Free Software Foundation; either version 3
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License (license.txt)
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- * or try this link: http://www.gnu.org/licenses/lgpl.html
- *
- * Contributors:
- * Martin O. J. Schmitz - initial API and implementation
- * Stefan A. Krüger - additional utility classes
- ******************************************************************************/
-package skrueger.geotools;
-
-import java.awt.Point;
-import java.awt.event.MouseEvent;
-import java.awt.event.MouseWheelEvent;
-
-import org.opengis.geometry.DirectPosition;
-
-import schmitzm.swing.event.MouseInputType;
-
-/**
- * Defines an action (e.g. Zoom in, zoom out, drag) when a click, drag or window
- * selection is performed on a {@link XMapPane}.
- *
- * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a>
- * (University of Bonn/Germany)
- */
-public interface XMapPaneAction {
-
- /**
- * This action can be assigned to any {@link MouseInputType} to perform
- * zoom-in
- **/
- public static XMapPaneAction_Zoom ZOOM_IN = new XMapPaneAction_Zoom.In();
-
- /**
- * This action can be assigned to any {@link MouseInputType} to perform
- * zoom-out
- **/
- public static XMapPaneAction_Zoom ZOOM_OUT = new XMapPaneAction_Zoom.Out();
-
- /**
- * This action can be assigned to any {@link MouseInputType} to perform
- * panning on a Map
- **/
- public static XMapPaneAction_Pan PAN = new XMapPaneAction_Pan();
-
- /**
- * This action can be assigned to fire events for any number of feature from all layers.
- **/
- public static XMapPaneAction_Select.All SELECT_ALL = new XMapPaneAction_Select.All();
-
- /**
- * This action can be assigned to fire selection events for one feature from the top layer.
- **/
- public static XMapPaneAction_Select.OneFromTop SELECT_ONE_FROM_TOP = new XMapPaneAction_Select.OneFromTop();
-
- /**
- * This action can be assigned to fire events for any number of feature from the top layer.
- **/
- public static XMapPaneAction_Select.Top SELECT_TOP = new XMapPaneAction_Select.Top();
-
- /**
- * Defines the action in case of a single click on the map. Called by ###
- * XMapPaneMouseAdapter ### on {@link MouseInputType#LClick} and
- * {@link MouseInputType#RClick}.
- *
- * @param mapPane
- * map pane the action should be performed on
- * @param ev
- * mouse event of the action
- * @param coord
- * geo coordinate the click is performed on
- */
- public void performClick(XMapPane mapPane, MouseEvent ev,
- DirectPosition coord);
-
- /**
- * Defines the action in case of a mouse drag on the map. This method is
- * called on every mouse motion.
- *
- * @param mapPane
- * map pane the action should be performed on
- * @param ev
- * mouse event of the action
- * @param dragStartPos
- * window position the drag was started (the current position can
- * be determined from the mouse event)
- * @param startCoord
- * geo coordinate the drag was started
- * @param endCoord
- * geo coordinate the drag is currently moved over
- */
- public void performDragging(XMapPane mapPane, MouseEvent ev,
- Point dragStartPos, Point dragLastPos, DirectPosition startCoord,
- DirectPosition endCoord);
-
- /**
- * Defines the action in case of a window selection on the map (the moment a
- * drag ends).
- *
- * @param mapPane
- * map pane the action should be performed on
- * @param ev
- * mouse event of the action
- * @param dragStartPos
- * window position the window starts (the end position can be
- * determined from the mouse event)
- * @param startCoord
- * geo coordinate the window starts
- * @param endCoord
- * geo coordinate the window ends
- */
- public void performDragged(XMapPane mapPane, MouseEvent ev,
- Point dragStartPos, Point dragLastPos, DirectPosition startCoord,
- DirectPosition endCoord);
-
- /**
- * Defines the action in case of a mouse wheel action on the map (the moment
- * a drag ends).
- *
- * @param mapPane
- * map pane the action should be performed on
- * @param ev
- * mouse event of the action
- * @param coord
- * geo coordinate the wheel is turned on
- */
- public void performWheel(XMapPane mapPane, MouseWheelEvent ev,
- DirectPosition coord);
-
- /**
- * Defines what happens if this action has been triggered by a keyboard-key.
- *
- * @param mapPane
- * map pane the action should be performed on
- *
- * @param param
- * An optinal paramter that can be defined.
- */
- public void performKeyboard(XMapPane mapPane, Object param);
-
-}
Deleted: trunk/src/skrueger/geotools/XMapPaneActionAdapter.java
===================================================================
--- trunk/src/skrueger/geotools/XMapPaneActionAdapter.java 2010-03-03 01:48:43 UTC (rev 739)
+++ trunk/src/skrueger/geotools/XMapPaneActionAdapter.java 2010-03-03 10:32:14 UTC (rev 740)
@@ -1,86 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2009 Martin O. J. Schmitz.
- *
- * This file is part of the SCHMITZM library - a collection of utility
- * classes based on Java 1.6, focusing (not only) on Java Swing
- * and the Geotools library.
- *
- * The SCHMITZM project is hosted at:
- * http://wald.intevation.org/projects/schmitzm/
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public License
- * as published by the Free Software Foundation; either version 3
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License (license.txt)
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- * or try this link: http://www.gnu.org/licenses/lgpl.html
- *
- * Contributors:
- * Martin O. J. Schmitz - initial API and implementation
- * Stefan A. Krüger - additional utility classes
- ******************************************************************************/
-
-package skrueger.geotools;
-
-import java.awt.Point;
-import java.awt.event.MouseEvent;
-import java.awt.event.MouseWheelEvent;
-
-import org.opengis.geometry.DirectPosition;
-
-/**
- * Empty implementation of {@link XMapPaneAction}. No method of this class
- * does anything.
- * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
- */
-public class XMapPaneActionAdapter implements XMapPaneAction {
-
- /**
- * Implements the action on a mouse click event. Does nothing.
- */
- @Override
- public void performClick(XMapPane mapPane, MouseEvent ev, DirectPosition coord) {
- }
-
- /**
- * Implements the action AFTER a mouse drag has ended. Does nothing.
- */
- @Override
- public void performDragged(XMapPane mapPane, MouseEvent ev,
- Point dragStartPos, Point dragLastPos, DirectPosition startCoord,
- DirectPosition endCoord) {
- }
-
- /**
- * Implements the action DURING a mouse drag. Does nothing.
- */
- @Override
- public void performDragging(XMapPane mapPane, MouseEvent ev,
- Point dragStartPos, Point dragLastPos, DirectPosition startCoord,
- DirectPosition endCoord) {
- }
-
- /**
- * Implements the action on a keyboard stroke. Does nothing.
- */
- @Override
- public void performKeyboard(XMapPane mapPane, Object param) {
- }
-
- /**
- * Implements the action on mouse wheel event. Does nothing.
- */
- @Override
- public void performWheel(XMapPane mapPane, MouseWheelEvent ev,
- DirectPosition coord) {
- }
-
-}
Deleted: trunk/src/skrueger/geotools/XMapPaneAction_Pan.java
===================================================================
--- trunk/src/skrueger/geotools/XMapPaneAction_Pan.java 2010-03-03 01:48:43 UTC (rev 739)
+++ trunk/src/skrueger/geotools/XMapPaneAction_Pan.java 2010-03-03 10:32:14 UTC (rev 740)
@@ -1,175 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2009 Martin O. J. Schmitz.
- *
- * This file is part of the SCHMITZM library - a collection of utility
- * classes based on Java 1.6, focusing (not only) on Java Swing
- * and the Geotools library.
- *
- * The SCHMITZM project is hosted at:
- * http://wald.intevation.org/projects/schmitzm/
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public License
- * as published by the Free Software Foundation; either version 3
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License (license.txt)
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- * or try this link: http://www.gnu.org/licenses/lgpl.html
- *
- * Contributors:
- * Martin O. J. Schmitz - initial API and implementation
- * Stefan A. Krüger - additional utility classes
- ******************************************************************************/
-package skrueger.geotools;
-
-import java.awt.Cursor;
-import java.awt.Point;
-import java.awt.Rectangle;
-import java.awt.event.MouseEvent;
-import java.awt.event.MouseWheelEvent;
-
-import org.opengis.geometry.DirectPosition;
-
-import schmitzm.swing.SwingUtil;
-
-import com.vividsolutions.jts.geom.Envelope;
-
-public class XMapPaneAction_Pan implements XMapPaneAction {
-
- public static enum Direction {
- UP, DOWN, RIGHT, LEFT
- }
-
- /**
- * If this action is triggered by keyboard, defines the amount of panning in
- * screen pixels
- **/
- private static final int KEYBOARD_PAN_LENGTH = 15;
-
- /**
- * This variable can be used to backup the active cursor of the mapPane, if
- * the actions changes the cursor during dragging
- */
- public Cursor backupCursor = null;
-
- /**
- * Performs a pan action. During panning, the displacement is stored in
- * {@link #imageOrigin} object. Calling {@link #performPan()} will reset the
- * offset and call {@link #setMapArea(Envelope)}.
- */
- @Override
- public void performDragged(XMapPane mapPane, MouseEvent ev,
- Point dragStartPos, Point dragLastPos, DirectPosition startCoord,
- DirectPosition endCoord) {
-
- Point translation = mapPane.getImageOrigin();
-
- doPan(mapPane, translation);
- }
-
- private void doPan(XMapPane mapPane, Point translation) {
-
- final Rectangle winBounds = mapPane.getVisibleRect();
- winBounds.translate(-translation.x, -translation.y);
- final Envelope newMapArea = mapPane.tranformWindowToGeo(winBounds.x,
- winBounds.y, winBounds.x + winBounds.width, winBounds.y
- + winBounds.height);
-
- translation.x = 0;
- translation.y = 0;
-
- if (!mapPane.setMapArea(newMapArea)) {
- /**
- * If setMapArea returns true, the finalImage is updated anyways.
- * This if-case exists to ensure that we repaint a correct image
- * even if the new panning area has been denied.
- */
- mapPane.updateFinalImage();
- mapPane.repaint();
- }
-
- if (mapPane.getCursor() == SwingUtil.PANNING_CURSOR) {
- mapPane.setCursor(backupCursor);
- }
- }
-
- /**
- * TODO: Stop dragging if the expected map area would not be valid.
- */
- @Override
- public void performDragging(XMapPane mapPane, MouseEvent ev,
- Point dragStartPos, Point dragLastPos, DirectPosition startCoord,
- DirectPosition endCoord) {
-
- if (mapPane.getCursor() != SwingUtil.PANNING_CURSOR) {
- backupCursor = mapPane.getCursor();
- mapPane.setCursor(SwingUtil.PANNING_CURSOR);
- }
-
- // Variables for the translation in screen pixels
- int dX;
- int dY;
-
- if (dragLastPos == null) {
- dX = ev.getPoint().x - dragStartPos.x;
- dY = ev.getPoint().y - dragStartPos.y;
- } else {
- dX = ev.getPoint().x - dragLastPos.x;
- dY = ev.getPoint().y - dragLastPos.y;
- }
-
- if (dX != 0 && dY != 0)
- mapPane.pan(dX, dY);
-
- }
-
- @Override
- public void performWheel(XMapPane mapPane, MouseWheelEvent ev,
- DirectPosition coord) {
- }
-
- @Override
- public void performClick(XMapPane mapPane, MouseEvent ev,
- DirectPosition coord) {
- }
-
- @Override
- public void performKeyboard(XMapPane mapPane, Object param) {
- if (param == null)
- return;
-
- if (!(param instanceof Direction)) {
- throw new IllegalArgumentException("param = " + param
- + " is of expected type XMapPaneAction_Pan.Direction");
- }
-
- // Variables for the translation in screen pixels
- int dX = 0;
- int dY = 0;
-
- switch ((Direction) param) {
- case DOWN:
- dY = KEYBOARD_PAN_LENGTH;
- break;
- case UP:
- dY = -KEYBOARD_PAN_LENGTH;
- break;
- case LEFT:
- dX = -KEYBOARD_PAN_LENGTH;
- break;
- case RIGHT:
- dX = KEYBOARD_PAN_LENGTH;
- break;
- }
-
- doPan(mapPane, new Point(dX, dY));
- }
-
-}
Deleted: trunk/src/skrueger/geotools/XMapPaneAction_Select.java
===================================================================
--- trunk/src/skrueger/geotools/XMapPaneAction_Select.java 2010-03-03 01:48:43 UTC (rev 739)
+++ trunk/src/skrueger/geotools/XMapPaneAction_Select.java 2010-03-03 10:32:14 UTC (rev 740)
@@ -1,215 +0,0 @@
-package skrueger.geotools;
-
-import java.awt.Color;
-import java.awt.Point;
-import java.awt.event.MouseEvent;
-import java.awt.event.MouseWheelEvent;
-import java.awt.geom.Point2D;
-import java.util.Enumeration;
-import java.util.Hashtable;
-import java.util.Iterator;
-
-import org.geotools.data.memory.MemoryFeatureCollection;
-import org.geotools.feature.FeatureCollection;
-import org.geotools.map.MapLayer;
-import org.opengis.feature.simple.SimpleFeature;
-import org.opengis.feature.simple.SimpleFeatureType;
-import org.opengis.geometry.DirectPosition;
-
-import schmitzm.geotools.gui.SelectableXMapPane;
-import schmitzm.geotools.map.event.FeatureSelectedEvent;
-import skrueger.geotools.GeomFilterGenerator.PointFilterGenerator;
-
-import com.vividsolutions.jts.geom.Coordinate;
-import com.vividsolutions.jts.geom.Envelope;
-import com.vividsolutions.jts.geom.Geometry;
-import com.vividsolutions.jts.geom.GeometryFactory;
-
-public abstract class XMapPaneAction_Select implements XMapPaneAction {
- //
- // /**
- // * Flag fuer Modus "SimpleFeature-Auswahl auf allen (sichtbaren) Layern".
- // *
- // * @see #setState(int)
- // * @see #setState(int)
- // */
- // public static enum SelMode {
- // SELECT_ALL
- // }
-
- public void performClick(XMapPane xMapPane, MouseEvent ev,
- DirectPosition geoCoord) {
-
- SelectableXMapPane sexMapPane = (SelectableXMapPane) xMapPane;
-
- // calculate a circle radius around the mouse position
- double radius = DEFAULT_DISTANCE_FRACTION
- * (xMapPane.getMapArea().getWidth() + xMapPane.getMapArea()
- .getHeight()) / 2;
-
- // Fenster-Koordinate in Geo-Koordinate umwandelt
- Point2D geoPoint = xMapPane.getScreenToWorld().transform(ev.getPoint(),
- null);
-
- PointFilterGenerator filterGenerator = new PointFilterGenerator(
- geoCoord, radius);
- Hashtable<MapLayer, FeatureCollection<SimpleFeatureType, SimpleFeature>> result = sexMapPane
- .findVisibleFeatures(filterGenerator, getSelectionMode(),
- new Envelope(geoPoint.getX(), geoPoint.getX(), geoPoint
- .getY(), geoPoint.getY()));
-
- // Ein Event auslösen für das jeweils nächste Feature pro Layer
- for (Enumeration<MapLayer> element = result.keys(); element
- .hasMoreElements();) {
-
- MapLayer layer = element.nextElement();
- FeatureCollection<SimpleFeatureType, SimpleFeature> fc = result
- .get(layer);
- FeatureCollection<SimpleFeatureType, SimpleFeature> fcOne;
-
- if (fc != null && !fc.isEmpty()) {
-
- if (fc.size() > 1) {
- // If the result contains more that one feature, we only
- // return the nearest one.
-
- SimpleFeature nearestFeature = null;
- Double nearestDist = 0.0;
-
- Iterator<SimpleFeature> fcIt = fc.iterator();
- try {
- com.vividsolutions.jts.geom.Point mousePoint = new GeometryFactory()
- .createPoint(new Coordinate(geoPoint.getX(),
- geoPoint.getY()));
-
- while (fcIt.hasNext()) {
- SimpleFeature f = fcIt.next();
- Geometry obj = (Geometry) f
- .getDefaultGeometryProperty().getValue();
-
- // TODO Hier muss doch irgendwie noch CRS
- // umgewrechnet werden...
-
- Geometry featureGeometry = (Geometry) obj;
-
- double distance = featureGeometry
- .distance(mousePoint);
-
- if ((nearestFeature == null)
- || (distance < nearestDist)) {
- nearestFeature = f;
- nearestDist = distance;
- }
-
- }
-
- } finally {
- fc.close(fcIt);
- }
-
- fcOne = new MemoryFeatureCollection(fc.getSchema());
- fc.clear();
- fcOne.add(nearestFeature);
- } else {
- fcOne = fc;
- }
-
- // Fire the event with the one selected feature
- sexMapPane.fireMapPaneEvent(new FeatureSelectedEvent(
- sexMapPane, layer, fcOne.getBounds(), fcOne));
- }
- }
-
- // If no vector features were found, or we are in SELECT_ALL mode, we
- // check the raster layers now
- if (getSelectionMode() == SelectableXMapPane.SELECT_ALL || result.isEmpty()) {
- sexMapPane.findGridCoverageValuesAndFireEvents(geoPoint,
- getSelectionMode());
- }
- }
-
- /**
- * Does nothing if initiated by keyboard.
- *
- * TODO select all features should be assignable to Strg-A
- */
- @Override
- public void performKeyboard(XMapPane mapPane, Object param) {
- }
-
- /**
- * Default distance fraction used with line and point features. When the
- * user clicks on the map, this tool searches for features within a
- * rectangle of width w centered on the mouse location, where w is the
- * average map side length multiplied by the value of this constant.
- */
- public static final double DEFAULT_DISTANCE_FRACTION = 0.01d;
-
- // @Override
- // public void performClick(XMapPane xMapPane, MouseEvent ev,
- // DirectPosition geoCoord) {
- //
- // performSelectionClick(xMapPane, ev, geoCoord, XMapPane.SELECT_ALL);
- // }
-
- @Override
- public void performDragged(XMapPane mapPane, MouseEvent ev,
- Point dragStartPos, Point dragLastPos, DirectPosition startCoord,
- DirectPosition endCoord) {
-
- SelectableXMapPane sexMapPane = (SelectableXMapPane) mapPane;
-
- Point mp = ev.getPoint();
-
- // Ist es eine wirkliche Selektion, oder etwas nur ein Klick?
- if (dragStartPos.x != mp.x && dragStartPos.y != mp.y) {
- sexMapPane.drawRectangle(sexMapPane.getGraphics(), dragStartPos, ev
- .getPoint(), Color.BLUE.brighter(), true);
- }
-
- // SELECTION!
- sexMapPane.performSelectionEvent(dragStartPos.x, dragStartPos.y, mp.x,
- mp.y, getSelectionMode());
- }
-
- abstract int getSelectionMode();
-
- @Override
- public void performDragging(XMapPane mapPane, MouseEvent ev,
- Point dragStartPos, Point dragLastPos, DirectPosition startCoord,
- DirectPosition endCoord) {
- if (dragLastPos != null)
- mapPane.drawRectangle(mapPane.getGraphics(), dragStartPos,
- dragLastPos, Color.BLUE.brighter(), true);
-
- mapPane.drawRectangle(mapPane.getGraphics(), dragStartPos, ev
- .getPoint(), Color.BLUE.brighter(), true);
- }
-
- @Override
- public void performWheel(XMapPane mapPane, MouseWheelEvent ev,
- DirectPosition coord) {
- }
-
- public static class All extends XMapPaneAction_Select {
-
- int getSelectionMode() {
- return SelectableXMapPane.SELECT_ALL;
- }
- }
-
- public static class OneFromTop extends XMapPaneAction_Select {
-
- int getSelectionMode() {
- return SelectableXMapPane.SELECT_ONE_FROM_TOP;
- }
- }
-
- public static class Top extends XMapPaneAction_Select {
-
- int getSelectionMode() {
- return SelectableXMapPane.SELECT_TOP;
- }
- }
-
-}
Deleted: trunk/src/skrueger/geotools/XMapPaneAction_Zoom.java
===================================================================
--- trunk/src/skrueger/geotools/XMapPaneAction_Zoom.java 2010-03-03 01:48:43 UTC (rev 739)
+++ trunk/src/skrueger/geotools/XMapPaneAction_Zoom.java 2010-03-03 10:32:14 UTC (rev 740)
@@ -1,240 +0,0 @@
-package skrueger.geotools;
-
-import java.awt.Point;
-import java.awt.Rectangle;
-import java.awt.event.MouseEvent;
-import java.awt.event.MouseWheelEvent;
-
-import org.opengis.geometry.DirectPosition;
-
-import schmitzm.geotools.JTSUtil;
-
-import com.vividsolutions.jts.geom.Coordinate;
-import com.vividsolutions.jts.geom.Envelope;
-
-public abstract class XMapPaneAction_Zoom implements XMapPaneAction {
-
- @Override
- public void performDragging(XMapPane mapPane, MouseEvent ev,
- Point dragStartPos, Point dragLastPos,
- DirectPosition startCoord, DirectPosition endCoord) {
-
- if (dragLastPos != null)
- mapPane.drawRectangle(mapPane.getGraphics(), dragStartPos,
- dragLastPos);
-
- mapPane.drawRectangle(mapPane.getGraphics(), dragStartPos, ev
- .getPoint());
- }
-
- public static class In extends XMapPaneAction_Zoom {
-
- @Override
- public void performClick(XMapPane mapPane, MouseEvent ev,
- DirectPosition coord) {
-
-// mapPane.zoomTo(ev.getPoint(), 1 / 2.);
-
- mapPane.zoomTowards(ev.getPoint(), 1/1.3);
- }
-
- @Override
- public void performWheel(XMapPane mapPane, MouseWheelEvent wheelEvt,
- DirectPosition coord) {
-
- double zFactor = wheelEvt.getUnitsToScroll() > 0 ? 1.3 : 1 / 1.3;
- mapPane.zoomTowards(wheelEvt.getPoint(), zFactor);
-
-// // vorher double zFactor = units > 0 ? 1/1.2 : 1.2;
-//
-// // Fenster-Koordinaten zu Karten-Koordinaten transformieren
-// Point2D mapCoord = XMapPane.getMapCoordinatesFromEvent(wheelEvt);
-// // Relative Position des Mauszeigers zum Kartenausschnitt
-// // -> Nach Zoom soll dieselbe Kartenposition unterhalb des Mauszeigers
-// // erscheinen, wie vor dem Zoom
-// double relX = (mapCoord.getX() - mapPane.getMapArea().getMinX())
-// / mapPane.getMapArea().getWidth();
-// double relY = (mapCoord.getY() - mapPane.getMapArea().getMinY())
-// / mapPane.getMapArea().getHeight();
-//
-// // Neuen Karten-Ausschnitt berechnen
-// Coordinate ll = new Coordinate(mapCoord.getX()
-// - mapPane.getMapArea().getWidth() * relX * zFactor, mapCoord.getY()
-// - mapPane.getMapArea().getHeight() * relY * zFactor);
-// Coordinate ur = new Coordinate(mapCoord.getX()
-// + mapPane.getMapArea().getWidth() * (1 - relX) * zFactor, mapCoord
-// .getY()
-// + mapPane.getMapArea().getHeight() * (1 - relY) * zFactor);
-// mapPane.setMapArea(new Envelope(ll, ur));
- }
-
- @Override
- public void performDragged(XMapPane mapPane, MouseEvent ev,
- Point dragStartPos, Point dragLastPos,
- DirectPosition startCoord, DirectPosition endCoord) {
-
- if (dragLastPos != null)
- mapPane.drawRectangle(mapPane.getGraphics(), dragStartPos,
- dragLastPos);
-
- // If this is similar to a click, let mouseClicked handle it!
- if ((Math.abs(dragStartPos.x - ev.getPoint().x) * Math.abs(ev
- .getPoint().y
- - dragStartPos.y)) < 160) {
- // performClick(mapPane, ev, coord)
- return;
- }
-
- final Rectangle bounds = mapPane.getBounds();
-
- Envelope mapArea = mapPane.getMapArea();
-
- // Replace with transform and translate
- final double mapWidth = mapArea.getWidth();
- final double mapHeight = mapArea.getHeight();
-
- final double startX = ((dragStartPos.x * mapWidth) / (double) bounds.width)
- + mapArea.getMinX();
- final double startY = (((bounds.getHeight() - dragStartPos.y) * mapHeight) / (double) bounds.height)
- + mapArea.getMinY();
- final double endX = ((ev.getPoint().x * mapWidth) / (double) bounds.width)
- + mapArea.getMinX();
- final double endY = (((bounds.getHeight() - ev.getPoint().y) * mapHeight) / (double) bounds.height)
- + mapArea.getMinY();
-
- final double left = Math.min(startX, endX);
- final double right = Math.max(startX, endX);
- final double bottom = Math.min(startY, endY);
- final double top = Math.max(startY, endY);
- final Coordinate ll = new Coordinate(left, bottom);
- final Coordinate ur = new Coordinate(right, top);
-
- mapPane.setMapArea(new Envelope(ll, ur));
-
- }
-
- /**
- * @param param is ignored
- */
- @Override
- public void performKeyboard(XMapPane mapPane, Object param) {
- mapPane.setMapArea( JTSUtil.expandEnvelope(mapPane.getMapArea(), -.10) );
- }
-
- }
-
- public static class Out extends XMapPaneAction_Zoom {
-
- /**
- * @param param is ignored
- */
- @Override
- public void performKeyboard(XMapPane mapPane, Object param) {
- mapPane.setMapArea( JTSUtil.expandEnvelope(mapPane.getMapArea(), .10) );
- }
-
- @Override
- public void performClick(XMapPane mapPane, MouseEvent ev,
- DirectPosition coord) {
-
-// mapPane.zoomTo(ev.getPoint(), 2.);
-
- mapPane.zoomTowards(ev.getPoint(), 1.3);
- }
-
- @Override
- public void performWheel(XMapPane mapPane, MouseWheelEvent wheelEvt,
- DirectPosition coord) {
-
- double zFactor = wheelEvt.getUnitsToScroll() > 0 ? 1.3 : 1 / 1.3;
- mapPane.zoomTowards(wheelEvt.getPoint(), zFactor);
-
-// int units = wheelEvt.getUnitsToScroll();
-// // Positiver Wert --> Zoom in --> Faktor < 1
-// // Negativer Wert --> Zoom out --> Faktir > 1
-//
-// // SK: 9.9.2007 zoom jetzt wie bei GoogleEarth
-// double zFactor = units > 0 ? 1.3 : 1 / 1.3;
-// // vorher double zFactor = units > 0 ? 1/1.2 : 1.2;
-//
-// // Fenster-Koordinaten zu Karten-Koordinaten transformieren
-// Point2D mapCoord = XMapPane.getMapCoordinatesFromEvent(wheelEvt);
-// // Relative Position des Mauszeigers zum Kartenausschnitt
-// // -> Nach Zoom soll dieselbe Kartenposition unterhalb des Mauszeigers
-// // erscheinen, wie vor dem Zoom
-// double relX = (mapCoord.getX() - mapPane.getMapArea().getMinX())
-// / mapPane.getMapArea().getWidth();
-// double relY = (mapCoord.getY() - mapPane.getMapArea().getMinY())
-// / mapPane.getMapArea().getHeight();
-//
-// // Neuen Karten-Ausschnitt berechnen
-// Coordinate ll = new Coordinate(mapCoord.getX()
-// - mapPane.getMapArea().getWidth() * relX * zFactor, mapCoord.getY()
-// - mapPane.getMapArea().getHeight() * relY * zFactor);
-// Coordinate ur = new Coordinate(mapCoord.getX()
-// + mapPane.getMapArea().getWidth() * (1 - relX) * zFactor, mapCoord
-// .getY()
-// + mapPane.getMapArea().getHeight() * (1 - relY) * zFactor);
-// mapPane.setMapArea(new Envelope(ll, ur));
- }
-
-
- @Override
- public void performDragged(XMapPane mapPane, MouseEvent ev,
- Point dragStartPos, Point dragLastPos,
- DirectPosition startCoord, DirectPosition endCoord) {
-
- if (dragLastPos != null)
- mapPane.drawRectangle(mapPane.getGraphics(), dragStartPos,
- dragLastPos);
-
- // If this is similar to a click, let mouseClicked handle it!
- if ((Math.abs(dragStartPos.x - ev.getPoint().x) * Math.abs(ev
- .getPoint().y
- - dragStartPos.y)) < 160) {
- // performClick(mapPane, ev, coord)
- return;
- }
-
- final Rectangle bounds = mapPane.getBounds();
-
- Envelope mapArea = mapPane.getMapArea();
-
- // Replace with transform and translate
- final double mapWidth = mapArea.getWidth();
- final double mapHeight = mapArea.getHeight();
-
- final double startX = ((dragStartPos.x * mapWidth) / (double) bounds.width)
- + mapArea.getMinX();
- final double startY = (((bounds.getHeight() - dragStartPos.y) * mapHeight) / (double) bounds.height)
- + mapArea.getMinY();
- final double endX = ((ev.getPoint().x * mapWidth) / (double) bounds.width)
- + mapArea.getMinX();
- final double endY = (((bounds.getHeight() - ev.getPoint().y) * mapHeight) / (double) bounds.height)
- + mapArea.getMinY();
-
- // make the dragged rectangle in screen coords the new map size?
- final double left = Math.min(startX, endX);
- final double right = Math.max(startX, endX);
- final double bottom = Math.min(startY, endY);
- final double top = Math.max(startY, endY);
- final double nWidth = (mapWidth * mapWidth) / (right - left);
- final double nHeight = (mapHeight * mapHeight) / (top - bottom);
- final double deltaX1 = left - mapArea.getMinX();
- final double nDeltaX1 = (deltaX1 * nWidth) / mapWidth;
- final double deltaY1 = bottom - mapArea.getMinY();
- final double nDeltaY1 = (deltaY1 * nHeight) / mapHeight;
- final Coordinate ll = new Coordinate(mapArea.getMinX() - nDeltaX1,
- mapArea.getMinY() - nDeltaY1);
- final double deltaX2 = mapArea.getMaxX() - right;
- final double nDeltaX2 = (deltaX2 * nWidth) / mapWidth;
- final double deltaY2 = mapArea.getMaxY() - top;
- final double nDeltaY2 = (deltaY2 * nHeight) / mapHeight;
- final Coordinate ur = new Coordinate(mapArea.getMaxX() + nDeltaX2,
- mapArea.getMaxY() + nDeltaY2);
-
- mapPane.setMapArea(new Envelope(ll, ur));
-
- }
- }
-}
\ No newline at end of file
Deleted: trunk/src/skrueger/geotools/XMapPaneMouseListener.java
===================================================================
--- trunk/src/skrueger/geotools/XMapPaneMouseListener.java 2010-03-03 01:48:43 UTC (rev 739)
+++ trunk/src/skrueger/geotools/XMapPaneMouseListener.java 2010-03-03 10:32:14 UTC (rev 740)
@@ -1,187 +0,0 @@
-package skrueger.geotools;
-
-import java.awt.event.ActionEvent;
-import java.awt.event.ActionListener;
-import java.awt.event.MouseEvent;
-import java.awt.event.MouseWheelEvent;
-import java.awt.geom.AffineTransform;
-import java.awt.geom.Point2D;
-import java.util.HashMap;
-import java.util.Map;
-
-import javax.swing.JComponent;
-import javax.swing.KeyStroke;
-
-import org.geotools.geometry.DirectPosition2D;
-
-import schmitzm.swing.event.MouseInputType;
-import schmitzm.swing.event.SelectiveMouseAdapter;
-
-public class XMapPaneMouseListener extends SelectiveMouseAdapter {
-
- /**
- * Holds the configuration of which {@link XMapPaneAction} is associated
- * with which {@link MouseInputType}
- **/
- Map<MouseInputType, XMapPaneAction> actions = new HashMap<MouseInputType, XMapPaneAction>(
- MouseInputType.values().length);
-
- /**
- * A reference to the {@link XMapPane} that the {@link XMapPaneAction}s will
- * be performed on.
- */
- private final XMapPane xMapPane;
-
- public XMapPaneMouseListener(XMapPane xMapPane) {
- this.xMapPane = xMapPane;
- }
-
- /**
- * Configures the instance with definitions from a {@link XMapPaneTool}
- */
- public void configure(final XMapPaneTool tool) {
- actions = tool.mouseActions;
-
- // TODO Remove any KEYSrokes registered previously
-
- // Adding configured keyboard actions
- for (final KeyStroke stroke : tool.keyAction.keySet()) {
- xMapPane.registerKeyboardAction(new ActionListener() {
-
- public void actionPerformed(final ActionEvent e) {
- XMapPaneAction action = tool.keyAction.get(stroke);
- action.performKeyboard(xMapPane, tool.keyActionParams
- .get(stroke));
- }
-
- }, stroke, JComponent.WHEN_IN_FOCUSED_WINDOW);
- }
- }
-
- @Override
- public void performMouseClicked(MouseEvent mEv) {
-
- MouseInputType key = null;
-
- switch (mEv.getButton()) {
- case MouseEvent.BUTTON1:
- key = MouseInputType.LClick;
- break;
- case MouseEvent.BUTTON3:
- key = MouseInputType.RClick;
- break;
- default:
- return;
- }
-
- XMapPaneAction action = actions.get(key);
-
- if (action == null) {
- // No action has been defined for this - no problem
- return;
- }
-
- // Calculate the coordinates in the map's CRS
- DirectPosition2D coord = XMapPane.getMapCoordinatesFromEvent(mEv);
-
- /** Call the XMapPaneAction */
- if (coord != null)
- action.performClick(xMapPane, mEv, coord);
- }
-
- @Override
- public void performMouseDragged(MouseEvent mEv) {
-
- MouseInputType key = null;
-
- switch (dragButton) {
- case MouseEvent.BUTTON1:
- key = MouseInputType.LDrag;
- break;
- case MouseEvent.BUTTON3:
- key = MouseInputType.RDrag;
- break;
- default:
- return;
- }
-
- XMapPaneAction action = actions.get(key);
-
- if (action == null) {
- // No action has been defined for this - no problem
- return;
- }
-
- // Calculate the coordinates in the map's CRS
- DirectPosition2D endCoord = XMapPane.getMapCoordinatesFromEvent(mEv);
-
- DirectPosition2D startCoord = getDragStartCoord();
-
- /** Call the XMapPaneAction */
- if (startCoord != null && endCoord != null)
- action.performDragging(xMapPane, mEv, dragStartPos, dragLastPos,
- startCoord, endCoord);
- }
-
- @Override
- public void performMouseWheelMoved(MouseWheelEvent mEv) {
-
- XMapPaneAction action = actions.get(MouseInputType.Wheel);
-
- if (action == null)
- return;
-
- // Calculate the coordinates in the map's CRS
- DirectPosition2D coord = XMapPane.getMapCoordinatesFromEvent(mEv);
-
- /** Call the XMapPaneAction */
- if (coord != null)
- action.performWheel(xMapPane, mEv, coord);
- }
-
- public void performMouseReleased(MouseEvent mEv) {
- MouseInputType key;
- switch (mEv.getButton()) {
- case MouseEvent.BUTTON1:
- key = MouseInputType.LDrag;
- break;
- case MouseEvent.BUTTON3:
- key = MouseInputType.RDrag;
- break;
- default:
- return;
- }
-
- XMapPaneAction action = actions.get(key);
-
- if (action == null)
- return;
-
- // Transform window coordinates to MapContext coordinates
-
- // Calculate the coordinates in the map's CRS
- DirectPosition2D endCoord = XMapPane.getMapCoordinatesFromEvent(mEv);
- if (endCoord == null)
- return;
-
- action.performDragged(xMapPane, mEv, dragStartPos, dragLastPos,
- getDragStartCoord(), endCoord);
- }
-
- /**
- * Returns the drag position in map CRS
- */
- public DirectPosition2D getDragStartCoord() {
-
- final AffineTransform at = xMapPane.getScreenToWorld();
- if (at == null)
- return null;
-
- Point2D transformed = at.transform(dragStartPos, null);
- DirectPosition2D startCoord = new DirectPosition2D(xMapPane
- .getMapContext().getCoordinateReferenceSystem(), transformed
- .getX(), transformed.getY());
- return startCoord;
- }
-
-}
Deleted: trunk/src/skrueger/geotools/XMapPaneTool.java
===================================================================
--- trunk/src/skrueger/geotools/XMapPaneTool.java 2010-03-03 01:48:43 UTC (rev 739)
+++ trunk/src/skrueger/geotools/XMapPaneTool.java 2010-03-03 10:32:14 UTC (rev 740)
@@ -1,464 +0,0 @@
-package skrueger.geotools;
-
-import java.awt.Cursor;
-import java.awt.event.InputEvent;
-import java.awt.event.KeyEvent;
-import java.util.HashMap;
-import java.util.Locale;
-import java.util.Map;
-
-import javax.swing.Icon;
-import javax.swing.ImageIcon;
-import javax.swing.KeyStroke;
-
-import schmitzm.lang.LangUtil;
-import schmitzm.lang.ResourceProvider;
-import schmitzm.swing.SwingUtil;
-import schmitzm.swing.event.MouseInputType;
-
-/**
- * This class combines the mapping of mouse-inputs and keyboard inputs to
- * {@link XMapPaneAction}s and provides a tool icon and a default mouse cursor.
- */
-public class XMapPaneTool implements Copyable<XMapPaneTool> {
- public static ResourceProvider RESOURCE = new ResourceProvider(
- LangUtil.extendPackagePath(MapPaneToolBar.class,
- "resource.locales.mapPaneToolbar"),
- Locale.ENGLISH);
- public static String R(String key, Object... values) {
- return RESOURCE.getString(key, values);
- }
-
- /** The cursor of the mouse if the tool is active **/
- private Cursor cursor = null;
-
- /** A tool-tip for the tool , optional **/
- private String toolTip = null;
-
- /** The icon for the button **/
- private Icon icon = null;
-
- /**
- * Defines which {@link XMapPaneAction} should be should be called when a
- * {@link MouseInputType} is triggered
- **/
- Map<MouseInputType, XMapPaneAction> mouseActions = new HashMap<MouseInputType, XMapPaneAction>();
-
- /**
- * Defines which {@link XMapPaneAction#performKeyboard(XMapPane, Object)}
- * should be called when a {@link KeyStroke} is triggered
- **/
- Map<KeyStroke, XMapPaneAction> keyAction = new HashMap<KeyStroke, XMapPaneAction>();
-
- /**
- * Defines which optional parameter should be passed to
- * {@link XMapPaneAction#performKeyboard(XMapPane, Object)} if a
- * {@link KeyStroke} is triggered
- **/
- Map<KeyStroke, Object> keyActionParams = new HashMap<KeyStroke, Object>();
-
- /**
- * The default constructor sets some default keyboard settings
- */
- public XMapPaneTool() {
- initTool();
- }
-
- /**
- * Called by the constructor. Initializes the tool actions by defining default
- * keyboard actions.
- */
- protected void initTool() {
- // + and - keys zoom
- keyAction.put(KeyStroke.getKeyStroke(KeyEvent.VK_PLUS, 0),
- XMapPaneAction.ZOOM_IN);
- keyAction.put(KeyStroke.getKeyStroke(KeyEvent.VK_MINUS, 0),
- XMapPaneAction.ZOOM_OUT);
-
- KeyStroke keyStroke;
- for (int modifier : new int[] { InputEvent.ALT_DOWN_MASK,
- InputEvent.ALT_GRAPH_DOWN_MASK,
- InputEvent.CTRL_DOWN_MASK,
- InputEvent.SHIFT_DOWN_MASK,
- InputEvent.META_DOWN_MASK }) {
- // RIGHT button pan
- keyStroke = KeyStroke.getKeyStroke(KeyEvent.VK_LEFT, modifier);
- keyAction.put(keyStroke, XMapPaneAction.PAN);
- keyActionParams.put(keyStroke, XMapPaneAction_Pan.Direction.RIGHT);
-
- // LEFT button pan
- keyStroke = KeyStroke.getKeyStroke(KeyEvent.VK_RIGHT, modifier);
- keyAction.put(keyStroke, XMapPaneAction.PAN);
- keyActionParams.put(keyStroke, XMapPaneAction_Pan.Direction.LEFT);
-
- // UP button pan
- keyStroke = KeyStroke.getKeyStroke(KeyEvent.VK_DOWN, modifier);
- keyAction.put(keyStroke, XMapPaneAction.PAN);
- keyActionParams.put(keyStroke, XMapPaneAction_Pan.Direction.UP);
-
- // DOWN button pan
- keyStroke = KeyStroke.getKeyStroke(KeyEvent.VK_UP, modifier);
- keyAction.put(keyStroke, XMapPaneAction.PAN);
- keyActionParams.put(keyStroke, XMapPaneAction_Pan.Direction.DOWN);
- }
- }
-
- /**
- * Returns a copy of the tool to derive other tools.
- */
- public XMapPaneTool copy() {
- return copyTo(null);
- }
-
- /**
- * Copies all actions of this tool to another.
- * @param tool tool to copy the actions to (if {@code null} a new
- * tool is created)
- * @return the modified or created tool
- */
- public XMapPaneTool copyTo(XMapPaneTool tool) {
- if ( tool == null )
- tool = new XMapPaneTool();
-
- tool.setCursor( getCursor() );
- tool.setIcon( getIcon() );
- tool.setToolTip( getToolTip() );
- for ( MouseInputType type : mouseActions.keySet() )
- tool.setMouseAction(type, getMouseAction(type));
- for ( KeyStroke stroke : keyAction.keySet() )
- tool.setKeyAction(stroke, getKeyAction(stroke));
- for ( KeyStroke stroke : keyActionParams.keySet() )
- tool.setKeyActionParam(stroke, getKeyActionParam(stroke));
-
- return tool;
- }
-
- /**
- * @return the {@link Cursor} that shall be set as the default mouse cursor
- * (when no button is clicked)
- */
- public Cursor getCursor() {
- return cursor;
- }
-
- /**
- * @return the {@link Cursor} that shall be set as the default mouse cursor
- * (when no button is clicked)
- */
- public void setCursor(Cursor cursor) {
- this.cursor = cursor;
- }
-
- public String getToolTip() {
- return toolTip;
- }
-
- public void setToolTip(String toolTip) {
- this.toolTip = toolTip;
- }
-
- /**
- * An icon to use if the tool is associated with a button. May be
- * <code>null</code>.
- */
- public Icon getIcon() {
- return icon;
- }
-
- /**
- * An icon to use if the tool is associated with a button. May be
- * <code>null</code>.
- */
- public void setIcon(Icon icon) {
- this.icon = icon;
- }
-
- /**
- * @return The {@link XMapPaneAction} associated with a given
- * {@link MouseInputType}
- */
- public XMapPaneAction getMouseAction(MouseInputType type) {
- return mouseActions.get(type);
- }
-
- /**
- * Sets the {@link XMapPaneAction} for a given {@link MouseInputType}
- */
- public void setMouseAction(MouseInputType type, XMapPaneAction mouseAction) {
- this.mouseActions.put(type, mouseAction);
- }
-
- /**
- * @return The {@link XMapPaneAction} associated with a {@link KeyStroke}
- */
- public XMapPaneAction getKeyAction(KeyStroke keyStroke) {
- return keyAction.get(keyStroke);
- }
-
- /**
- * Set the {@link XMapPaneAction} for a {@link KeyStroke}
- */
- public void setKeyAction(KeyStroke keyStroke, XMapPaneAction keyAction) {
- this.keyAction.put(keyStroke, keyAction);
- }
-
- /**
- * Get the optional parameter for a{@link XMapPaneAction} when triggered by
- * {@link KeyStroke}
- */
- public Object getKeyActionParam(KeyStroke keyStroke) {
- return keyActionParams.get(keyStroke);
- }
-
- /**
- * Set the optional parameter for a{@link XMapPaneAction} when triggered by
- * {@link KeyStroke}
- */
- public void setKeyActionParam(KeyStroke keyStroke, Object param) {
- this.keyActionParams.put(keyStroke, param);
- }
-
- /** This {@link XMapPaneTool} does nothing **/
- public static XMapPaneTool NO_ACTION = new XMapPaneTool();
- static {
- // Remove the keyboard mapping that are defined by the default
- // constructor
- NO_ACTION.keyAction.clear();
- NO_ACTION.keyActionParams.clear();
- }
-
- /** The configuration of the default ZOOM IN {@link XMapPaneTool} **/
- public static XMapPaneTool ZOOM_IN = new XMapPaneTool();
- static {
- ZOOM_IN.icon = new ImageIcon(
- MapView.class.getResource("resource/icons/zoom_in.png"));
- ZOOM_IN.toolTip = R("MapPaneButtons.ZoomIn.TT");
- ZOOM_IN.cursor = SwingUtil.ZOOMIN_CURSOR;
-
- // Left mouse click & drag zoom in
- ZOOM_IN.mouseActions.put(MouseInputType.LClick, XMapPaneAction.ZOOM_IN);
- ZOOM_IN.mouseActions.put(MouseInputType.LDrag, XMapPaneAction.ZOOM_IN);
-
- // Right mouse click & drag zoom out
- ZOOM_IN.mouseActions.put(MouseInputType.RClick, XMapPaneAction.ZOOM_OUT);
- ZOOM_IN.mouseActions.put(MouseInputType.RDrag, XMapPaneAction.PAN);
-
- // Mousewheel can zoom too
- ZOOM_IN.mouseActions.put(MouseInputType.Wheel, XMapPaneAction.ZOOM_IN);
- }
-
- /** The configuration of the default ZOOM IN {@link XMapPaneTool} **/
- public static XMapPaneTool ZOOM_OUT = new XMapPaneTool();
- static {
- ZOOM_OUT.icon = new ImageIcon(
- MapView.class.getResource("resource/icons/zoom_out.png"));
- ZOOM_OUT.toolTip = R("MapPaneButtons.ZoomOut.TT");
- ZOOM_OUT.cursor = SwingUtil.ZOOMOUT_CURSOR;
-
- // Left mouse click & drag zoom in
- ZOOM_OUT.mouseActions.put(MouseInputType.LClick, XMapPaneAction.ZOOM_OUT);
- ZOOM_OUT.mouseActions.put(MouseInputType.LDrag, XMapPaneAction.ZOOM_OUT);
-
- // Right mouse click & drag zoom out
- ZOOM_OUT.mouseActions.put(MouseInputType.RClick, XMapPaneAction.ZOOM_IN);
- ZOOM_OUT.mouseActions.put(MouseInputType.RDrag, XMapPaneAction.PAN);
-
- // Mousewheel can zoom
- ZOOM_OUT.mouseActions.put(MouseInputType.Wheel, XMapPaneAction.ZOOM_IN);
-
- }
-
- /** The configuration of the PAN {@link XMapPaneTool} **/
- public static final XMapPaneTool PAN = new XMapPaneTool();
- static {
- PAN.icon = new ImageIcon(
- MapView.class.getResource("resource/icons/pan.png"));
- PAN.toolTip = R("MapPaneButtons.Pan.TT");
- PAN.cursor = SwingUtil.PAN_CURSOR;
-
- // Left mouse click & drag zoom in
- PAN.mouseActions.put(MouseInputType.LClick, XMapPaneAction.PAN);
- PAN.mouseActions.put(MouseInputType.LDrag, XMapPaneAction.PAN);
-
- // Right mouse click & drag zoom out
- PAN.mouseActions.put(MouseInputType.RClick, XMapPaneAction.PAN);
- PAN.mouseActions.put(MouseInputType.RDrag, XMapPaneAction.PAN);
-
- // Mousewheel can zoom
- PAN.mouseActions.put(MouseInputType.Wheel, XMapPaneAction.ZOOM_IN);
-
- }
-
- /** A tool that will do a select_top action on the left mouse button **/
- public static final XMapPaneTool SELECTION_TOP_LAYER = new XMapPaneTool();
- static {
- SELECTION_TOP_LAYER.icon = new ImageIcon(
- MapView.class.getResource("resource/icons/selection_set.png"));
-
- SELECTION_TOP_LAYER.cursor = SwingUtil.SELECTION_SET_CURSOR;
-
- // Left mouse click & drag zoom in
- SELECTION_TOP_LAYER.mouseActions.put(MouseInputType.LClick,
- XMapPaneAction.SELECT_TOP);
- SELECTION_TOP_LAYER.mouseActions.put(MouseInputType.LDrag,
- XMapPaneAction.SELECT_TOP);
-
- SELECTION_TOP_LAYER.mouseActions.put(MouseInputType.RDrag,
- XMapPaneAction.PAN);
-
- // Mousewheel can zoom
- SELECTION_TOP_LAYER.mouseActions.put(MouseInputType.Wheel,
- XMapPaneAction.ZOOM_IN);
-
- // TODO Strg-A shoud select all
- }
-
- /** A tool that will do a select_top action on the left mouse button **/
- public static final XMapPaneTool SELECTION_ONE_FROM_TOP_LAYER = new XMapPaneTool();
- static {
- SELECTION_ONE_FROM_TOP_LAYER.icon = new ImageIcon(
- MapView.class.getResource("resource/icons/selection_set.png"));
-
- SELECTION_ONE_FROM_TOP_LAYER.cursor = SwingUtil.SELECTION_SET_CURSOR;
-
- // Left mouse click & drag zoom in
- SELECTION_ONE_FROM_TOP_LAYER.mouseActions.put(
- MouseInputType.LClick,
- XMapPaneAction.SELECT_ONE_FROM_TOP);
- SELECTION_ONE_FROM_TOP_LAYER.mouseActions.put(
- MouseInputType.LDrag,
- XMapPaneAction.SELECT_ONE_FROM_TOP);
-
- SELECTION_ONE_FROM_TOP_LAYER.mouseActions.put(MouseInputType.RDrag,
- XMapPaneAction.PAN);
-
- // Mousewheel can zoom
- SELECTION_ONE_FROM_TOP_LAYER.mouseActions.put(MouseInputType.Wheel,
- XMapPaneAction.ZOOM_IN);
-
- // TODO Strg-A shoud select all
- }
-
- /** A tool that will do a select_top action on the left mouse button **/
- public static final XMapPaneTool SELECTION_ALL_LAYERS = new XMapPaneTool();
- static {
- SELECTION_ALL_LAYERS.icon = new ImageIcon(
- MapView.class.getResource("resource/icons/selection_set.png"));
-
- SELECTION_ALL_LAYERS.cursor = SwingUtil.SELECTION_SET_CURSOR;
-
- // Left mouse click & drag zoom in
- SELECTION_ALL_LAYERS.mouseActions.put(MouseInputType.LClick,
- XMapPaneAction.SELECT_ALL);
- SELECTION_ALL_LAYERS.mouseActions.put(MouseInputType.LDrag,
- XMapPaneAction.SELECT_ALL);
-
- SELECTION_ALL_LAYERS.mouseActions.put(MouseInputType.RDrag,
- XMapPaneAction.PAN);
-
- // Mousewheel can zoom
- SELECTION_ALL_LAYERS.mouseActions.put(MouseInputType.Wheel,
- XMapPaneAction.ZOOM_IN);
-
- // TODO Strg-A shoud select all
- }
-
- /** The configuration of the INFO {@link XMapPaneTool} **/
- public static final XMapPaneTool INFO = new XMapPaneTool();
-
- static {
- INFO.icon = new ImageIcon(
- MapView.class.getResource("resource/icons/info.png"));
- INFO.toolTip = R("MapPaneButtons.Info.TT");
- INFO.cursor = SwingUtil.INFO_CURSOR;
-
- // Left mouse click & drag zoom in
- INFO.mouseActions.put(MouseInputType.LClick,
- XMapPaneAction.SELECT_ONE_FROM_TOP);
- // INFO.mouseActions.put(MouseInputType.LDrag,
- // XMapPaneAction.SELECT_ONE_FROM_TOP);
-
- INFO.mouseActions.put(MouseInputType.RDrag, XMapPaneAction.PAN);
-
- // Mousewheel can zoom
- INFO.mouseActions.put(MouseInputType.Wheel, XMapPaneAction.ZOOM_IN);
-
- }
-
- public static final XMapPaneTool SELECTION_ADD = new XMapPaneTool();
- static {
- SELECTION_ADD.icon = new ImageIcon(
- MapView.class.getResource("resource/icons/selection_add.png"));
- SELECTION_ADD.toolTip = R("MapPaneButtons.Selection.AddSelection.TT"); // TODO
- // move
- // to
- // schmitzm
-
- SELECTION_ADD.cursor = SwingUtil.SELECTION_ADD_CURSOR;
-
- // Left mouse click & drag zoom in
- SELECTION_ADD.mouseActions.put(MouseInputType.LClick,
- XMapPaneAction.SELECT_ALL);
- SELECTION_ADD.mouseActions.put(MouseInputType.LDrag,
- XMapPaneAction.SELECT_ALL);
-
- SELECTION_ADD.mouseActions.put(MouseInputType.RDrag, XMapPaneAction.PAN);
-
- // Mousewheel can zoom
- SELECTION_ADD.mouseActions.put(MouseInputType.Wheel, XMapPaneAction.ZOOM_IN);
-
- // TODO Strg-A shoud select all
- }
-
- public static final XMapPaneTool SELECTION_REMOVE = new XMapPaneTool();
- static {
- SELECTION_REMOVE.icon = new ImageIcon(
- MapView.class.getResource("resource/icons/selection_remove.png"));
- SELECTION_REMOVE.toolTip = R("MapPaneButtons.Selection.RemoveSelection.TT"); // TODO
- // move
- // to
- // schmitzm
-
- SELECTION_REMOVE.cursor = SwingUtil.SELECTION_REMOVE_CURSOR;
-
- // Left mouse click & drag zoom in
- SELECTION_REMOVE.mouseActions.put(MouseInputType.LClick,
- XMapPaneAction.SELECT_ALL);
- SELECTION_REMOVE.mouseActions.put(MouseInputType.LDrag,
- XMapPaneAction.SELECT_ALL);
-
- SELECTION_REMOVE.mouseActions.put(MouseInputType.RDrag, XMapPaneAction.PAN);
-
- // Mousewheel can zoom
- SELECTION_REMOVE.mouseActions.put(MouseInputType.Wheel,
- XMapPaneAction.ZOOM_IN);
-
- // TODO Strg-A shoud select all
- }
-
- public static final XMapPaneTool SELECTION_SET = new XMapPaneTool();
- static {
- SELECTION_SET.icon = new ImageIcon(
- MapView.class.getResource("resource/icons/selection_set.png"));
- SELECTION_SET.toolTip = R("MapPaneButtons.Selection.SetSelection.TT"); // TODO
- // move
- // to
- // schmitzm
-
- SELECTION_SET.cursor = SwingUtil.SELECTION_SET_CURSOR;
-
- // Left mouse click & drag zoom in
- SELECTION_SET.mouseActions.put(MouseInputType.LClick,
- XMapPaneAction.SELECT_ALL);
- SELECTION_SET.mouseActions.put(MouseInputType.LDrag,
- XMapPaneAction.SELECT_ALL);
-
- SELECTION_SET.mouseActions.put(MouseInputType.RDrag, XMapPaneAction.PAN);
-
- // Mousewheel can zoom
- SELECTION_SET.mouseActions.put(MouseInputType.Wheel, XMapPaneAction.ZOOM_IN);
-
- // TODO Strg-A shoud select all
- }
-
-}
Modified: trunk/src/skrueger/geotools/labelsearch/SearchResultFeature.java
===================================================================
--- trunk/src/skrueger/geotools/labelsearch/SearchResultFeature.java 2010-03-03 01:48:43 UTC (rev 739)
+++ trunk/src/skrueger/geotools/labelsearch/SearchResultFeature.java 2010-03-03 10:32:14 UTC (rev 740)
@@ -36,9 +36,9 @@
import org.opengis.display.canvas.RenderingState;
import org.opengis.feature.simple.SimpleFeature;
+import schmitzm.geotools.gui.MapRenderingStateEvent;
+import schmitzm.geotools.gui.XMapPaneEvent;
import schmitzm.geotools.map.event.JMapPaneListener;
-import schmitzm.geotools.map.event.MapPaneEvent;
-import schmitzm.geotools.map.event.MapRenderingStateEvent;
public class SearchResultFeature implements SearchResult {
final static private Logger LOGGER = Logger
@@ -91,7 +91,7 @@
boolean virgin = true;
@Override
- public void performMapPaneEvent(MapPaneEvent e) {
+ public void performMapPaneEvent(XMapPaneEvent e) {
if (virgin && e instanceof MapRenderingStateEvent) {
MapRenderingStateEvent mre = (MapRenderingStateEvent) e;
if (mre.getState() == RenderingState.ON_HOLD) {
Modified: trunk/src/skrueger/geotools/selection/FeatureMapLayerSelectionSynchronizer.java
===================================================================
--- trunk/src/skrueger/geotools/selection/FeatureMapLayerSelectionSynchronizer.java 2010-03-03 01:48:43 UTC (rev 739)
+++ trunk/src/skrueger/geotools/selection/FeatureMapLayerSelectionSynchronizer.java 2010-03-03 10:32:14 UTC (rev 740)
@@ -69,9 +69,9 @@
import schmitzm.geotools.FilterUtil;
import schmitzm.geotools.gui.SelectableXMapPane;
+import schmitzm.geotools.gui.XMapPaneEvent;
import schmitzm.geotools.map.event.FeatureSelectedEvent;
import schmitzm.geotools.map.event.JMapPaneListener;
-import schmitzm.geotools.map.event.MapPaneEvent;
import schmitzm.geotools.styling.StylingUtil;
import skrueger.geotools.MapPaneToolBar;
import skrueger.geotools.StyledFeaturesInterface;
@@ -417,7 +417,7 @@
* {@link StyledFeatureLayerSelectionModel}
*/
@Override
- public void performMapPaneEvent(MapPaneEvent e) {
+ public void performMapPaneEvent(XMapPaneEvent e) {
// Ignore event if it is caused by us or the synchronizer is disabled.
if (!isEnabled() || selectionChangeCausedByMe)
More information about the Schmitzm-commits
mailing list