[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 &lt; 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 &gt; 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&uuml;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&uuml;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&uuml;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&uuml;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&uuml;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&uuml;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&uuml;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&uuml;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&uuml;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 &lt; 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 &gt; 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 &lt; 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 &gt; 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 &lt; 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 &gt; 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&uuml;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&uuml;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&uuml;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&uuml;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&uuml;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&uuml;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&uuml;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&uuml;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&uuml;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 &lt; 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 &gt; 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 &lt; 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 &gt; 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