[Schmitzm-commits] r304 - in trunk/src: org/geotools/data org/geotools/renderer/shape schmitzm/geotools/gui skrueger

scm-commit@wald.intevation.org scm-commit at wald.intevation.org
Wed Aug 19 14:03:16 CEST 2009


Author: alfonx
Date: 2009-08-19 14:03:12 +0200 (Wed, 19 Aug 2009)
New Revision: 304

Added:
   trunk/src/org/geotools/data/shapefile/
Modified:
   trunk/src/org/geotools/renderer/shape/TransitionShapefileRenderer.java
   trunk/src/schmitzm/geotools/gui/JMapPane.java
   trunk/src/skrueger/AttributeMetaData.java
Log:
* GP/Schmitzm: The org.geotools.JMapPane has been patched: 
The problem: Clicking into the map with the InfoCLick tool took very long. The algorithm has been modified to only check for hits in layers, that actually have any visible attributes. The AttributeMetaDataMap can therefore be given to the JMapPane (#setAttributeMetaDataFor(String ID, AttributeMetaDataMap amdMap). This feature is fully transparent: If no AttributeMetadata is supplied, all works as before.

* GP-Feature: The TransitionShapefileRenderer is in use again. It speeds up Shapefile rendering, but has been reported to make the GP hang. We include this feature in 1.1 again and will try to reproduce it.

* GP-Feature: Calculation of size now ignores CSV and SVN directories


Modified: trunk/src/org/geotools/renderer/shape/TransitionShapefileRenderer.java
===================================================================
--- trunk/src/org/geotools/renderer/shape/TransitionShapefileRenderer.java	2009-08-18 12:01:45 UTC (rev 303)
+++ trunk/src/org/geotools/renderer/shape/TransitionShapefileRenderer.java	2009-08-19 12:03:12 UTC (rev 304)
@@ -1321,7 +1321,7 @@
 				if (layers[i].getQuery() != null
 						&& layers[i].getQuery().getFilter() instanceof FeatureOperationTreeFilter) {
 					layerIndexInfo[i] = STREAMING_RENDERER_INFO;
-//					LOGGER.info("Fallback to StreamingRenderer because Filter is instanceof FeatureOperationTreeFilter!");
+					LOGGER.info("Fallback to StreamingRenderer because Filter is instanceof FeatureOperationTreeFilter!");
 				} else {
 
 					ShapefileDataStore sds = (ShapefileDataStore) ds;

Modified: trunk/src/schmitzm/geotools/gui/JMapPane.java
===================================================================
--- trunk/src/schmitzm/geotools/gui/JMapPane.java	2009-08-18 12:01:45 UTC (rev 303)
+++ trunk/src/schmitzm/geotools/gui/JMapPane.java	2009-08-19 12:03:12 UTC (rev 304)
@@ -112,6 +112,8 @@
 import schmitzm.geotools.map.event.ScaleChangedEvent;
 import schmitzm.geotools.styling.StylingUtil;
 import schmitzm.swing.SwingUtil;
+import skrueger.AttributeMetaData;
+import skrueger.geotools.StyledLayerUtil;
 
 import com.vividsolutions.jts.geom.Coordinate;
 import com.vividsolutions.jts.geom.Envelope;
@@ -156,2443 +158,2554 @@
  * {@linkplain AffineTransform affine Transformation} mit der die aktuellen
  * Fenster-Koordinaten (z.B. eines <code>MouseEvent</code>) in
  * Karten-Koordinaten (Latitude/Longitude) umgerechnet werden koennen.
- *
+ * 
  * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a>
  *         (University of Bonn/Germany)
  * @version 1.0
  */
 public class JMapPane extends org.geotools.gui.swing.JMapPane {
 
-    /**
-     * SK: Nach dem Drag, soll die {@link GeoMapPane} erfahren, dass die Area
-     * veraendert wurde.
-     */
-    protected void processDrag(int x1, int y1, int x2, int y2, MouseEvent e) {
-        // MS, 26.05.2008: Zoom-Funktion der Oberklasse soll nur erfolgen, wenn
-        // diese auch fuer die WindowSelection-Aktion eingestellt ist!
-        // Wenn z.B. fuer Links-Klick ZOOM_IN eingestellt ist, fuer
-        // Links-Drag aber SELECT_TOP, dann soll kein Zoom beim
-        // Links-Drag erfolgen!!
-        // Ausnahme: Bei Rechts-Drag (Button 3) soll die Methode
-        // trotzdem aufgerufen werden fuer Pan!
-        if (getState() == ZOOM_IN && getWindowSelectionState() != ZOOM_IN
-                && e.getButton() != 3)
-            return;
-        super.processDrag(x1, y1, x2, y2, e);
+	/**
+	 * SK: Nach dem Drag, soll die {@link GeoMapPane} erfahren, dass die Area
+	 * veraendert wurde.
+	 */
+	protected void processDrag(int x1, int y1, int x2, int y2, MouseEvent e) {
+		// MS, 26.05.2008: Zoom-Funktion der Oberklasse soll nur erfolgen, wenn
+		// diese auch fuer die WindowSelection-Aktion eingestellt ist!
+		// Wenn z.B. fuer Links-Klick ZOOM_IN eingestellt ist, fuer
+		// Links-Drag aber SELECT_TOP, dann soll kein Zoom beim
+		// Links-Drag erfolgen!!
+		// Ausnahme: Bei Rechts-Drag (Button 3) soll die Methode
+		// trotzdem aufgerufen werden fuer Pan!
+		if (getState() == ZOOM_IN && getWindowSelectionState() != ZOOM_IN
+				&& e.getButton() != 3)
+			return;
+		super.processDrag(x1, y1, x2, y2, e);
 
-        // SK, 19.6.2009:
-        // Ein MapAreaChangedEvent soll nur geworfen werden, wenn auch gezoomt
-        // wurde! Irgendwie wird das auch aufgerufen, wenn man mit InfoClick
-        // tool nur click - also garkeit kein draggin gemacht hat.
-        if (( oldMapArea == null || !oldMapArea.equals(mapArea) )  && (getState() == ZOOM_IN || getState() == ZOOM_OUT))
-            fireMapPaneEvent(new MapAreaChangedEvent(this, oldMapArea, mapArea));
-    }
+		// SK, 19.6.2009:
+		// Ein MapAreaChangedEvent soll nur geworfen werden, wenn auch gezoomt
+		// wurde! Irgendwie wird das auch aufgerufen, wenn man mit InfoClick
+		// tool nur click - also garkeit kein draggin gemacht hat.
+		if ((oldMapArea == null || !oldMapArea.equals(mapArea))
+				&& (getState() == ZOOM_IN || getState() == ZOOM_OUT))
+			fireMapPaneEvent(new MapAreaChangedEvent(this, oldMapArea, mapArea));
+	}
 
-    private static final Cursor WAIT_CURSOR = Cursor
-            .getPredefinedCursor(Cursor.WAIT_CURSOR);
+	private static final Cursor WAIT_CURSOR = Cursor
+			.getPredefinedCursor(Cursor.WAIT_CURSOR);
 
-    /** Logger for debug messages. */
-    protected static final Logger LOGGER = Logger.getLogger(JMapPane.class
-            .getName());
+	/** Logger for debug messages. */
+	protected static final Logger LOGGER = Logger.getLogger(JMapPane.class
+			.getName());
 
-    /** @deprecated ersetzt durch {@link #ZOOM_IN} */
-    public static final int ZoomIn = org.geotools.gui.swing.JMapPane.ZoomIn;
-    /** @deprecated ersetzt durch {@link #ZOOM_OUT} */
-    public static final int ZoomOut = org.geotools.gui.swing.JMapPane.ZoomOut;
-    /** @deprecated ersetzt durch {@link #PAN} */
-    public static final int Pan = org.geotools.gui.swing.JMapPane.Pan;
-    /** @deprecated ersetzt durch {@link #RESET} */
-    public static final int Reset = org.geotools.gui.swing.JMapPane.Reset;
-    /** @deprecated ersetzt durch {@link #SELECT_TOP} */
-    public static final int Select = org.geotools.gui.swing.JMapPane.Select;
+	/** @deprecated ersetzt durch {@link #ZOOM_IN} */
+	public static final int ZoomIn = org.geotools.gui.swing.JMapPane.ZoomIn;
+	/** @deprecated ersetzt durch {@link #ZOOM_OUT} */
+	public static final int ZoomOut = org.geotools.gui.swing.JMapPane.ZoomOut;
+	/** @deprecated ersetzt durch {@link #PAN} */
+	public static final int Pan = org.geotools.gui.swing.JMapPane.Pan;
+	/** @deprecated ersetzt durch {@link #RESET} */
+	public static final int Reset = org.geotools.gui.swing.JMapPane.Reset;
+	/** @deprecated ersetzt durch {@link #SELECT_TOP} */
+	public static final int Select = org.geotools.gui.swing.JMapPane.Select;
 
-    /**
-     * Flag fuer Modus "Nichts machen".
-     *
-     * @see #setWindowSelectionState(int)
-     * @see #setState(int)
-     */
-    public static final int NONE = 100;
-    /**
-     * Flag fuer Modus "Zuruecksetzen". Nicht fuer Window-Auswahl moeglich!
-     *
-     * @see #setState(int)
-     */
-    public static final int RESET = org.geotools.gui.swing.JMapPane.Reset;
-    /**
-     * Flag fuer Modus "Kartenausschnitt bewegen". Nicht fuer Window-Auswahl
-     * moeglich!
-     *
-     * @see #setState(int)
-     */
-    public static final int PAN = org.geotools.gui.swing.JMapPane.Pan;
-    /**
-     * Flag fuer Modus "Heran zoomen".
-     *
-     * @see #setWindowSelectionState(int)
-     * @see #setState(int)
-     */
-    public static final int ZOOM_IN = org.geotools.gui.swing.JMapPane.ZoomIn;
-    /**
-     * Flag fuer Modus "Heraus zoomen". Nicht fuer Window-Auswahl moeglich!
-     *
-     * @see #setState(int)
-     */
-    public static final int ZOOM_OUT = org.geotools.gui.swing.JMapPane.ZoomOut;
-    /**
-     * Flag fuer Modus "Feature-Auswahl auf dem obersten (sichtbaren) Layer".
-     *
-     * @see #setWindowSelectionState(int)
-     * @see #setState(int)
-     */
-    public static final int SELECT_TOP = org.geotools.gui.swing.JMapPane.Select;
-    /**
-     * Flag fuer Modus "Feature-Auswahl auf allen (sichtbaren) Layern".
-     *
-     * @see #setWindowSelectionState(int)
-     * @see #setState(int)
-     */
-    public static final int SELECT_ALL = 103;
-    /**
-     * Flag fuer Modus
-     * "Auswahl nur eines Features, das erste sichtbare von Oben".
-     *
-     * @see #setWindowSelectionState(int)
-     * @see #setState(int)
-     */
-    public static final int SELECT_ONE_FROM_TOP = 104;
+	/**
+	 * Flag fuer Modus "Nichts machen".
+	 * 
+	 * @see #setWindowSelectionState(int)
+	 * @see #setState(int)
+	 */
+	public static final int NONE = 100;
+	/**
+	 * Flag fuer Modus "Zuruecksetzen". Nicht fuer Window-Auswahl moeglich!
+	 * 
+	 * @see #setState(int)
+	 */
+	public static final int RESET = org.geotools.gui.swing.JMapPane.Reset;
+	/**
+	 * Flag fuer Modus "Kartenausschnitt bewegen". Nicht fuer Window-Auswahl
+	 * moeglich!
+	 * 
+	 * @see #setState(int)
+	 */
+	public static final int PAN = org.geotools.gui.swing.JMapPane.Pan;
+	/**
+	 * Flag fuer Modus "Heran zoomen".
+	 * 
+	 * @see #setWindowSelectionState(int)
+	 * @see #setState(int)
+	 */
+	public static final int ZOOM_IN = org.geotools.gui.swing.JMapPane.ZoomIn;
+	/**
+	 * Flag fuer Modus "Heraus zoomen". Nicht fuer Window-Auswahl moeglich!
+	 * 
+	 * @see #setState(int)
+	 */
+	public static final int ZOOM_OUT = org.geotools.gui.swing.JMapPane.ZoomOut;
+	/**
+	 * Flag fuer Modus "Feature-Auswahl auf dem obersten (sichtbaren) Layer".
+	 * 
+	 * @see #setWindowSelectionState(int)
+	 * @see #setState(int)
+	 */
+	public static final int SELECT_TOP = org.geotools.gui.swing.JMapPane.Select;
+	/**
+	 * Flag fuer Modus "Feature-Auswahl auf allen (sichtbaren) Layern".
+	 * 
+	 * @see #setWindowSelectionState(int)
+	 * @see #setState(int)
+	 */
+	public static final int SELECT_ALL = 103;
+	/**
+	 * Flag fuer Modus
+	 * "Auswahl nur eines Features, das erste sichtbare von Oben".
+	 * 
+	 * @see #setWindowSelectionState(int)
+	 * @see #setState(int)
+	 */
+	public static final int SELECT_ONE_FROM_TOP = 104;
 
-    /** Modus fuer Window-Selektion (Default: {@link #ZOOM_IN}). */
-    protected int selState = NONE;
+	/** Modus fuer Window-Selektion (Default: {@link #ZOOM_IN}). */
+	protected int selState = NONE;
 
-    /**
-     * Transformation zwischen Fenster-Koordinaten und Karten-Koordinaten
-     * (lat/lon)
-     */
-    protected AffineTransform transform = null;
+	/**
+	 * Transformation zwischen Fenster-Koordinaten und Karten-Koordinaten
+	 * (lat/lon)
+	 */
+	protected AffineTransform transform = null;
 
-    /**
-     * Liste der angeschlossenen Listener, die auf Aktionen des MapPanes
-     * lauschen.
-     */
-    protected Vector<JMapPaneListener> mapPaneListeners = new Vector<JMapPaneListener>();
+	/**
+	 * Liste der angeschlossenen Listener, die auf Aktionen des MapPanes
+	 * lauschen.
+	 */
+	protected Vector<JMapPaneListener> mapPaneListeners = new Vector<JMapPaneListener>();
 
-    protected MouseSelectionTracker_Public selTracker = new MouseSelectionTracker_Public() {
-        public void mouseDragged(final MouseEvent event) {
-          // Wenn Fenster-Selektions-Modus auf NICHTS steht (z.B. Info-Tool),
-          // keinen Rahmen beim Draggen zeichnen
-          if ( selState == NONE  )
-            return;
-          // Wenn Zoom bereits durch Oberklasse aktiviert wird,
-          // malt diese das Rectangle
-          if ( getState() == ZOOM_IN || getState() == ZOOM_OUT )
-            return;
+	protected MouseSelectionTracker_Public selTracker = new MouseSelectionTracker_Public() {
+		public void mouseDragged(final MouseEvent event) {
+			// Wenn Fenster-Selektions-Modus auf NICHTS steht (z.B. Info-Tool),
+			// keinen Rahmen beim Draggen zeichnen
+			if (selState == NONE)
+				return;
+			// Wenn Zoom bereits durch Oberklasse aktiviert wird,
+			// malt diese das Rectangle
+			if (getState() == ZOOM_IN || getState() == ZOOM_OUT)
+				return;
 
-          super.mouseDragged(event);
-        }
+			super.mouseDragged(event);
+		}
 
-        protected void selectionPerformed(int ox, int oy, int px, int py) {
-            // MS, 20.05.2008: In performSelectionEvent(..) wurde das Zoomen
-            // wieder reingenommen, damit bei Fenster-Auswahl auch gezoomt
-            // wird, wenn der Klick-Zoom (setState(.)) deaktiviert
-            // ist. Wenn dieser jedoch ebenfalls aktiviert ist,
-            // darf an dieser Stelle nicht nochmal gezoomt werden,
-            // da sonst 2x gezoomt wird!!
-            if (getState() != ZOOM_IN)
-                performSelectionEvent(ox, oy, px, py);
-        }
-    };
+		protected void selectionPerformed(int ox, int oy, int px, int py) {
+			// MS, 20.05.2008: In performSelectionEvent(..) wurde das Zoomen
+			// wieder reingenommen, damit bei Fenster-Auswahl auch gezoomt
+			// wird, wenn der Klick-Zoom (setState(.)) deaktiviert
+			// ist. Wenn dieser jedoch ebenfalls aktiviert ist,
+			// darf an dieser Stelle nicht nochmal gezoomt werden,
+			// da sonst 2x gezoomt wird!!
+			if (getState() != ZOOM_IN)
+				performSelectionEvent(ox, oy, px, py);
+		}
+	};
 
-    private static final FilterFactoryImpl ff = FilterUtil.FILTER_FAC;
-    private static final GeometryFactory gf = FilterUtil.GEOMETRY_FAC;
+	private static final FilterFactoryImpl ff = FilterUtil.FILTER_FAC;
+	private static final GeometryFactory gf = FilterUtil.GEOMETRY_FAC;
 
-    /**
-     * A flag indicating if dispose() was already called. If true, then further
-     * use of this {@link JMapPane} is undefined.
-     */
-    private boolean disposed = false;
+	/**
+	 * A flag indicating if dispose() was already called. If true, then further
+	 * use of this {@link JMapPane} is undefined.
+	 */
+	private boolean disposed = false;
 
-    /** Listener, der auf das Mausrad lauscht und mit Zoom reagiert */
-    private MouseWheelListener mouseWheelZoomListener;
+	/** Listener, der auf das Mausrad lauscht und mit Zoom reagiert */
+	private MouseWheelListener mouseWheelZoomListener;
 
-    // /** Wenn true, dann werden RasterLayer waehrend des Panning auf
-    // setVisible(false) gesetzt **/
-    // protected boolean hideRasterLayersDuringPan = false;
-    // /** Remebers the layers that are hidden during a PAN action **/
-    // protected List<MapLayer> hiddenForPanning = new LinkedList<MapLayer>();
+	// /** Wenn true, dann werden RasterLayer waehrend des Panning auf
+	// setVisible(false) gesetzt **/
+	// protected boolean hideRasterLayersDuringPan = false;
+	// /** Remebers the layers that are hidden during a PAN action **/
+	// protected List<MapLayer> hiddenForPanning = new LinkedList<MapLayer>();
 
-    /**
-     * Wenn true, dann wird der Cursor waehrend des naechsten Repaint auf die
-     * WAIT gesetzt.
-     **/
-    private boolean setWaitCursorDuringNextRepaint;
-    /**
-     * Defines which Component to change the MouseCursor if in WAIT STATE. If
-     * unset, only THIS component is used
-     **/
-    private Component mouseWaitCursorComponent;
+	/**
+	 * Wenn true, dann wird der Cursor waehrend des naechsten Repaint auf die
+	 * WAIT gesetzt.
+	 **/
+	private boolean setWaitCursorDuringNextRepaint;
+	/**
+	 * Defines which Component to change the MouseCursor if in WAIT STATE. If
+	 * unset, only THIS component is used
+	 **/
+	private Component mouseWaitCursorComponent;
 
-    /** Cursor wenn kein Mausbutton gedrueckt wird. default oder SwingUtil.PAN **/
-    private Cursor normalCursor = Cursor
-            .getPredefinedCursor(Cursor.DEFAULT_CURSOR);
+	/** Cursor wenn kein Mausbutton gedrueckt wird. default oder SwingUtil.PAN **/
+	private Cursor normalCursor = Cursor
+			.getPredefinedCursor(Cursor.DEFAULT_CURSOR);
 
-    /**
-     * Manuell gesetzter statischer Cursor, unabhaengig von der aktuellen
-     * MapPane-Funktion
-     */
-    protected Cursor staticCursor = null;
+	/**
+	 * Manuell gesetzter statischer Cursor, unabhaengig von der aktuellen
+	 * MapPane-Funktion
+	 */
+	protected Cursor staticCursor = null;
 
-    private MouseInputAdapter dragWaitCursorListener;
+	private MouseInputAdapter dragWaitCursorListener;
 
-    /** An (transparent) image to paint over the map in the lower right corner **/
-    private BufferedImage mapImage = null;
+	/** An (transparent) image to paint over the map in the lower right corner **/
+	private BufferedImage mapImage = null;
 
-    /**
-     * Erzeugt ein neues MapPane.
-     *
-     * @param layout
-     *            Layout-Manager fuer die GUI-Komponente (z.B.
-     *            {@link BorderLayout})
-     * @param isDoubleBuffered
-     *            siehe Konstruktor der
-     *            {@linkplain org.geotools.gui.swing.JMapPane#JMapPane(LayoutManager,boolean,GTRenderer,MapContext)
-     *            Oberklasse}
-     * @param renderer
-     *            Renderer fuer die graphische Darestellung (z.B.
-     *            {@link StreamingRenderer})
-     * @param context
-     *            Verwaltung der einzelnen Layer (z.B. {@link DefaultMapContext}
-     *            ).
-     */
-    public JMapPane() {
-        this(null, true, null, null);
-    }
+	/** A cache to optionally supply AttributeMetaData to the {@link JMapPane}. */
+	final protected HashMap<String, Map<Integer, AttributeMetaData>> attributeMetaDataMapCache = new HashMap<String, Map<Integer, AttributeMetaData>>();
 
-    /**
-     * Erzeugt ein neues MapPane. Benutzt einen {@link TransitionShapefileRenderer} als default!
-     *
-     * @param layout
-     *            Layout-Manager fuer die GUI-Komponente (z.B.
-     *            {@link BorderLayout})
-     * @param isDoubleBuffered
-     *            siehe Konstruktor der
-     *            {@linkplain org.geotools.gui.swing.JMapPane#JMapPane(LayoutManager,boolean,GTRenderer,MapContext)
-     *            Oberklasse}. Bei <code>null</code> wird <code>true</code> andgenommen.
-     * @param renderer
-     *            Renderer fuer die graphische Darestellung (z.B.
-     *            {@link StreamingRenderer})
-     * @param context
-     *            Verwaltung der einzelnen Layer (z.B. {@link DefaultMapContext}
-     *            ).
-     */
-    public JMapPane(LayoutManager layout, Boolean isDoubleBuffered,
-            GTRenderer renderer, MapContext context) {
-        super(layout != null ? layout : new BorderLayout(), isDoubleBuffered != null ? isDoubleBuffered : true,
-//                renderer != null ? renderer : new TransitionShapefileRenderer(),
-                renderer != null ? renderer : new StreamingRenderer(),
-                context != null ? context : new DefaultMapContext(GTUtil.WGS84));
+	/**
+	 * Erzeugt ein neues MapPane.
+	 * 
+	 * @param layout
+	 *            Layout-Manager fuer die GUI-Komponente (z.B.
+	 *            {@link BorderLayout})
+	 * @param isDoubleBuffered
+	 *            siehe Konstruktor der
+	 *            {@linkplain org.geotools.gui.swing.JMapPane#JMapPane(LayoutManager,boolean,GTRenderer,MapContext)
+	 *            Oberklasse}
+	 * @param renderer
+	 *            Renderer fuer die graphische Darestellung (z.B.
+	 *            {@link StreamingRenderer})
+	 * @param context
+	 *            Verwaltung der einzelnen Layer (z.B. {@link DefaultMapContext}
+	 *            ).
+	 */
+	public JMapPane() {
+		this(null, true, null, null);
+	}
 
-        // Dieser Hint sorgt wohl dafuer, dass die Rasterpixel nicht
-        // interpoliert werden
-        // Ueber die Methode enableAntiAliasing(boolean) kann das
-        // rechenintensive AntiAliasing fuer Text un Vectoren eingeschaltet
-        // werden
-        RenderingHints hints = ImageUtilities.NN_INTERPOLATION_HINT;
-        getRenderer().setJava2DHints(hints);
+	/**
+	 * Erzeugt ein neues MapPane. Benutzt einen
+	 * {@link TransitionShapefileRenderer} als default!
+	 * 
+	 * @param layout
+	 *            Layout-Manager fuer die GUI-Komponente (z.B.
+	 *            {@link BorderLayout})
+	 * @param isDoubleBuffered
+	 *            siehe Konstruktor der
+	 *            {@linkplain org.geotools.gui.swing.JMapPane#JMapPane(LayoutManager,boolean,GTRenderer,MapContext)
+	 *            Oberklasse}. Bei <code>null</code> wird <code>true</code>
+	 *            andgenommen.
+	 * @param renderer
+	 *            Renderer fuer die graphische Darestellung (z.B.
+	 *            {@link StreamingRenderer})
+	 * @param context
+	 *            Verwaltung der einzelnen Layer (z.B. {@link DefaultMapContext}
+	 *            ).
+	 */
+	public JMapPane(LayoutManager layout, Boolean isDoubleBuffered,
+			GTRenderer renderer, MapContext context) {
+		super(
+				layout != null ? layout : new BorderLayout(),
+				isDoubleBuffered != null ? isDoubleBuffered : true,
+				renderer != null ? renderer : new TransitionShapefileRenderer(),
+				// renderer != null ? renderer : new StreamingRenderer(),
+				context != null ? context : new DefaultMapContext(GTUtil.WGS84));
 
-        // hints.add( new RenderingHints(RenderingHints.KEY_ANTIALIASING,
-        // RenderingHints.VALUE_ANTIALIAS_OFF ) );
-        // hints.add( new RenderingHints(RenderingHints.KEY_INTERPOLATION,
-        // RenderingHints.VALUE_INTERPOLATION_NEAREST_NEIGHBOR ) );
-        // hints.add( new RenderingHints(RenderingHints.KEY_INTERPOLATION,
-        // RenderingHints.VALUE_INTERPOLATION_BICUBIC ) );
-        // hints.add( new RenderingHints(RenderingHints.KEY_INTERPOLATION,
-        // RenderingHints.VALUE_INTERPOLATION_BILINEAR ) );
-        // hints.add( new RenderingHints(RenderingHints.KEY_ALPHA_INTERPOLATION,
-        // RenderingHints.VALUE_ALPHA_INTERPOLATION_SPEED ) );
-        // hints.add( new RenderingHints(RenderingHints.KEY_ALPHA_INTERPOLATION,
-        // RenderingHints.VALUE_ALPHA_INTERPOLATION_QUALITY ) );
-        // Map rendererParams = new HashMap();
-        // rendererParams.put("optimizedDataLoadingEnabled",new Boolean(true) );
-        // renderer.setRendererHints( rendererParams );
+		// Dieser Hint sorgt wohl dafuer, dass die Rasterpixel nicht
+		// interpoliert werden
+		// Ueber die Methode enableAntiAliasing(boolean) kann das
+		// rechenintensive AntiAliasing fuer Text un Vectoren eingeschaltet
+		// werden
+		RenderingHints hints = ImageUtilities.NN_INTERPOLATION_HINT;
+		getRenderer().setJava2DHints(hints);
 
-        setWindowSelectionState(ZOOM_IN);
-        setState(ZOOM_IN);
+		// hints.add( new RenderingHints(RenderingHints.KEY_ANTIALIASING,
+		// RenderingHints.VALUE_ANTIALIAS_OFF ) );
+		// hints.add( new RenderingHints(RenderingHints.KEY_INTERPOLATION,
+		// RenderingHints.VALUE_INTERPOLATION_NEAREST_NEIGHBOR ) );
+		// hints.add( new RenderingHints(RenderingHints.KEY_INTERPOLATION,
+		// RenderingHints.VALUE_INTERPOLATION_BICUBIC ) );
+		// hints.add( new RenderingHints(RenderingHints.KEY_INTERPOLATION,
+		// RenderingHints.VALUE_INTERPOLATION_BILINEAR ) );
+		// hints.add( new RenderingHints(RenderingHints.KEY_ALPHA_INTERPOLATION,
+		// RenderingHints.VALUE_ALPHA_INTERPOLATION_SPEED ) );
+		// hints.add( new RenderingHints(RenderingHints.KEY_ALPHA_INTERPOLATION,
+		// RenderingHints.VALUE_ALPHA_INTERPOLATION_QUALITY ) );
+		// Map rendererParams = new HashMap();
+		// rendererParams.put("optimizedDataLoadingEnabled",new Boolean(true) );
+		// renderer.setRendererHints( rendererParams );
 
-         // Listener, der auf das Mausrad lauscht und mit Zoom reagiert
-         mouseWheelZoomListener = new MouseWheelListener() {
-           public void mouseWheelMoved(MouseWheelEvent e) {
-             performMouseWheelEvent(e);
-           }
-         };
-         this.addMouseWheelListener(mouseWheelZoomListener);
+		setWindowSelectionState(ZOOM_IN);
+		setState(ZOOM_IN);
 
-        // Listener, der auf das Mausrad lauscht und mit Zoom reagiert
-        mouseWheelZoomListener = new MouseWheelListener() {
-            public void mouseWheelMoved(MouseWheelEvent e) {
-                performMouseWheelEvent(e);
-            }
-        };
-        this.addMouseWheelListener(mouseWheelZoomListener);
+		// Listener, der auf das Mausrad lauscht und mit Zoom reagiert
+		mouseWheelZoomListener = new MouseWheelListener() {
+			public void mouseWheelMoved(MouseWheelEvent e) {
+				performMouseWheelEvent(e);
+			}
+		};
+		this.addMouseWheelListener(mouseWheelZoomListener);
 
-        /**
-         * Dieser Listener setzt nach dem Panning (aka Drag) den Maus-Cursor auf
-         * Wait. Der Rest des Panning wird in der Uberklasse abgewickelt
-         */
-        dragWaitCursorListener = new MouseInputAdapter() {
-            public void mouseReleased(MouseEvent e) {
-                setWaitCursorDuringNextRepaint = true;
-            };
-        };
-        this.addMouseListener(dragWaitCursorListener);
+		// Listener, der auf das Mausrad lauscht und mit Zoom reagiert
+		mouseWheelZoomListener = new MouseWheelListener() {
+			public void mouseWheelMoved(MouseWheelEvent e) {
+				performMouseWheelEvent(e);
+			}
+		};
+		this.addMouseWheelListener(mouseWheelZoomListener);
 
-        // Hightlight immer auf dem obersten sichtbaren Nicht-Raster-Layer
-        // MS-01.sc: Der GT-Highlight-Manager arbeitet zu langsam und ohnehin
-        // nur fuer unprojizierte Layer korrekt
-        // this.setHighlight(true);
-        this.setHighlight(false);
-        // MS-01.ec
+		/**
+		 * Dieser Listener setzt nach dem Panning (aka Drag) den Maus-Cursor auf
+		 * Wait. Der Rest des Panning wird in der Uberklasse abgewickelt
+		 */
+		dragWaitCursorListener = new MouseInputAdapter() {
+			public void mouseReleased(MouseEvent e) {
+				setWaitCursorDuringNextRepaint = true;
+			};
+		};
+		this.addMouseListener(dragWaitCursorListener);
 
-        getContext().addMapLayerListListener(
-                new schmitzm.geotools.map.event.MapLayerListAdapter() {
-                    private void resetHighlightLayer() {
-                        if (isHighlight())
-                            setHighlightLayer(getTopVisibleNonGridCoverageLayer());
-                    }
+		// Hightlight immer auf dem obersten sichtbaren Nicht-Raster-Layer
+		// MS-01.sc: Der GT-Highlight-Manager arbeitet zu langsam und ohnehin
+		// nur fuer unprojizierte Layer korrekt
+		// this.setHighlight(true);
+		this.setHighlight(false);
+		// MS-01.ec
 
-                    public void layerAdded(
-                            org.geotools.map.event.MapLayerListEvent e) {
-                        resetHighlightLayer();
-                    }
+		getContext().addMapLayerListListener(
+				new schmitzm.geotools.map.event.MapLayerListAdapter() {
+					private void resetHighlightLayer() {
+						if (isHighlight())
+							setHighlightLayer(getTopVisibleNonGridCoverageLayer());
+					}
 
-                    public void layerChanged(
-                            org.geotools.map.event.MapLayerListEvent e) {
-                        resetHighlightLayer();
-                    }
+					public void layerAdded(
+							org.geotools.map.event.MapLayerListEvent e) {
+						resetHighlightLayer();
+					}
 
-                    public void layerMoved(
-                            org.geotools.map.event.MapLayerListEvent e) {
-                        resetHighlightLayer();
-                    }
+					public void layerChanged(
+							org.geotools.map.event.MapLayerListEvent e) {
+						resetHighlightLayer();
+					}
 
-                    public void layerRemoved(
-                            org.geotools.map.event.MapLayerListEvent e) {
-                        resetHighlightLayer();
-                    }
-                });
+					public void layerMoved(
+							org.geotools.map.event.MapLayerListEvent e) {
+						resetHighlightLayer();
+					}
 
-        // CRS wird immer vom ersten in die Karte eingefuegten Layer uebernommen
-        // Wenn noch keine MapArea gesetzt wurde, wird diese vom Layer
-        // uebernommen
-        getContext().addMapLayerListListener(
-                new schmitzm.geotools.map.event.MapLayerListAdapter() {
-                    public void layerAdded(
-                            org.geotools.map.event.MapLayerListEvent e) {
-                        if (getContext().getLayerCount() == 1) {
-                            CoordinateReferenceSystem crs = null;
-                            // CRS aus Layer ermitteln
-                            try {
-                                crs = e.getLayer().getFeatureSource()
-                                        .getSchema().getDefaultGeometry()
-                                        .getCoordinateSystem();
-                                // wenn noch keine MapArea gesetzt wurde, den
-                                // Ausdehnungsbereich des ersten Layers
-                                // verwenden, so dass die erste
-                                // Karte komplett angezeigt wird
-                                if (getMapArea() == null) {
-                                    Envelope newMapArea = new Envelope(e
-                                            .getLayer().getFeatureSource()
-                                            .getBounds());
-                                    // 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)
-                                    newMapArea.expandBy(
-                                            newMapArea.getWidth() * 0.1,
-                                            newMapArea.getHeight() * 0.1);
-                                    setMapArea(newMapArea);
-                                    // in layerAdded(.) der Oberklasse wird
-                                    // mapArea nochmal neu gesetzt, wenn das
-                                    // erste Layer
-                                    // eingefuegt wird
-                                    // >> hier nur die AreaOfInterest setzen
-                                    getContext().setAreaOfInterest(newMapArea,
-                                            crs);
-                                }
-                            } catch (Exception err) {
-                                LOGGER
-                                        .warn("CRS could not be determined from map layer. WGS84 used.");
-                                // err.printStackTrace();
-                                crs = DefaultGeographicCRS.WGS84;
-                            }
-                            // CRS dem MapContext zuweisen
-                            try {
-                                getContext().setCoordinateReferenceSystem(crs);
-//                                LOGGER.debug("MapContext-CRS set to: "+crs);
-                            } catch (Exception err) {
-                                LOGGER
-                                        .error("CRS could not be assigned to map context.", err);
-                            }
-                        }
-                    }
-                });
-    }
+					public void layerRemoved(
+							org.geotools.map.event.MapLayerListEvent e) {
+						resetHighlightLayer();
+					}
+				});
 
-    /**
-     * 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;
-    }
+		// CRS wird immer vom ersten in die Karte eingefuegten Layer uebernommen
+		// Wenn noch keine MapArea gesetzt wurde, wird diese vom Layer
+		// uebernommen
+		getContext().addMapLayerListListener(
+				new schmitzm.geotools.map.event.MapLayerListAdapter() {
+					public void layerAdded(
+							org.geotools.map.event.MapLayerListEvent e) {
+						if (getContext().getLayerCount() == 1) {
+							CoordinateReferenceSystem crs = null;
+							// CRS aus Layer ermitteln
+							try {
+								crs = e.getLayer().getFeatureSource()
+										.getSchema().getDefaultGeometry()
+										.getCoordinateSystem();
+								// wenn noch keine MapArea gesetzt wurde, den
+								// Ausdehnungsbereich des ersten Layers
+								// verwenden, so dass die erste
+								// Karte komplett angezeigt wird
+								if (getMapArea() == null) {
+									Envelope newMapArea = new Envelope(e
+											.getLayer().getFeatureSource()
+											.getBounds());
+									// 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)
+									newMapArea.expandBy(
+											newMapArea.getWidth() * 0.1,
+											newMapArea.getHeight() * 0.1);
+									setMapArea(newMapArea);
+									// in layerAdded(.) der Oberklasse wird
+									// mapArea nochmal neu gesetzt, wenn das
+									// erste Layer
+									// eingefuegt wird
+									// >> hier nur die AreaOfInterest setzen
+									getContext().setAreaOfInterest(newMapArea,
+											crs);
+								}
+							} catch (Exception err) {
+								LOGGER
+										.warn("CRS could not be determined from map layer. WGS84 used.");
+								// err.printStackTrace();
+								crs = DefaultGeographicCRS.WGS84;
+							}
+							// CRS dem MapContext zuweisen
+							try {
+								getContext().setCoordinateReferenceSystem(crs);
+								// LOGGER.debug("MapContext-CRS set to: "+crs);
+							} catch (Exception err) {
+								LOGGER
+										.error(
+												"CRS could not be assigned to map context.",
+												err);
+							}
+						}
+					}
+				});
+	}
 
-    /**
-     * 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(BufferedImage mapImage) {
-        this.mapImage = mapImage;
-    }
+	/**
+	 * 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;
+	}
 
-    /**
-     * Gibt die optional gesetzte {@link Component} zurueck, deren Cursor auch
-     * auf WAIT gesetzt werden soll
-     *
-     * @author <a href="mailto:skpublic at wikisquare.de">Stefan Alfons
-     *         Kr&uuml;ger</a>
-     *
-     * @return null oder {@link Component}
-     */
-    public Component getWaitCursorComponent() {
-        return mouseWaitCursorComponent;
-    }
+	/**
+	 * 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(BufferedImage mapImage) {
+		this.mapImage = mapImage;
+	}
 
-    /**
-     * Setzt eine Componente, deren Cursor zusaetzlich zu THIS noch auf WAIT
-     * gesetzt wird falls durch dies ueberhaupt durch
-     * setSetWaitCursorDuringNextRepaint(true) veranlasst wurde
-     *
-     * @param parentComponent
-     *            z.b. der Frame, der diese {@link JMapPane} enhaelt
-     *
-     * @author <a href="mailto:skpublic at wikisquare.de">Stefan Alfons
-     *         Kr&uuml;ger</a>
-     */
-    public void setWaitCursorComponent(Component parentComponent) {
-        this.mouseWaitCursorComponent = parentComponent;
-    }
+	/**
+	 * Gibt die optional gesetzte {@link Component} zurueck, deren Cursor auch
+	 * auf WAIT gesetzt werden soll
+	 * 
+	 * @author <a href="mailto:skpublic at wikisquare.de">Stefan Alfons
+	 *         Kr&uuml;ger</a>
+	 * 
+	 * @return null oder {@link Component}
+	 */
+	public Component getWaitCursorComponent() {
+		return mouseWaitCursorComponent;
+	}
 
-    /**
-     * Aktualisiert die Karten-Anzeige vollstaendig. Ruft
-     * {@link JMapPane#setReset(boolean) JMapPane#setReset(true)} auf und
-     * anschliessend {@link #repaint()}.
-     *
-     * <br>
-     * SK: Der Mauszeiger wird waehrend des repaints auf WAIT gesetzt mittels
-     * {@link #setWaitCursorDuringNextRepaint(boolean)}
-     *
-     * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a>
-     *         (University of Bonn/Germany)
-     * @author <a href="mailto:skpublic at wikisquare.de">Stefan Alfons
-     *         Kr&uuml;ger</a>
-     */
-    public void refresh() {
+	/**
+	 * Setzt eine Componente, deren Cursor zusaetzlich zu THIS noch auf WAIT
+	 * gesetzt wird falls durch dies ueberhaupt durch
+	 * setSetWaitCursorDuringNextRepaint(true) veranlasst wurde
+	 * 
+	 * @param parentComponent
+	 *            z.b. der Frame, der diese {@link JMapPane} enhaelt
+	 * 
+	 * @author <a href="mailto:skpublic at wikisquare.de">Stefan Alfons
+	 *         Kr&uuml;ger</a>
+	 */
+	public void setWaitCursorComponent(Component parentComponent) {
+		this.mouseWaitCursorComponent = parentComponent;
+	}
 
-        // SK: Added by SK, 27.09.2007
-        // Durch den reset ist das repaint immer etwas aufwaendiger. Der Cursor
-        // wechselt dann auf WAIT
-        setWaitCursorDuringNextRepaint(true);
+	/**
+	 * Aktualisiert die Karten-Anzeige vollstaendig. Ruft
+	 * {@link JMapPane#setReset(boolean) JMapPane#setReset(true)} auf und
+	 * anschliessend {@link #repaint()}.
+	 * 
+	 * <br>
+	 * SK: Der Mauszeiger wird waehrend des repaints auf WAIT gesetzt mittels
+	 * {@link #setWaitCursorDuringNextRepaint(boolean)}
+	 * 
+	 * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a>
+	 *         (University of Bonn/Germany)
+	 * @author <a href="mailto:skpublic at wikisquare.de">Stefan Alfons
+	 *         Kr&uuml;ger</a>
+	 */
+	public void refresh() {
 
-        setReset(true);
-        repaint();
-    }
+		// SK: Added by SK, 27.09.2007
+		// Durch den reset ist das repaint immer etwas aufwaendiger. Der Cursor
+		// wechselt dann auf WAIT
+		setWaitCursorDuringNextRepaint(true);
 
-    /**
-     * Aktiviert oder deaktiviert das AntiAliasing for diese {@link JMapPane}.
-     * 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 = getRenderer().getJava2DHints();
-        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);
-        getRenderer().setJava2DHints(java2DHints);
-    }
+		setReset(true);
+		repaint();
+	}
 
-    /**
-     * Setzt den Kartenausschnitt auf die Ausdehnung eines bestimmten Layers.
-     * Macht nichts, wenn {@code null} uebergeben wird.
-     *
-     * <br>
-     * A refresh of the map is NOT called.
-     *
-     * @param layer
-     *            ein Layer
-     */
-    public void zoomToLayer(MapLayer layer) {
-        if (layer == null)
-            return;
-        // This action ususally takes some time..
-        setWaitCursorDuringNextRepaint = true;
-        try {
+	/**
+	 * Aktiviert oder deaktiviert das AntiAliasing for diese {@link JMapPane}.
+	 * 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 = getRenderer().getJava2DHints();
+		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);
+		getRenderer().setJava2DHints(java2DHints);
+	}
 
-            // BB umrechnen von Layer-CRS in Map-CRS
-            final Envelope mapAreaNew = JTSUtil.transformEnvelope(layer
-                    .getFeatureSource().getBounds(), layer.getFeatureSource()
-                    .getSchema().getDefaultGeometry().getCoordinateSystem(),
-                    getContext().getCoordinateReferenceSystem());
-            // 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.expandBy(mapAreaNew.getWidth() * 0.1, mapAreaNew
-            			.getHeight() * 0.1);
-            	setMapArea(mapAreaNew);
-            } else {
-            	LOGGER.warn("Couldn't transformEnvelope when zooming to the layer");
-            }
-        } catch (Exception err) {
-            LOGGER.warn("Zoom to layer did not terminate correctly", err);
-        }
-    }
+	/**
+	 * Setzt den Kartenausschnitt auf die Ausdehnung eines bestimmten Layers.
+	 * Macht nichts, wenn {@code null} uebergeben wird.
+	 * 
+	 * <br>
+	 * A refresh of the map is NOT called.
+	 * 
+	 * @param layer
+	 *            ein Layer
+	 */
+	public void zoomToLayer(MapLayer layer) {
+		if (layer == null)
+			return;
+		// This action ususally takes some time..
+		setWaitCursorDuringNextRepaint = true;
+		try {
 
-    /**
-     * Zooms the {@link JMapPane} 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 = getContext();
-        if (context != null)
-            zoomToLayer(context.getLayer(index));
-    }
+			// BB umrechnen von Layer-CRS in Map-CRS
+			final Envelope mapAreaNew = JTSUtil.transformEnvelope(layer
+					.getFeatureSource().getBounds(), layer.getFeatureSource()
+					.getSchema().getDefaultGeometry().getCoordinateSystem(),
+					getContext().getCoordinateReferenceSystem());
+			// 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)
 
-    /**
-     * Zooms the {@link JMapPane} 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(getContext().getLayerCount() - 1 - index);
-    }
+			if (mapAreaNew != null) {
+				mapAreaNew.expandBy(mapAreaNew.getWidth() * 0.1, mapAreaNew
+						.getHeight() * 0.1);
+				setMapArea(mapAreaNew);
+			} else {
+				LOGGER
+						.warn("Couldn't transformEnvelope when zooming to the layer");
+			}
+		} catch (Exception err) {
+			LOGGER.warn("Zoom to layer did not terminate correctly", err);
+		}
+	}
 
-    /**
-     * Liefert die Anzahl der Einheiten, die ein Bildschirm-Pixel darstellt. Die
-     * Einheit ist die Grundeinheit des CRS
-     */
-    public double getScale() {
-        if (getWidth() == 0 || getMapArea() == null)
-            return 0.0;
-        return getMapArea().getWidth() / getWidth();
-    }
+	/**
+	 * Zooms the {@link JMapPane} 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 = getContext();
+		if (context != null)
+			zoomToLayer(context.getLayer(index));
+	}
 
-    /**
-     * Liefert oberste Layer (sichtbar oder unsichtbar).
-     */
-    public MapLayer getTopLayer() {
-        int count = getContext().getLayerCount();
-        return count > 0 ? getContext().getLayer(count - 1) : null;
-    }
+	/**
+	 * Zooms the {@link JMapPane} 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(getContext().getLayerCount() - 1 - index);
+	}
 
-    /**
-     * Liefert oberste sichtbare Layer.
-     */
-    public MapLayer getTopVisibleLayer() {
-        for (int i = getContext().getLayerCount() - 1; i >= 0; i--) {
-            MapLayer layer = getContext().getLayer(i);
-            if (layer.isVisible())
-                return layer;
-        }
-        return null;
-    }
+	/**
+	 * Liefert die Anzahl der Einheiten, die ein Bildschirm-Pixel darstellt. Die
+	 * Einheit ist die Grundeinheit des CRS
+	 */
+	public double getScale() {
+		if (getWidth() == 0 || getMapArea() == null)
+			return 0.0;
+		return getMapArea().getWidth() / getWidth();
+	}
 
-    /**
-     * Liefert oberste sichtbare Raster-Layer.
-     */
-    public MapLayer getTopVisibleGridCoverageLayer() {
-        for (int i = getContext().getLayerCount() - 1; i >= 0; i--) {
-            MapLayer layer = getContext().getLayer(i);
-            if (layer.isVisible() && isGridCoverageLayer(layer))
-                return layer;
-        }
-        return null;
-    }
+	/**
+	 * Liefert oberste Layer (sichtbar oder unsichtbar).
+	 */
+	public MapLayer getTopLayer() {
+		int count = getContext().getLayerCount();
+		return count > 0 ? getContext().getLayer(count - 1) : null;
+	}
 
-    /**
-     * Liefert oberste sichtbare Nicht-Raster-Layer.
-     */
-    public MapLayer getTopVisibleNonGridCoverageLayer() {
-        for (int i = getContext().getLayerCount() - 1; i >= 0; i--) {
-            MapLayer layer = getContext().getLayer(i);
-            if (layer.isVisible() && !isGridCoverageLayer(layer))
-                return layer;
-        }
-        return null;
-    }
+	/**
+	 * Liefert oberste sichtbare Layer.
+	 */
+	public MapLayer getTopVisibleLayer() {
+		for (int i = getContext().getLayerCount() - 1; i >= 0; i--) {
+			MapLayer layer = getContext().getLayer(i);
+			if (layer.isVisible())
+				return layer;
+		}
+		return null;
+	}
 
-    /**
-     * Liefert unterste Layer (sichtbar oder unsichtbar).
-     */
-    public MapLayer getBottomLayer() {
-        return getContext().getLayerCount() > 0 ? getContext().getLayer(0)
-                : null;
-    }
+	/**
+	 * Liefert oberste sichtbare Raster-Layer.
+	 */
+	public MapLayer getTopVisibleGridCoverageLayer() {
+		for (int i = getContext().getLayerCount() - 1; i >= 0; i--) {
+			MapLayer layer = getContext().getLayer(i);
+			if (layer.isVisible() && isGridCoverageLayer(layer))
+				return layer;
+		}
+		return null;
+	}
 
-    /**
-     * Setzt den Modus fuer Window-Selektion. Default ist {@link #ZOOM_IN}.
-     *
-     *
-     * <ul>
-     * <li>{@link #ZOOM_IN}: Zoom auf selektierten Bereich</li>
-     * <li>{@link #SELECT_TOP}: Auswahl der Features im selektierten Bereich des
-     * <b>obersten</b> (sichtbaren) Layers</li>
-     * <li>{@link #SELECT_ALL} Auswahl der Features im selektierten ueber alle
-     * Layer</li>
-     * <li>{@link #NONE} Nichts machen</li>
-     * </ul>
-     *
-     * @param newSelState
-     *            Modus fuer Window-Selektion
-     */
-    public void setWindowSelectionState(final int newSelState) {
-        if (newSelState != NONE && newSelState != ZOOM_IN
-                && newSelState != SELECT_TOP && newSelState != SELECT_ALL
-                && newSelState != SELECT_ONE_FROM_TOP)
-            throw new IllegalArgumentException(
-                    "Unknown selection state for window selection!");
+	/**
+	 * Liefert oberste sichtbare Nicht-Raster-Layer.
+	 */
+	public MapLayer getTopVisibleNonGridCoverageLayer() {
+		for (int i = getContext().getLayerCount() - 1; i >= 0; i--) {
+			MapLayer layer = getContext().getLayer(i);
+			if (layer.isVisible() && !isGridCoverageLayer(layer))
+				return layer;
+		}
+		return null;
+	}
 
-        // Den selTracker bei Wechsel zu NONE deaktivieren (SK), damit
-        // Selektionsfenster beim Draggen nicht mehr gezeichnet wird
-        if ((newSelState == NONE) && (selState != NONE)) {
-            this.removeMouseListener(selTracker);
-        } else
-        // Den selTracker bei Wechsel von NONE aktivieren (SK)
-        if ((newSelState != NONE) && (selState == NONE)) {
-            this.addMouseListener(selTracker);
-        }
+	/**
+	 * Liefert unterste Layer (sichtbar oder unsichtbar).
+	 */
+	public MapLayer getBottomLayer() {
+		return getContext().getLayerCount() > 0 ? getContext().getLayer(0)
+				: null;
+	}
 
-        this.selState = newSelState;
+	/**
+	 * Setzt den Modus fuer Window-Selektion. Default ist {@link #ZOOM_IN}.
+	 * 
+	 * 
+	 * <ul>
+	 * <li>{@link #ZOOM_IN}: Zoom auf selektierten Bereich</li>
+	 * <li>{@link #SELECT_TOP}: Auswahl der Features im selektierten Bereich des
+	 * <b>obersten</b> (sichtbaren) Layers</li>
+	 * <li>{@link #SELECT_ALL} Auswahl der Features im selektierten ueber alle
+	 * Layer</li>
+	 * <li>{@link #NONE} Nichts machen</li>
+	 * </ul>
+	 * 
+	 * @param newSelState
+	 *            Modus fuer Window-Selektion
+	 */
+	public void setWindowSelectionState(final int newSelState) {
+		if (newSelState != NONE && newSelState != ZOOM_IN
+				&& newSelState != SELECT_TOP && newSelState != SELECT_ALL
+				&& newSelState != SELECT_ONE_FROM_TOP)
+			throw new IllegalArgumentException(
+					"Unknown selection state for window selection!");
 
-        // Je nach Aktion den Cursor umsetzen
-        updateCursor();
-    }
+		// Den selTracker bei Wechsel zu NONE deaktivieren (SK), damit
+		// Selektionsfenster beim Draggen nicht mehr gezeichnet wird
+		if ((newSelState == NONE) && (selState != NONE)) {
+			this.removeMouseListener(selTracker);
+		} else
+		// Den selTracker bei Wechsel von NONE aktivieren (SK)
+		if ((newSelState != NONE) && (selState == NONE)) {
+			this.addMouseListener(selTracker);
+		}
 
-    /**
-     * 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(Cursor cursor) {
-        this.staticCursor = cursor;
-        if (cursor != null)
-            super.setCursor(cursor);
-    }
+		this.selState = newSelState;
 
-    /**
-     * 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;
-    }
+		// Je nach Aktion den Cursor umsetzen
+		updateCursor();
+	}
 
-    /**
-     * Abhaengig von selState wird der Cursor gesetzt
-     */
-    public void updateCursor() {
-        // wenn manueller Cursor gesetzt ist, dann diesen verwenden (unabhaengig
-        // von der aktuellen Aktion
-        if (this.staticCursor != null) {
-            setCursor(staticCursor);
-            return;
-        }
-        // Je nach Aktion den Cursor umsetzen
-        switch (this.selState) {
-        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;
-        default:
-            setCursor(getNormalCursor());
-            break;
-        }
-    }
+	/**
+	 * 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(Cursor cursor) {
+		this.staticCursor = cursor;
+		if (cursor != null)
+			super.setCursor(cursor);
+	}
 
-    /**
-     * Liefert den Modus fuer Window-Selektion.
-     *
-     * @see #setWindowSelectionState(int)
-     */
-    public int getWindowSelectionState() {
-        return this.selState;
-    }
+	/**
+	 * 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;
+	}
 
-    /**
-     * Fuegt der Map einen Listener hinzu.
-     *
-     * @param l
-     *            neuer Listener
-     */
-    public void addMapPaneListener(JMapPaneListener l) {
-        mapPaneListeners.add(l);
-    }
+	/**
+	 * Abhaengig von selState wird der Cursor gesetzt
+	 */
+	public void updateCursor() {
+		// wenn manueller Cursor gesetzt ist, dann diesen verwenden (unabhaengig
+		// von der aktuellen Aktion
+		if (this.staticCursor != null) {
+			setCursor(staticCursor);
+			return;
+		}
+		// Je nach Aktion den Cursor umsetzen
+		switch (this.selState) {
+		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;
+		default:
+			setCursor(getNormalCursor());
+			break;
+		}
+	}
 
-    /**
-     * Entfernt einen Listener von der Map.
-     *
-     * @param l
-     *            zu entfernender Listener
-     */
-    public void removeMapPaneListener(JMapPaneListener l) {
-        mapPaneListeners.remove(l);
-    }
+	/**
+	 * Liefert den Modus fuer Window-Selektion.
+	 * 
+	 * @see #setWindowSelectionState(int)
+	 */
+	public int getWindowSelectionState() {
+		return this.selState;
+	}
 
-    /**
-     * Propagiert ein Ereignis an alle angeschlossenen Listener.
-     *
-     * @param e
-     *            Ereignis
-     */
-    protected void fireMapPaneEvent(JMapPaneEvent e) {
-        for (JMapPaneListener l : mapPaneListeners)
-            l.performMapPaneEvent(e);
-    }
+	/**
+	 * Fuegt der Map einen Listener hinzu.
+	 * 
+	 * @param l
+	 *            neuer Listener
+	 */
+	public void addMapPaneListener(JMapPaneListener l) {
+		mapPaneListeners.add(l);
+	}
 
-    /**
-     * Konvertiert die Maus-Koordinaten (relativ zum <code>JMapPane</code>) in
-     * Karten-Koordinaten.
-     *
-     * @param e
-     *            Maus-Ereignis
-     */
-    public static Point2D getMapCoordinatesFromEvent(MouseEvent e) {
-        // aktuelle Geo-Position aus GeoMouseEvent ermitteln
-        if (e != null && e instanceof GeoMouseEvent)
-            try {
-                return ((GeoMouseEvent) e).getMapCoordinate(null).toPoint2D();
-            } catch (Exception err) {
-                LOGGER.error("return ((GeoMouseEvent) e).getMapCoordinate(null).toPoint2D();", err);
-            }
+	/**
+	 * Entfernt einen Listener von der Map.
+	 * 
+	 * @param l
+	 *            zu entfernender Listener
+	 */
+	public void removeMapPaneListener(JMapPaneListener l) {
+		mapPaneListeners.remove(l);
+	}
 
-        // aktuelle Geo-Position ueber Transformation des JMapPane berechnen
-        if (e != null && e.getSource() instanceof JMapPane) {
-            AffineTransform at = ((JMapPane) e.getSource()).getTransform();
-            if (at != null)
-                return at.transform(e.getPoint(), null);
-        }
+	/**
+	 * Propagiert ein Ereignis an alle angeschlossenen Listener.
+	 * 
+	 * @param e
+	 *            Ereignis
+	 */
+	protected void fireMapPaneEvent(JMapPaneEvent e) {
+		for (JMapPaneListener l : mapPaneListeners)
+			l.performMapPaneEvent(e);
+	}
 
-        return null;
-    }
+	/**
+	 * Konvertiert die Maus-Koordinaten (relativ zum <code>JMapPane</code>) in
+	 * Karten-Koordinaten.
+	 * 
+	 * @param e
+	 *            Maus-Ereignis
+	 */
+	public static Point2D getMapCoordinatesFromEvent(MouseEvent e) {
+		// aktuelle Geo-Position aus GeoMouseEvent ermitteln
+		if (e != null && e instanceof GeoMouseEvent)
+			try {
+				return ((GeoMouseEvent) e).getMapCoordinate(null).toPoint2D();
+			} catch (Exception err) {
+				LOGGER
+						.error(
+								"return ((GeoMouseEvent) e).getMapCoordinate(null).toPoint2D();",
+								err);
+			}
 
-    /**
-     * Verarbeitet die Selektion eines Karten-Ausschnitts. Erzeugt immer ein
-     * {@link GeneralSelectionEvent} fuer den ausgewaehlten Bereich. Wurden
-     * Features oder Raster selektiert, werden zudem
-     * {@link FeatureSelectedEvent FeatureSelectedEvents} (bzw.
-     * GridCoverageSelectedEvents GridCoverageSelectedEvents) ausgeloest.
-     *
-     * @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
-     */
-    protected void performSelectionEvent(int ox, int oy, int px, int py) {
-        if (getContext().getLayerCount() == 0)
-            return;
+		// aktuelle Geo-Position ueber Transformation des JMapPane berechnen
+		if (e != null && e.getSource() instanceof JMapPane) {
+			AffineTransform at = ((JMapPane) e.getSource()).getTransform();
+			if (at != null)
+				return at.transform(e.getPoint(), null);
+		}
 
-        // keine wirkliche Selektion, sondern nur ein Klick
-        if (ox == px || oy == py)
-            return;
+		return null;
+	}
 
-        // Fenster-Koordinaten in Map-Koordinaten umwandeln
-        Envelope env = tranformWindowToGeo(ox, oy, px, py);
+	/**
+	 * Verarbeitet die Selektion eines Karten-Ausschnitts. Erzeugt immer ein
+	 * {@link GeneralSelectionEvent} fuer den ausgewaehlten Bereich. Wurden
+	 * Features oder Raster selektiert, werden zudem
+	 * {@link FeatureSelectedEvent FeatureSelectedEvents} (bzw.
+	 * GridCoverageSelectedEvents GridCoverageSelectedEvents) ausgeloest.
+	 * 
+	 * @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
+	 */
+	protected void performSelectionEvent(int ox, int oy, int px, int py) {
+		if (getContext().getLayerCount() == 0)
+			return;
 
-        // Generelles Event ausloesen
-        fireMapPaneEvent(new GeneralSelectionEvent(this, env));
+		// keine wirkliche Selektion, sondern nur ein Klick
+		if (ox == px || oy == py)
+			return;
 
-        int selectState = getWindowSelectionState();
-        switch (selectState) {
-        case ZOOM_IN: // Karte neu setzen
-            this.setMapArea(env);
-            refresh(); // WICHTIG!! Damit die veraenderte Form beruecksichtigt
-            // wird!?
-            break;
-        case SELECT_TOP:
-        case SELECT_ONE_FROM_TOP:
-        case SELECT_ALL: // Features selektieren
-            boolean featuresFound = findFeaturesAndFireEvents(
-                                      new BoundingBoxFilterGenerator(env,getContext().getCoordinateReferenceSystem()),
-                                      selectState,
-                                      env
-            );
-            if (selectState == SELECT_ALL || !featuresFound)
-                findGridCoverageSubsetsAndFireEvents(env, selectState);
-            break;
-        }
-    }
+		// Fenster-Koordinaten in Map-Koordinaten umwandeln
+		Envelope env = tranformWindowToGeo(ox, oy, px, py);
 
-    /**
-     * Verarbeitet die Mausrad-Aktion, indem gezoomed wird.
-     *
-     * @param e
-     *            Mausrad-Event
-     */
-    protected void performMouseWheelEvent(MouseWheelEvent e) {
-        if (getContext().getLayerCount() == 0)
-            return;
+		// Generelles Event ausloesen
+		fireMapPaneEvent(new GeneralSelectionEvent(this, env));
 
-        int units = e.getUnitsToScroll();
-        // Positiver Wert --> Zoom in --> Faktor < 1
-        // Negativer Wert --> Zoom out --> Faktir > 1
+		int selectState = getWindowSelectionState();
+		switch (selectState) {
+		case ZOOM_IN: // Karte neu setzen
+			this.setMapArea(env);
+			refresh(); // WICHTIG!! Damit die veraenderte Form beruecksichtigt
+			// wird!?
+			break;
+		case SELECT_TOP:
+		case SELECT_ONE_FROM_TOP:
+		case SELECT_ALL: // Features selektieren
+			boolean featuresFound = findFeaturesAndFireEvents(
+					new BoundingBoxFilterGenerator(env, getContext()
+							.getCoordinateReferenceSystem()), selectState, env);
+			if (selectState == SELECT_ALL || !featuresFound)
+				findGridCoverageSubsetsAndFireEvents(env, selectState);
+			break;
+		}
+	}
 
-        // 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;
+	/**
+	 * Verarbeitet die Mausrad-Aktion, indem gezoomed wird.
+	 * 
+	 * @param e
+	 *            Mausrad-Event
+	 */
+	protected void performMouseWheelEvent(MouseWheelEvent e) {
+		if (getContext().getLayerCount() == 0)
+			return;
 
-        // Fenster-Koordinaten zu Karten-Koordinaten transformieren
-        Point2D mapCoord = getTransform().transform(e.getPoint(), null);
-        // Relative Position des Mauszeigers zum Kartenausschnitt
-        // -> Nach Zoom soll dieselbe Kartenposition unterhalb des Mauszeigers
-        // erscheinen, wie vor dem Zoom
-        double relX = (mapCoord.getX() - getMapArea().getMinX())
-                / getMapArea().getWidth();
-        double relY = (mapCoord.getY() - getMapArea().getMinY())
-                / getMapArea().getHeight();
+		int units = e.getUnitsToScroll();
+		// Positiver Wert --> Zoom in --> Faktor < 1
+		// Negativer Wert --> Zoom out --> Faktir > 1
 
-        // 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);
-        setMapArea(new Envelope(ll, ur));
+		// 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;
 
-        setWaitCursorDuringNextRepaint(true);
-        repaint();
-    }
+		// Fenster-Koordinaten zu Karten-Koordinaten transformieren
+		Point2D mapCoord = getTransform().transform(e.getPoint(), null);
+		// Relative Position des Mauszeigers zum Kartenausschnitt
+		// -> Nach Zoom soll dieselbe Kartenposition unterhalb des Mauszeigers
+		// erscheinen, wie vor dem Zoom
+		double relX = (mapCoord.getX() - getMapArea().getMinX())
+				/ getMapArea().getWidth();
+		double relY = (mapCoord.getY() - getMapArea().getMinY())
+				/ getMapArea().getHeight();
 
-    /**
-     * 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(int ox, int oy, int px, int py) {
-        AffineTransform at = getTransform();
-        Point2D geoO = at.transform(new Point2D.Double(ox, oy), null);
-        Point2D geoP = at.transform(new Point2D.Double(px, py), null);
-        return new Envelope(geoO.getX(), geoP.getX(), geoO.getY(), geoP.getY());
-    }
+		// 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);
+		setMapArea(new Envelope(ll, ur));
 
-    /**
-     * Transformiert eine Fenster-Koordinate in eine Geo-Koordinate.
-     *
-     * @param x
-     *            X-Koordinate
-     * @param y
-     *            Y-Koordinate
-     */
-    public Point2D tranformWindowToGeo(int x, int y) {
-        AffineTransform at = getTransform();
-        return at.transform(new Point2D.Double(x, y), null);
-    }
+		setWaitCursorDuringNextRepaint(true);
+		repaint();
+	}
 
-    /**
-     * Berechnet die Transformation zwischen Fenster- und Karten-Koordinaten
-     * neu.
-     */
-    protected void resetTransform() {
-        if (getMapArea() == null || getWidth() == 0 || getHeight() == 0)
-            return;
-        this.transform = new AffineTransform(
-        // Genauso wie die Fenster-Koordinaten, werden die Longitude-Koordinaten
-                // nach rechts (Osten) hin groesser
-                // --> positive Verschiebung
-                getMapArea().getWidth() / getWidth(),
-                // keine Verzerrung
-                0.0, 0.0,
-                // Waehrend die Fenster-Koordinaten nach unten hin groesser
-                // werden,
-                // werden Latitude-Koordinaten nach Sueden hin keiner
-                // --> negative Verschiebung
-                -getMapArea().getHeight() / getHeight(),
-                // Die Longitude-Koordinaten werden nach Osten hin groesser
-                // --> obere linke Ecke des Fensters hat also den Minimalwert
-                getMapArea().getMinX(),
-                // Die Latitude-Koordinaten werden nach Norden hin groesser
-                // --> obere linke Ecke des Fensters hat also den Maximalwert
-                getMapArea().getMaxY());
-    }
+	/**
+	 * 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(int ox, int oy, int px, int py) {
+		AffineTransform at = getTransform();
+		Point2D geoO = at.transform(new Point2D.Double(ox, oy), null);
+		Point2D geoP = at.transform(new Point2D.Double(px, py), null);
+		return new Envelope(geoO.getX(), geoP.getX(), geoO.getY(), geoP.getY());
+	}
 
-    /**
-     * 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 getTransform() {
-        // Workaround: Obwohl eine Karte gesetzt ist, kann es sein, dass die
-        // Transformation noch nicht gesetzt ist (da noch kein
-        // setMapArea(.)-Aufruf stattgefunden hat!)
-        if (transform == null)
-            resetTransform();
-        // nur Kopie der Transformation zurueckgeben!
-        if (transform != null)
-            return new AffineTransform(transform);
-        return null;
-    }
+	/**
+	 * Transformiert eine Fenster-Koordinate in eine Geo-Koordinate.
+	 * 
+	 * @param x
+	 *            X-Koordinate
+	 * @param y
+	 *            Y-Koordinate
+	 */
+	public Point2D tranformWindowToGeo(int x, int y) {
+		AffineTransform at = getTransform();
+		return at.transform(new Point2D.Double(x, y), null);
+	}
 
-    /**
-     * Setzt die sichtbare Karte. Danach wird die {@linkplain AffineTransform
-     * Transformation} zwischen Fenster-Koordinaten und Karten-Koordinaten neu
-     * berechnet.<br>
-     * Loest ein {@link ScaleChangedEvent aus}
-     *
-     * {@link #setMapArea(Envelope)} wird ignoriert, falls durch die neue
-     * MapArea ein nicht gueltiger Massstab entstehen wuerde UND die bisherige
-     * maparea != null ist
-     *
-     * @param env
-     *            neuer Kartenausschnitt
-     * @see #resetTransform()
-     * @see #getTransform()
-     *
-     * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a>
-     *         (University of Bonn/Germany)
-     * @author <a href="mailto:skpublic at wikisquare.de">Stefan Alfons
-     *         Kr&uuml;ger</a>
-     */
-    @Override
-    public void setMapArea(Envelope env) {
-        // **********************************************************************
-        // Ueber die Funktionen setMaxZoomScale und setMinZoomScale kann der
-        // geotools JMapPane ein gueltiger Massstabsbereich gesetzt werden.
-        // Dieser
-        // wird hier ueberprueft. (SK)
-        // **********************************************************************
-        if (super.getMapArea() != null) {
-            env = bestAllowedMapArea(env);
-        }
+	/**
+	 * Berechnet die Transformation zwischen Fenster- und Karten-Koordinaten
+	 * neu.
+	 */
+	protected void resetTransform() {
+		if (getMapArea() == null || getWidth() == 0 || getHeight() == 0)
+			return;
+		this.transform = new AffineTransform(
+		// Genauso wie die Fenster-Koordinaten, werden die Longitude-Koordinaten
+				// nach rechts (Osten) hin groesser
+				// --> positive Verschiebung
+				getMapArea().getWidth() / getWidth(),
+				// keine Verzerrung
+				0.0, 0.0,
+				// Waehrend die Fenster-Koordinaten nach unten hin groesser
+				// werden,
+				// werden Latitude-Koordinaten nach Sueden hin keiner
+				// --> negative Verschiebung
+				-getMapArea().getHeight() / getHeight(),
+				// Die Longitude-Koordinaten werden nach Osten hin groesser
+				// --> obere linke Ecke des Fensters hat also den Minimalwert
+				getMapArea().getMinX(),
+				// Die Latitude-Koordinaten werden nach Norden hin groesser
+				// --> obere linke Ecke des Fensters hat also den Maximalwert
+				getMapArea().getMaxY());
+	}
 
-        double oldScale = getScale();
-        Envelope oldEnv = getMapArea();
+	/**
+	 * 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 getTransform() {
+		// Workaround: Obwohl eine Karte gesetzt ist, kann es sein, dass die
+		// Transformation noch nicht gesetzt ist (da noch kein
+		// setMapArea(.)-Aufruf stattgefunden hat!)
+		if (transform == null)
+			resetTransform();
+		// nur Kopie der Transformation zurueckgeben!
+		if (transform != null)
+			return new AffineTransform(transform);
+		return null;
+	}
 
-        super.setMapArea(env);
+	/**
+	 * Setzt die sichtbare Karte. Danach wird die {@linkplain AffineTransform
+	 * Transformation} zwischen Fenster-Koordinaten und Karten-Koordinaten neu
+	 * berechnet.<br>
+	 * Loest ein {@link ScaleChangedEvent aus}
+	 * 
+	 * {@link #setMapArea(Envelope)} wird ignoriert, falls durch die neue
+	 * MapArea ein nicht gueltiger Massstab entstehen wuerde UND die bisherige
+	 * maparea != null ist
+	 * 
+	 * @param env
+	 *            neuer Kartenausschnitt
+	 * @see #resetTransform()
+	 * @see #getTransform()
+	 * 
+	 * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a>
+	 *         (University of Bonn/Germany)
+	 * @author <a href="mailto:skpublic at wikisquare.de">Stefan Alfons
+	 *         Kr&uuml;ger</a>
+	 */
+	@Override
+	public void setMapArea(Envelope env) {
+		// **********************************************************************
+		// Ueber die Funktionen setMaxZoomScale und setMinZoomScale kann der
+		// geotools JMapPane ein gueltiger Massstabsbereich gesetzt werden.
+		// Dieser
+		// wird hier ueberprueft. (SK)
+		// **********************************************************************
+		if (super.getMapArea() != null) {
+			env = bestAllowedMapArea(env);
+		}
 
-        resetTransform();
-        double newScale = getScale();
-        Envelope newEnv = getMapArea();
+		double oldScale = getScale();
+		Envelope oldEnv = getMapArea();
 
-        if (oldScale != newScale)
-            fireMapPaneEvent(new ScaleChangedEvent(this, oldScale, newScale));
-        if (oldEnv == null && newEnv != null || oldEnv != null
-                && !oldEnv.equals(newEnv))
-            fireMapPaneEvent(new MapAreaChangedEvent(this, oldEnv, newEnv));
-    }
+		super.setMapArea(env);
 
-    /**
-     * Reagiert auf Linksklick mit der ueber {@link #setState(int)}eingestellten
-     * Aktion und auf Rechtsklick mit Zoom-Out (sofern {@link #ZOOM_IN}-State
-     * fuer Linksklick eingestellt). Alle anderen Klicks werden ignoriert.
-     *
-     * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a>
-     *         (University of Bonn/Germany)
-     * @author <a href="mailto:skpublic at wikisquare.de">Stefan Alfons
-     *         Kr&uuml;ger</a>
-     */
-    public void mouseClicked(MouseEvent e) {
-        // wenn noch kein Layer dargestellt wird, nichts machen
-        if (getContext().getLayerCount() == 0)
-            return;
+		resetTransform();
+		double newScale = getScale();
+		Envelope newEnv = getMapArea();
 
-        // double oldScale = getScale();
-        // Envelope oldEnv = getMapArea();
+		if (oldScale != newScale)
+			fireMapPaneEvent(new ScaleChangedEvent(this, oldScale, newScale));
+		if (oldEnv == null && newEnv != null || oldEnv != null
+				&& !oldEnv.equals(newEnv))
+			fireMapPaneEvent(new MapAreaChangedEvent(this, oldEnv, newEnv));
+	}
 
-        switch (e.getButton()) {
-        // Linksklick --> Eingestellte Funktion
-        case MouseEvent.BUTTON1: // Feature-Auswahl nicht ueber die
-            // super-Funktion
-            int state = getState();
+	/**
+	 * Reagiert auf Linksklick mit der ueber {@link #setState(int)}eingestellten
+	 * Aktion und auf Rechtsklick mit Zoom-Out (sofern {@link #ZOOM_IN}-State
+	 * fuer Linksklick eingestellt). Alle anderen Klicks werden ignoriert.
+	 * 
+	 * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a>
+	 *         (University of Bonn/Germany)
+	 * @author <a href="mailto:skpublic at wikisquare.de">Stefan Alfons
+	 *         Kr&uuml;ger</a>
+	 */
+	public void mouseClicked(MouseEvent e) {
+		// wenn noch kein Layer dargestellt wird, nichts machen
+		if (getContext().getLayerCount() == 0)
+			return;
 
-            if (state == SELECT_TOP || state == SELECT_ONE_FROM_TOP
-                    || state == SELECT_ALL) {
+		// double oldScale = getScale();
+		// Envelope oldEnv = getMapArea();
 
-                /**
-                 * BEGIN StefanChange Dieser Block findet sichtbare Features im
-                 * Umkreis des Mausklicks und kümmert sich selbst um das
-                 * verschicken der Events. Dabei wird z.Zt. immer eine
-                 * FeaterCollection mit nur einem Feature verschickt. Und zwar
-                 * jenes Feature, welches am nächsten liegt.
-                 */
+		switch (e.getButton()) {
+		// Linksklick --> Eingestellte Funktion
+		case MouseEvent.BUTTON1: // Feature-Auswahl nicht ueber die
+			// super-Funktion
+			int state = getState();
 
-                // Fenster-Koordinate in Geo-Koordinate umwandelt
-                Point2D geoCoord = getTransform().transform(e.getPoint(), null);
-                com.vividsolutions.jts.geom.Point mousePoint = new GeometryFactory()
-                        .createPoint(new Coordinate(geoCoord.getX(), geoCoord
-                                .getY()));
+			if (state == SELECT_TOP || state == SELECT_ONE_FROM_TOP
+					|| state == SELECT_ALL) {
 
-                // Rechnet 10 Pixel in die Einheit der Karte um.
-                final Point pAtDistance = new Point(
-                        (int) e.getPoint().getX() + 10, (int) e.getPoint()
-                                .getY());
-                final Point2D geoCoordAtDistance = getTransform().transform(
-                        pAtDistance, null);
-                final Double dist = Math.abs(geoCoordAtDistance.getX()
-                        - geoCoord.getX());
+				/**
+				 * BEGIN StefanChange Dieser Block findet sichtbare Features im
+				 * Umkreis des Mausklicks und kümmert sich selbst um das
+				 * verschicken der Events. Dabei wird z.Zt. immer eine
+				 * FeaterCollection mit nur einem Feature verschickt. Und zwar
+				 * jenes Feature, welches am nächsten liegt.
+				 */
 
-                final Envelope envelope = new Envelope(geoCoord.getX(),
-                        geoCoord.getX(), geoCoord.getY(), geoCoord.getY());
+				// Fenster-Koordinate in Geo-Koordinate umwandelt
+				Point2D geoCoord = getTransform().transform(e.getPoint(), null);
+				com.vividsolutions.jts.geom.Point mousePoint = new GeometryFactory()
+						.createPoint(new Coordinate(geoCoord.getX(), geoCoord
+								.getY()));
 
-                Hashtable<MapLayer, FeatureCollection> result = findVisibleFeatures(
-                        new NearPointFilterGenerator(geoCoord, dist, getContext().getCoordinateReferenceSystem()),
-                        state,
-                        envelope
-                );
+				// Rechnet 10 Pixel in die Einheit der Karte um.
+				final Point pAtDistance = new Point(
+						(int) e.getPoint().getX() + 10, (int) e.getPoint()
+								.getY());
+				final Point2D geoCoordAtDistance = getTransform().transform(
+						pAtDistance, null);
+				final Double dist = Math.abs(geoCoordAtDistance.getX()
+						- geoCoord.getX());
 
-                boolean featuresFound = false;
-                // Events ausloesen fuer jedes Layer
-                for (Enumeration<MapLayer> element = result.keys(); element
-                        .hasMoreElements();) {
+				final Envelope envelope = new Envelope(geoCoord.getX(),
+						geoCoord.getX(), geoCoord.getY(), geoCoord.getY());
 
-                    MapLayer layer = element.nextElement();
-                    FeatureCollection fc = result.get(layer);
-                    FeatureCollection fcOne;
+				Hashtable<MapLayer, FeatureCollection> result = findVisibleFeatures(
+						new NearPointFilterGenerator(geoCoord, dist,
+								getContext().getCoordinateReferenceSystem()),
+						state, envelope);
 
-                    if (fc != null && !fc.isEmpty()) {
+				boolean featuresFound = false;
+				// Events ausloesen fuer jedes Layer
+				for (Enumeration<MapLayer> element = result.keys(); element
+						.hasMoreElements();) {
 
-                        if (fc.size() > 1) {
-                            // Hier werden alle Features weggeschmissen, bis auf
-                            // das raeumlich naechste.
+					MapLayer layer = element.nextElement();
+					FeatureCollection fc = result.get(layer);
+					FeatureCollection fcOne;
 
-                            Feature nearestFeature = null;
-                            Double nearestDist = 0.0;
+					if (fc != null && !fc.isEmpty()) {
 
-                            Iterator<Feature> fcIt = fc.iterator();
-                            while (fcIt.hasNext()) {
-                                Feature f = fcIt.next();
-                                Object obj = f.getAttribute(0);
+						if (fc.size() > 1) {
+							// Hier werden alle Features weggeschmissen, bis auf
+							// das raeumlich naechste.
 
-                                if (obj instanceof Geometry) {
-                                    // Bei Punkten ja noch ganz einfach:
-                                    Geometry featureGeometry = (Geometry) obj;
-                                    double distance = featureGeometry
-                                            .distance(mousePoint);
+							Feature nearestFeature = null;
+							Double nearestDist = 0.0;
 
-                                    if ((nearestFeature == null)
-                                            || (distance < nearestDist)) {
-                                        nearestFeature = f;
-                                        nearestDist = distance;
-                                    }
-                                } else {
-                                    LOGGER
-                                            .info("!obj instanceof Geometry      obj = "
-                                                    + obj.getClass()
-                                                            .getSimpleName());
-                                }
+							Iterator<Feature> fcIt = fc.iterator();
+							while (fcIt.hasNext()) {
+								Feature f = fcIt.next();
+								Object obj = f.getAttribute(0);
 
-                            }
-                            fc.close(fcIt);
+								if (obj instanceof Geometry) {
+									// Bei Punkten ja noch ganz einfach:
+									Geometry featureGeometry = (Geometry) obj;
+									double distance = featureGeometry
+											.distance(mousePoint);
 
-                            fcOne = new MemoryFeatureCollection(fc
-                                    .getFeatureType());
-                            fc.clear();
-                            fcOne.add(nearestFeature);
-                        } else {
-                            fcOne = fc;
-                        }
-                        fireMapPaneEvent(new FeatureSelectedEvent(
-                                JMapPane.this, layer, envelope, fcOne));
-                        featuresFound = true;
-                    }
-                }
+									if ((nearestFeature == null)
+											|| (distance < nearestDist)) {
+										nearestFeature = f;
+										nearestDist = distance;
+									}
+								} else {
+									LOGGER
+											.info("!obj instanceof Geometry      obj = "
+													+ obj.getClass()
+															.getSimpleName());
+								}
 
-                // TODO TODO TODO SK: DIese trennung: erst Feature layers, dann
-                // grid layers check ist doof!
-                // if (state == SELECT_ALL || !result.isEmpty())
+							}
+							fc.close(fcIt);
 
-                // LOGGER.info("state= "+state+"     featuresFound = "+
-                // featuresFound);
-                if (state == SELECT_ALL || !featuresFound) {
-                    // LOGGER.info("   findGridCoverageValuesAndFireEvents");
-                    findGridCoverageValuesAndFireEvents(geoCoord, state);
-                }
+							fcOne = new MemoryFeatureCollection(fc
+									.getFeatureType());
+							fc.clear();
+							fcOne.add(nearestFeature);
+						} else {
+							fcOne = fc;
+						}
+						fireMapPaneEvent(new FeatureSelectedEvent(
+								JMapPane.this, layer, envelope, fcOne));
+						featuresFound = true;
+					}
+				}
 
-                break;
-            }
-            super.mouseClicked(e);
-            return; // was: breka, aber wir brauchen ja nicht das
-            // setMapArea(mapArea)
+				// TODO TODO TODO SK: DIese trennung: erst Feature layers, dann
+				// grid layers check ist doof!
+				// if (state == SELECT_ALL || !result.isEmpty())
 
-            // Rechtsklick --> Zoom-Out
-        case MouseEvent.BUTTON3:
-            int oldState = getState();
-            // MS: ist doch eleganter, wenn IMMER mit Rechtsklick raus-gezoomt
-            // werden kann!
-            // // ZOOM_OUT nur wenn Links-Klick auf ZOOM_IN eingestellt ist)
-            // if ( oldState != ZOOM_IN )
-            // return;
-            setState(ZOOM_OUT);
-            super.mouseClicked(e);
-            setState(oldState);
-            break;
-        // Sonst nix
-        default:
-            return;
-        }
+				// LOGGER.info("state= "+state+"     featuresFound = "+
+				// featuresFound);
+				if (state == SELECT_ALL || !featuresFound) {
+					// LOGGER.info("   findGridCoverageValuesAndFireEvents");
+					findGridCoverageValuesAndFireEvents(geoCoord, state);
+				}
 
-        // In super.mouseClicked(.) wird (nach Zoom) die MapArea neu gesetzt,
-        // aber
-        // leider ohne setMapArea(.) aufzurufen, sondern indem einfach die
-        // Variable
-        // 'mapArea' neu belegt wird
-        // --> Transform muss neu berechnet werden
-        // --> Aenderung der Aufloesung propagieren
+				break;
+			}
+			super.mouseClicked(e);
+			return; // was: breka, aber wir brauchen ja nicht das
+			// setMapArea(mapArea)
 
-        setMapArea(mapArea);
-        // resetTransform();
-        // double newScale = getScale();
-        // Envelope newEnv = getMapArea();
-        // if ( oldScale != newScale )
-        // fireMapPaneEvent( new ScaleChangedEvent(this,oldScale,newScale) );
-        // if ( oldEnv == null && newEnv != null || oldEnv != null &&
-        // !oldEnv.equals( newEnv ) )
-        // fireMapPaneEvent( new MapAreaChangedEvent(this,oldEnv,newEnv) );
-    }
+			// Rechtsklick --> Zoom-Out
+		case MouseEvent.BUTTON3:
+			int oldState = getState();
+			// MS: ist doch eleganter, wenn IMMER mit Rechtsklick raus-gezoomt
+			// werden kann!
+			// // ZOOM_OUT nur wenn Links-Klick auf ZOOM_IN eingestellt ist)
+			// if ( oldState != ZOOM_IN )
+			// return;
+			setState(ZOOM_OUT);
+			super.mouseClicked(e);
+			setState(oldState);
+			break;
+		// Sonst nix
+		default:
+			return;
+		}
 
-    /**
-     * In <code>super.paintComponent(.)</code> wird unter gewissen Umstaenden
-     * die MapArea neu gesetzt, aber leider ohne {@link #setMapArea(Envelope)}
-     * aufzurufen, sondern indem einfach die Variable <code>mapArea</code> neu
-     * belegt wird. Damit auch die Transformation an den neuen Kartenbereich
-     * angepasst wird, muss diese Methode ueberschrieben werden.
-     * <p>
-     * Neu von SK: Ich habe in der Geotools
-     * {@link org.geotools.gui.swing.JMapPane} die noetigen variablen protected
-     * gemacht, um hier schon festzustellen, ob der aufruf von
-     * super.paintComponent das eigentliche aussehen der Karte veraendern wird.
-     * Die Methode paintComponent wird naemlich bei jeder Bewegung der Maus
-     * aufgerufen, und meistens wird super.paintComponent nur ein gebufferted
-     * Image auf den Ausschnitt zeichnen. Falls die "seriouseChange" zu erwarten
-     * ist, wird evt. der Mauscursor auf WAIT gesetzt, und auf jeden Fall die
-     * Methode {@link #resetTransform()} aufgerufen.<br>
-     * Sinn des Ganzen? Ich habe versucht etwas Performance zu gewinnen, da
-     * sonst bei jeder Mausbewegung die die {@link AffineTransform} durch
-     * {@link #resetTransform()} neu berechnet wurde.
-     *
-     * @param g
-     *            Graphics
-     * @see #resetTransform()
-     *
-     * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a>
-     *         (University of Bonn/Germany)
-     * @author <a href="mailto:skpublic at wikisquare.de">Stefan Alfons
-     *         Kr&uuml;ger</a>
-     */
-    protected void paintComponent(Graphics g) {
-    	
-//    	if (!reset) return; // TEST TEST TETS ONLY REMOVE!!
-    	
-        Cursor oldCursor = null;
-        boolean seriouseChange = false;
-        
-        if (!getBounds().equals(oldRect) || reset)
-            seriouseChange = true;
-        else if (!mapArea.equals(oldMapArea))
-            seriouseChange = true;
+		// In super.mouseClicked(.) wird (nach Zoom) die MapArea neu gesetzt,
+		// aber
+		// leider ohne setMapArea(.) aufzurufen, sondern indem einfach die
+		// Variable
+		// 'mapArea' neu belegt wird
+		// --> Transform muss neu berechnet werden
+		// --> Aenderung der Aufloesung propagieren
 
-        if (seriouseChange) {
-            if (setWaitCursorDuringNextRepaint) {
+		setMapArea(mapArea);
+		// resetTransform();
+		// double newScale = getScale();
+		// Envelope newEnv = getMapArea();
+		// if ( oldScale != newScale )
+		// fireMapPaneEvent( new ScaleChangedEvent(this,oldScale,newScale) );
+		// if ( oldEnv == null && newEnv != null || oldEnv != null &&
+		// !oldEnv.equals( newEnv ) )
+		// fireMapPaneEvent( new MapAreaChangedEvent(this,oldEnv,newEnv) );
+	}
 
-                if (getWaitCursorComponent() != null) {
-                    // Der Cursor soll auch in einer anderen Component geaendert
-                    // werden..
-                    oldCursor = getWaitCursorComponent().getCursor();
-                    getWaitCursorComponent().setCursor(WAIT_CURSOR);
-                }
+	/**
+	 * In <code>super.paintComponent(.)</code> wird unter gewissen Umstaenden
+	 * die MapArea neu gesetzt, aber leider ohne {@link #setMapArea(Envelope)}
+	 * aufzurufen, sondern indem einfach die Variable <code>mapArea</code> neu
+	 * belegt wird. Damit auch die Transformation an den neuen Kartenbereich
+	 * angepasst wird, muss diese Methode ueberschrieben werden.
+	 * <p>
+	 * Neu von SK: Ich habe in der Geotools
+	 * {@link org.geotools.gui.swing.JMapPane} die noetigen variablen protected
+	 * gemacht, um hier schon festzustellen, ob der aufruf von
+	 * super.paintComponent das eigentliche aussehen der Karte veraendern wird.
+	 * Die Methode paintComponent wird naemlich bei jeder Bewegung der Maus
+	 * aufgerufen, und meistens wird super.paintComponent nur ein gebufferted
+	 * Image auf den Ausschnitt zeichnen. Falls die "seriouseChange" zu erwarten
+	 * ist, wird evt. der Mauscursor auf WAIT gesetzt, und auf jeden Fall die
+	 * Methode {@link #resetTransform()} aufgerufen.<br>
+	 * Sinn des Ganzen? Ich habe versucht etwas Performance zu gewinnen, da
+	 * sonst bei jeder Mausbewegung die die {@link AffineTransform} durch
+	 * {@link #resetTransform()} neu berechnet wurde.
+	 * 
+	 * @param g
+	 *            Graphics
+	 * @see #resetTransform()
+	 * 
+	 * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a>
+	 *         (University of Bonn/Germany)
+	 * @author <a href="mailto:skpublic at wikisquare.de">Stefan Alfons
+	 *         Kr&uuml;ger</a>
+	 */
+	protected void paintComponent(Graphics g) {
 
-                // Den Cursor extra nochmal in dieser COmponente aendern
-                setCursor(WAIT_CURSOR);
-            }
-        }
+		// if (!reset) return; // TEST TEST TETS ONLY REMOVE!!
 
-        try {
-//        	if (!seriouseChange) {
-//        		LOGGER.info("No seriouse Change => reset = false");
-//        		reset= false;
-//        	}
-            super.paintComponent(g);
-        } catch (Exception e) {
-            /**
-             * I only need to catch UnknownHostException.. well...
-             */
-            LOGGER.info("Error during JMapPane printComponent. Probably we are offline and reference some online SVGs?", e);
-        }
-        if (seriouseChange) {
-            resetTransform();
-            if (setWaitCursorDuringNextRepaint) {
-                setWaitCursorDuringNextRepaint = false;
-                if (oldCursor != null)
-                    getWaitCursorComponent().setCursor(oldCursor);
-                updateCursor(); // Den Cursor in dieser Componente immer wieder
-                // herstellen
-            }
+		Cursor oldCursor = null;
+		boolean seriouseChange = false;
 
-            /**
-             * Paint an icon in the lower right corner. FeatureRequest: [#717]
-             * MapIcon has long been disabled and should come back
-             */
-            if (mapImage != null && baseImage != null) {
-                baseImage
-                        .getGraphics()
-                        .drawImage(
-                                mapImage,
-                                baseImage.getWidth() - mapImage.getWidth() - 10,
-                                baseImage.getHeight() - mapImage.getHeight()
-                                        - 10, this);
-                // Repaint with the cached image (fast) which now contains the
-                // logo
-                super.paintComponent(g);
-            }
-        }
+		if (!getBounds().equals(oldRect) || reset)
+			seriouseChange = true;
+		else if (!mapArea.equals(oldMapArea))
+			seriouseChange = true;
 
-    }
+		if (seriouseChange) {
+			if (setWaitCursorDuringNextRepaint) {
 
-    /**
-     * Testet (anhand der Bounding-Box), ob das Objekt eines Layers eine andere
-     * Bounding-Box schneidet. Die Bounding-Box des Layer-Objekts wird zunaechst
-     * in das CRS des MapPanes umgerechnets.
-     *
-     * @param layer
-     *            ein Layer
-     * @param env
-     *            Bounding-Box in CRS des MapPane
-     */
-    private boolean gridLayerIntersectsEnvelope(MapLayer layer, Envelope env) {
-        try {
-            // BB des Layers umrechnen von Layer-CRS in Map-CRS
-            Envelope bounds_MapCRS = JTSUtil.transformEnvelope(layer
-                    .getFeatureSource().getBounds(), layer.getFeatureSource()
-                    .getSchema().getDefaultGeometry().getCoordinateSystem(),
-                    getContext().getCoordinateReferenceSystem());
+				if (getWaitCursorComponent() != null) {
+					// Der Cursor soll auch in einer anderen Component geaendert
+					// werden..
+					oldCursor = getWaitCursorComponent().getCursor();
+					getWaitCursorComponent().setCursor(WAIT_CURSOR);
+				}
 
-            // TODO warum kann bounds_MapCRS == null sein ?? ?SK fragt martin???
-            if (bounds_MapCRS == null)
-                return false;
+				// Den Cursor extra nochmal in dieser COmponente aendern
+				setCursor(WAIT_CURSOR);
+			}
+		}
 
-            return bounds_MapCRS.intersects(env);
-        } catch (Exception err) {
-            return false;
-        }
-    }
+		try {
+			// if (!seriouseChange) {
+			// LOGGER.info("No seriouse Change => reset = false");
+			// reset= false;
+			// }
+			super.paintComponent(g);
+		} catch (Exception e) {
+			/**
+			 * I only need to catch UnknownHostException.. well...
+			 */
+			LOGGER
+					.info(
+							"Error during JMapPane printComponent. Probably we are offline and reference some online SVGs?",
+							e);
+		}
+		if (seriouseChange) {
+			resetTransform();
+			if (setWaitCursorDuringNextRepaint) {
+				setWaitCursorDuringNextRepaint = false;
+				if (oldCursor != null)
+					getWaitCursorComponent().setCursor(oldCursor);
+				updateCursor(); // Den Cursor in dieser Componente immer wieder
+				// herstellen
+			}
 
-    /**
-     * Testet (anhand der Features), ob das Objekt eines Layers eine
-     * Bounding-Box schneidet.
-     *
-     * @param layer
-     *            ein Layer
-     * @param env
-     *            Bounding-Box in CRS des MapPane
-     */
-    private boolean featureLayerIntersectsEnvelope(MapLayer layer, Envelope env) {
-        try {
-//          // BB umrechnen von Map-CRS in Layer-CRS
-//          Envelope env_LayerCRS = JTSUtil.transformEnvelope(env, getContext()
-//                  .getCoordinateReferenceSystem(), layer.getFeatureSource()
-//                  .getSchema().getDefaultGeometry().getCoordinateSystem());
-//          GeometryFilterImpl filter = createBoundingBoxFilter(env_LayerCRS);
-//          Expression geometry = ff.createAttributeExpression(layer
-//                  .getFeatureSource().getSchema().getDefaultGeometry()
-//                  .getLocalName());
-//          filter.setExpression1(geometry);
-            GeometryFilterImpl filter = new BoundingBoxFilterGenerator(
-                                               env,
-                                               getContext().getCoordinateReferenceSystem()
-            ).adaptFilter(layer.getFeatureSource());
-            return !layer.getFeatureSource().getFeatures(filter).isEmpty();
-        } catch (Exception err) {
-            return false;
-        }
-    }
+			/**
+			 * Paint an icon in the lower right corner. FeatureRequest: [#717]
+			 * MapIcon has long been disabled and should come back
+			 */
+			if (mapImage != null && baseImage != null) {
+				baseImage
+						.getGraphics()
+						.drawImage(
+								mapImage,
+								baseImage.getWidth() - mapImage.getWidth() - 10,
+								baseImage.getHeight() - mapImage.getHeight()
+										- 10, this);
+				// Repaint with the cached image (fast) which now contains the
+				// logo
+				super.paintComponent(g);
+			}
+		}
 
-    /**
-     * Ermittelt alle sichtbaren Features, die einen Filter erfuellen. Beim
-     * Modus {@link #SELECT_TOP} wird nur das oberste sichtbare Layer
-     * durchsucht. Beim Modus {@link #SELECT_ALL} werden alle sichtbaren Layer
-     * durchsucht.
-     *
-     * @see #findFeatures(GeometryFilterImpl, int, Envelope)
-     *
-     * @param filterGenerator
-     *            adapts the filter to a concrete FeatureSource
-     * @param mode
-     *            Suchmodus
-     * @return eine leere {@link Hashtable} falls der Filter {@code null} ist
-     */
-    protected Hashtable<MapLayer, FeatureCollection> findVisibleFeatures(
-            GeomFilterGenerator filterGenerator, int mode, Envelope env) {
-        Hashtable<MapLayer, FeatureCollection> result = new Hashtable<MapLayer, FeatureCollection>();
-        if (filterGenerator == null)
-            return result;
+	}
 
-        // Je nach Modus: Alle oder nur das oberste Layer
-        MapContext context = getContext();
-        MapLayer[] layerList = context.getLayers();
-        for (int i = layerList.length - 1; i >= 0; i--) {
-            MapLayer layer = layerList[i];
-            if (!layer.isVisible())
-                continue;
+	/**
+	 * Testet (anhand der Bounding-Box), ob das Objekt eines Layers eine andere
+	 * Bounding-Box schneidet. Die Bounding-Box des Layer-Objekts wird zunaechst
+	 * in das CRS des MapPanes umgerechnets.
+	 * 
+	 * @param layer
+	 *            ein Layer
+	 * @param env
+	 *            Bounding-Box in CRS des MapPane
+	 */
+	private boolean gridLayerIntersectsEnvelope(MapLayer layer, Envelope env) {
+		try {
+			// BB des Layers umrechnen von Layer-CRS in Map-CRS
+			Envelope bounds_MapCRS = JTSUtil.transformEnvelope(layer
+					.getFeatureSource().getBounds(), layer.getFeatureSource()
+					.getSchema().getDefaultGeometry().getCoordinateSystem(),
+					getContext().getCoordinateReferenceSystem());
 
-            // Bei einem Raster-Layer, das die BB schneidet, abbrechen, wenn nur
-            // im obersten (sichtbaren) Layer gesucht wird.
-            // Ansonsten Raster-Layer einfach uebergehen.
-            if (isGridCoverageLayer(layer)) {
-                if (mode == SELECT_TOP && gridLayerIntersectsEnvelope(layer, env))
-                    break;
-                continue;
-            }
+			// TODO warum kann bounds_MapCRS == null sein ?? ?SK fragt martin???
+			if (bounds_MapCRS == null)
+				return false;
 
-            // Filter an Layer koppeln
-            // WICHTIG: Dies darf erst geschehen, NACHDEM das
-            // Schleifen-Abbruch-Kriterium
-            // fuer die Raster-Layer geprueft wurde!!
-            // Werden folgende Zeilen naemlich auf das FeatureSource des
-            // Raster-Layers angewandt, dann "bricht" der Filter "irgendwie"
-            // zusammen und auch die ZUVOR gefilterten FeatureCollections,
-            // sind ploetzlich EMPTY!!!!!!!!!!!!!!!!!!!!!!!!!!!
-            final FeatureSource      featureSource = layer.getFeatureSource();
-            final GeometryFilterImpl distancefilter = filterGenerator.adaptFilter(featureSource);
+			return bounds_MapCRS.intersects(env);
+		} catch (Exception err) {
+			return false;
+		}
+	}
 
-            /**
-             * 8.8.2008: SK Wenn für das Layer auch ein Filter aktiv ist, dann
-             * soll dieser mit AND an den distanceFilter gebunden werden.
-             * "Filter filter" ist entweder der distanceFilter oder
-             * (distanceFilter AND layerFilter)
-             */
-            Filter filter = distancefilter;
-            if (layer.getQuery() != null) {
-                final Filter layerFilter = layer.getQuery().getFilter();
-                if (layerFilter != null) {
-                    filter = distancefilter.and(layerFilter);
-                }
-            }
+	/**
+	 * Testet (anhand der Features), ob das Objekt eines Layers eine
+	 * Bounding-Box schneidet.
+	 * 
+	 * @param layer
+	 *            ein Layer
+	 * @param env
+	 *            Bounding-Box in CRS des MapPane
+	 */
+	private boolean featureLayerIntersectsEnvelope(MapLayer layer, Envelope env) {
+		try {
+			// // BB umrechnen von Map-CRS in Layer-CRS
+			// Envelope env_LayerCRS = JTSUtil.transformEnvelope(env,
+			// getContext()
+			// .getCoordinateReferenceSystem(), layer.getFeatureSource()
+			// .getSchema().getDefaultGeometry().getCoordinateSystem());
+			// GeometryFilterImpl filter =
+			// createBoundingBoxFilter(env_LayerCRS);
+			// Expression geometry = ff.createAttributeExpression(layer
+			// .getFeatureSource().getSchema().getDefaultGeometry()
+			// .getLocalName());
+			// filter.setExpression1(geometry);
+			GeometryFilterImpl filter = new BoundingBoxFilterGenerator(env,
+					getContext().getCoordinateReferenceSystem())
+					.adaptFilter(layer.getFeatureSource());
+			return !layer.getFeatureSource().getFeatures(filter).isEmpty();
+		} catch (Exception err) {
+			return false;
+		}
+	}
 
-            try {
-                // Filter auf Layer des Features anwenden
-                // FeatureCollection fc = layer.getFeatureSource().getFeatures(
-                // FilterUtil.cloneFilter(filter) ); // KLAPPT (NOCH) NICHT
-                // FeatureCollection fc = featureSource.getFeatures(
-                // distancefilter );
-                FeatureCollection fc = featureSource.getFeatures(filter);
+	/**
+	 * Ermittelt alle sichtbaren Features, die einen Filter erfuellen. Beim
+	 * Modus {@link #SELECT_TOP} wird nur das oberste sichtbare Layer
+	 * durchsucht. Beim Modus {@link #SELECT_ALL} werden alle sichtbaren Layer
+	 * durchsucht.
+	 * 
+	 * @see #findFeatures(GeometryFilterImpl, int, Envelope)
+	 * 
+	 * @param filterGenerator
+	 *            adapts the filter to a concrete FeatureSource
+	 * @param mode
+	 *            Suchmodus
+	 * @return eine leere {@link Hashtable} falls der Filter {@code null} ist
+	 */
+	protected Hashtable<MapLayer, FeatureCollection> findVisibleFeatures(
+			GeomFilterGenerator filterGenerator, int mode, Envelope env) {
+		Hashtable<MapLayer, FeatureCollection> result = new Hashtable<MapLayer, FeatureCollection>();
+		if (filterGenerator == null)
+			return result;
 
-                // Liefert eine FeatureCollection zurück, in welcher nur
-                // Features enthalten sind, welche bei der aktuellen
-                // Anzeigeskala aufgrund des Styles gerendert werden.
-                if (layer.getTitle().equals(
-                        "vector_afrikan_countries_00040984322")) {
-                    LOGGER.warn("Cancelling here to avoid infinite loop in ShapefileReader.ensureCapacity(ByteBuffer, int, boolean) line: 203.");
-                    LOGGER.warn("Calling isEmpty() or getSize() in GT2.4.5 the ShapefileReader-Class enters infinite loop here for the here for layer vector_afrikan_countries_00040984322. It seems to be specific for this special ShapeFile. Canelling the operation here is a very ugly and very static work-arround. Hopefully this problem vanishes with GT 2.5");
-                    continue;
-                }
+		// Je nach Modus: Alle oder nur das oberste Layer
+		MapContext context = getContext();
+		MapLayer[] layerList = context.getLayers();
+		for (int i = layerList.length - 1; i >= 0; i--) {
+			MapLayer layer = layerList[i];
+			if (!layer.isVisible())
+				continue;
 
-                // @Martin Using size() produces the same problem
-                if (!fc.isEmpty()) {
-                    fc = filterSLDVisibleOnly(fc, layer.getStyle());
+			if (attributeMetaDataMapCache.containsKey(layer.getTitle())) {
+				/* AttributeMetaData is available... */
+				Map<Integer, AttributeMetaData> amdMap = attributeMetaDataMapCache
+						.get(layer.getTitle());
 
-                    if (!fc.isEmpty()) {
-                        result.put(layer, fc);
-                        // Beim Modus "oberstes Layer selektieren" die Schleife
-                        // beenden
-                        if (mode == SELECT_TOP || mode == SELECT_ONE_FROM_TOP)
-                            break;
-                    }
+				if (StyledLayerUtil.getVisibleAttributeMetaData(amdMap, true)
+						.size() == 0) {
+					LOGGER.debug("Ignoring layer " + layer.getTitle()
+							+ " because it has no visible attributes");
+					continue;
+				}
+			}
 
-                }
-            } catch (IOException err) {
-                LOGGER.error("applying the distanceWithin filter", err);
-            }
+			LOGGER.debug("mode = " + mode);
 
-            // for ( FeatureCollection fc1 : result.values() )
-            // LOGGER.debug("A  "+fc1+"    "+fc1.isEmpty());
-        }
-        // for ( FeatureCollection fc1 : result.values() )
-        // LOGGER.debug("B   "+fc1+"    "+fc1.isEmpty());
+			/*
+			 * SK: Change! If AttributeMetadata is provided, we check whether
+			 * any attribute is
+			 */
 
-        return result;
-    }
+			// Bei einem Raster-Layer, das die BB schneidet, abbrechen, wenn nur
+			// im obersten (sichtbaren) Layer gesucht wird.
+			// Ansonsten Raster-Layer einfach uebergehen.
+			if (isGridCoverageLayer(layer)) {
+				if (mode == SELECT_TOP
+						&& gridLayerIntersectsEnvelope(layer, env))
+					break;
+				continue;
+			}
 
-    /**
-     * Ermittelt alle Features, die einen Filter erfuellen. Beim Modus
-     * {@link #SELECT_TOP} wird nur das oberste sichtbare Layer durchsucht. Beim
-     * Modus {@link #SELECT_ALL} werden alle sichtbaren Layer durchsucht.
-     *
-     * 17.4.08, Stefan
-     *
-     * @param filter
-     *            Filter
-     * @param mode
-     *            Suchmodus
-     * @return eine leere {@link Hashtable} falls der Filter {@code null} ist
-     */
-    protected Hashtable<MapLayer, FeatureCollection> findFeatures(
-            GeomFilterGenerator filterGenerator, int mode, Envelope env) {
-        Hashtable<MapLayer, FeatureCollection> result = new Hashtable<MapLayer, FeatureCollection>();
-        if (filterGenerator == null)
-            return result;
+			// Filter an Layer koppeln
+			// WICHTIG: Dies darf erst geschehen, NACHDEM das
+			// Schleifen-Abbruch-Kriterium
+			// fuer die Raster-Layer geprueft wurde!!
+			// Werden folgende Zeilen naemlich auf das FeatureSource des
+			// Raster-Layers angewandt, dann "bricht" der Filter "irgendwie"
+			// zusammen und auch die ZUVOR gefilterten FeatureCollections,
+			// sind ploetzlich EMPTY!!!!!!!!!!!!!!!!!!!!!!!!!!!
+			final FeatureSource featureSource = layer.getFeatureSource();
+			final GeometryFilterImpl distancefilter = filterGenerator
+					.adaptFilter(featureSource);
 
-        // Je nach Modus: Alle oder nur das oberste Layer
-        MapContext context = getContext();
-        MapLayer[] layerList = context.getLayers();
-        for (int i = layerList.length - 1; i >= 0; i--) {
-            MapLayer layer = layerList[i];
-            if (!layer.isVisible())
-                continue;
+			/**
+			 * 8.8.2008: SK Wenn für das Layer auch ein Filter aktiv ist, dann
+			 * soll dieser mit AND an den distanceFilter gebunden werden.
+			 * "Filter filter" ist entweder der distanceFilter oder
+			 * (distanceFilter AND layerFilter)
+			 */
+			Filter filter = distancefilter;
+			if (layer.getQuery() != null) {
+				final Filter layerFilter = layer.getQuery().getFilter();
+				if (layerFilter != null) {
+					filter = distancefilter.and(layerFilter);
+				}
+			}
 
-            // Bei einem Raster-Layer, das die BB schneidet, abbrechen, wenn nur
-            // im
-            // obersten (sichtbaren) Layer gesucht
-            // wird.AbstractGridCoverage2DReader
-            // Ansonsten Raster-Layer einfach uebergehen.
-            if (isGridCoverageLayer(layer)) {
-                if (mode == SELECT_TOP
-                        && gridLayerIntersectsEnvelope(layer, env))
-                    break;
-                continue;
-            }
+			try {
+				// Filter auf Layer des Features anwenden
+				// FeatureCollection fc = layer.getFeatureSource().getFeatures(
+				// FilterUtil.cloneFilter(filter) ); // KLAPPT (NOCH) NICHT
+				// FeatureCollection fc = featureSource.getFeatures(
+				// distancefilter );
+				FeatureCollection fc = featureSource.getFeatures(filter);
 
-            // Filter an Layer koppeln
-            // WICHTIG: Dies darf erst geschehen, NACHDEM das
-            // Schleifen-Abbruch-Kriterium
-            // fuer die Raster-Layer geprueft wurde!!
-            // Werden folgende Zeilen naemlich auf das FeatureSource des
-            // Raster-Layers angewandt, dann "bricht" der Filter "irgendwie"
-            // zusammen und auch die ZUVOR gefilterten FeatureCollections,
-            // sind ploetzlich EMPTY!!!!!!!!!!!!!!!!!!!!!!!!!!!
-            final FeatureSource      featureSource = layer.getFeatureSource();
-            final GeometryFilterImpl filter        = filterGenerator.adaptFilter(featureSource);
+				LOGGER.info("Crazy finsvisible features position reached");
 
-            try {
-                // Filter auf Layer des Features anwenden
-                // FeatureCollection fc = layer.getFeatureSource().getFeatures(
-                // FilterUtil.cloneFilter(filter) ); // KLAPPT (NOCH) NICHT
-                FeatureCollection fc = featureSource.getFeatures(filter);
+				// Liefert eine FeatureCollection zurück, in welcher nur
+				// Features enthalten sind, welche bei der aktuellen
+				// Anzeigeskala aufgrund des Styles gerendert werden.
+				if (layer.getTitle().equals(
+						"vector_afrikan_countries_00040984322")) {
+					LOGGER
+							.warn("Cancelling here to avoid infinite loop in ShapefileReader.ensureCapacity(ByteBuffer, int, boolean) line: 203.");
+					LOGGER
+							.warn("Calling isEmpty() or getSize() in GT2.4.5 the ShapefileReader-Class enters infinite loop here for the here for layer vector_afrikan_countries_00040984322. It seems to be specific for this special ShapeFile. Canelling the operation here is a very ugly and very static work-arround. Hopefully this problem vanishes with GT 2.5");
+					continue;
+				}
 
-                // Liefert eine FeatureCollection zurück, in welcher nur
-                // Features enthalten sind, welche bei der aktuellen
-                // Anzeigeskala aufgrund des Styles gerendert werden.
-                fc = filterSLDVisibleOnly(fc, layer.getStyle());
+				// @Martin Using size() produces the same problem
+				if (!fc.isEmpty()) {
+					fc = filterSLDVisibleOnly(fc, layer.getStyle());
 
-                if (!fc.isEmpty()) {
-                    result.put(layer, fc);
-                    // Beim Modus "oberstes Layer selektieren" die Schleife
-                    // jetzt beenden, da wir sichtbare Features gefunden haben.
-                    if (mode == SELECT_TOP || mode == SELECT_ONE_FROM_TOP)
-                        break;
-                }
-            } catch (Exception err) {
-                LOGGER.error("Looking for features:", err);
-            }
+					if (!fc.isEmpty()) {
+						result.put(layer, fc);
+						// Beim Modus "oberstes Layer selektieren" die Schleife
+						// beenden
+						if (mode == SELECT_TOP || mode == SELECT_ONE_FROM_TOP)
+							break;
+					}
 
-            // for ( FeatureCollection fc1 : result.values() )
-            // LOGGER.debug("A  "+fc1+"    "+fc1.isEmpty());
-        }
-        // for ( FeatureCollection fc1 : result.values() )
-        // LOGGER.debug("B   "+fc1+"    "+fc1.isEmpty());
+				}
+			} catch (IOException err) {
+				LOGGER.error("applying the distanceWithin filter", err);
+			}
 
-        return result;
-    }
+			// for ( FeatureCollection fc1 : result.values() )
+			// LOGGER.debug("A  "+fc1+"    "+fc1.isEmpty());
+		}
+		// for ( FeatureCollection fc1 : result.values() )
+		// LOGGER.debug("B   "+fc1+"    "+fc1.isEmpty());
 
-    /**
-     * SLD Rules können die Paramter MinScaleDenominator und MaxScaleDenominator
-     * enthalten. Dadurch können Elemente für manche Zoom-Stufen deaktiviert
-     * werden.
-     *
-     * @param fc
-     *            Die zu filternde FeatureCollection. Diese wird nicht
-     *            verändert.
-     * @param style
-     *            Der Style, mit dem die Features gerendert werden (z.b.
-     *            layer.getStyle() )
-     *
-     * @return Eine FeatureCollection in welcher nur die Features enthalten
-     *         sind, welche bei aktuellen Scale mit dem übergebenen Style
-     *         gerendert werden.
-     *
-     * @author <a href="mailto:skpublic at wikisquare.de">Stefan Alfons
-     *         Kr&uuml;ger</a>
-     */
-    private MemoryFeatureCollection filterSLDVisibleOnly(
-            final FeatureCollection fc, final Style style) {
+		return result;
+	}
 
-        // Der "scaleDenominator" der aktuellen JMapPane
-        Double scaleDenominator = RendererUtilities
-                .calculateOGCScale(new ReferencedEnvelope(getMapArea(),
-                        getContext().getCoordinateReferenceSystem()),
-                        getSize().width, null);
+	/**
+	 * Ermittelt alle Features, die einen Filter erfuellen. Beim Modus
+	 * {@link #SELECT_TOP} wird nur das oberste sichtbare Layer durchsucht. Beim
+	 * Modus {@link #SELECT_ALL} werden alle sichtbaren Layer durchsucht.
+	 * 
+	 * 17.4.08, Stefan
+	 * 
+	 * @param filter
+	 *            Filter
+	 * @param mode
+	 *            Suchmodus
+	 * @return eine leere {@link Hashtable} falls der Filter {@code null} ist
+	 */
+	protected Hashtable<MapLayer, FeatureCollection> findFeatures(
+			GeomFilterGenerator filterGenerator, int mode, Envelope env) {
+		Hashtable<MapLayer, FeatureCollection> result = new Hashtable<MapLayer, FeatureCollection>();
+		if (filterGenerator == null)
+			return result;
 
-        return StylingUtil.filterSLDVisibleOnly(fc, style, scaleDenominator);
-    }
+		// Je nach Modus: Alle oder nur das oberste Layer
+		MapContext context = getContext();
+		MapLayer[] layerList = context.getLayers();
+		for (int i = layerList.length - 1; i >= 0; i--) {
+			MapLayer layer = layerList[i];
+			if (!layer.isVisible())
+				continue;
 
-    /**
-     * Ermittelt alle Features, die in einem Bereich liegen und erzeugt
-     * entsprechende {@link FeatureSelectedEvent FeatureSelectedEvents}. Beim
-     * Modus {@link #SELECT_TOP} wird nur das oberste sichtbare Layer
-     * durchsucht. Beim Modus {@link #SELECT_ALL} werden alle sichtbaren Layer
-     * durchsucht.
-     *
-     * @param filterGenerator
-     *            adapts a filter to a concrete {@link FeatureSource}
-     * @param mode
-     *            Suchmodus
-     * @param env
-     *            Bereich der durchsucht wird (fuer das Filtern irrelevant; wird
-     *            nur fuer Events benoetigt!)
-     */
-    protected boolean findFeaturesAndFireEvents(GeomFilterGenerator filterGenerator,
-            int mode, Envelope env) {
-        Hashtable<MapLayer, FeatureCollection> result = findVisibleFeatures(
-            filterGenerator, mode, env);
+			// Bei einem Raster-Layer, das die BB schneidet, abbrechen, wenn nur
+			// im
+			// obersten (sichtbaren) Layer gesucht
+			// wird.AbstractGridCoverage2DReader
+			// Ansonsten Raster-Layer einfach uebergehen.
+			if (isGridCoverageLayer(layer)) {
+				if (mode == SELECT_TOP
+						&& gridLayerIntersectsEnvelope(layer, env))
+					break;
+				continue;
+			}
 
-        // Events ausloesen fuer jedes Layer
-        for (final Enumeration<MapLayer> e = result.keys(); e.hasMoreElements();) {
-            final MapLayer layer = e.nextElement();
-            final FeatureCollection fc = result.get(layer);
-            if (fc != null && !fc.isEmpty())
-                fireMapPaneEvent(new FeatureSelectedEvent(this, layer, env, fc));
-        }
-        return !result.isEmpty();
-    }
+			// Filter an Layer koppeln
+			// WICHTIG: Dies darf erst geschehen, NACHDEM das
+			// Schleifen-Abbruch-Kriterium
+			// fuer die Raster-Layer geprueft wurde!!
+			// Werden folgende Zeilen naemlich auf das FeatureSource des
+			// Raster-Layers angewandt, dann "bricht" der Filter "irgendwie"
+			// zusammen und auch die ZUVOR gefilterten FeatureCollections,
+			// sind ploetzlich EMPTY!!!!!!!!!!!!!!!!!!!!!!!!!!!
+			final FeatureSource featureSource = layer.getFeatureSource();
+			final GeometryFilterImpl filter = filterGenerator
+					.adaptFilter(featureSource);
 
-    /**
-     * Ermittelt alle Teil-Raster, die in einem Bereich liegen.
-     * BefindFeaturesAndFireEventsim Modus {@link #SELECT_TOP} wird nur das
-     * oberste sichtbare Layer durchsucht. Beim Modus {@link #SELECT_ALL} werden
-     * alle sichtbaren Layer durchsucht.
-     *
-     * @param env
-     *            Bounding-Box
-     * @param mode
-     *            Suchmodus
-     * @return eine leere {@link Hashtable} falls die Bounding-Box {@code null}
-     *         ist
-     */
-    protected Hashtable<MapLayer, GridCoverage2D> findGridCoverageSubsets(
-            Envelope env, int mode) {
-        Hashtable<MapLayer, GridCoverage2D> result = new Hashtable<MapLayer, GridCoverage2D>();
-        if (env == null)
-            return result;
+			try {
+				// Filter auf Layer des Features anwenden
+				// FeatureCollection fc = layer.getFeatureSource().getFeatures(
+				// FilterUtil.cloneFilter(filter) ); // KLAPPT (NOCH) NICHT
+				FeatureCollection fc = featureSource.getFeatures(filter);
 
-        MapContext context = getContext();
-        // Je nach Modus: Alle oder nur das oberste Layer
-        MapLayer[] layerList = context.getLayers();
-        for (int i = layerList.length - 1; i >= 0; i--) {
-            MapLayer layer = layerList[i];
-            Object layerObj = getLayerSourceObject(layer);
-            if (!layer.isVisible())
-                continue;
+				// Liefert eine FeatureCollection zurück, in welcher nur
+				// Features enthalten sind, welche bei der aktuellen
+				// Anzeigeskala aufgrund des Styles gerendert werden.
+				fc = filterSLDVisibleOnly(fc, layer.getStyle());
 
-            // Bei einem Nicht-Raster-Layer, das die BB schneidet, abbrechen,
-            // wenn nur im obersten (sichtbaren) Layer gesucht wird.
-            // Ansonsten Nicht-Raster-Layer einfach uebergehen.
-            if (!(layerObj instanceof GridCoverage2D)) {
-                if ((mode == SELECT_TOP || mode == SELECT_ONE_FROM_TOP)
-                        && featureLayerIntersectsEnvelope(layer, env))
-                    break;
-                continue;
-            }
+				if (!fc.isEmpty()) {
+					result.put(layer, fc);
+					// Beim Modus "oberstes Layer selektieren" die Schleife
+					// jetzt beenden, da wir sichtbare Features gefunden haben.
+					if (mode == SELECT_TOP || mode == SELECT_ONE_FROM_TOP)
+						break;
+				}
+			} catch (Exception err) {
+				LOGGER.error("Looking for features:", err);
+			}
 
-            GridCoverage2D sourceGrid = (GridCoverage2D) layerObj;
-            com.vividsolutions.jts.geom.Envelope jtsEnv = env;
-            org.geotools.geometry.Envelope2D gtEnv2D = JTS.getEnvelope2D(
-                    jtsEnv, sourceGrid.getCoordinateReferenceSystem());
-            // org.opengis.spatialschema.geometry.Envelope gtGenEnv = new
-            // GeneralEnvelope
-            // ((org.opengis.spatialschema.geometry.Envelope)gtEnv2D); //
-            // gt2-2.3.4
-            org.opengis.geometry.Envelope gtGenEnv = new GeneralEnvelope(
-                    (org.opengis.geometry.Envelope) gtEnv2D); // gt2-2.4.2
+			// for ( FeatureCollection fc1 : result.values() )
+			// LOGGER.debug("A  "+fc1+"    "+fc1.isEmpty());
+		}
+		// for ( FeatureCollection fc1 : result.values() )
+		// LOGGER.debug("B   "+fc1+"    "+fc1.isEmpty());
 
-            // GridCoverage2D subsetGrid =
-            // (GridCoverage2D)Operations.DEFAULT.crop(sourceGrid,gtGenEnv);
-            GridCoverage2D subsetGrid = GridUtil.createGridCoverage(sourceGrid,
-                    gtGenEnv);
-            if (subsetGrid != null)
-                result.put(layer, subsetGrid);
-            // Beim Modus "oberstes Layer selektieren" die Schleife beenden
-            if (mode == SELECT_TOP || mode == SELECT_ONE_FROM_TOP)
-                break;
-        }
-        return result;
-    }
+		return result;
+	}
 
-    /**
-     * Ermittelt alle Teil-Raster, die in einem Bereich liegen und erzeugt
-     * entsprechende {@link GridCoverageSelectedEvent
-     * GridCoverageSelectedEvents}. Beim Modus {@link #SELECT_TOP} wird nur das
-     * oberste sichtbare Layer durchsucht. Beim Modus {@link #SELECT_ALL} werden
-     * alle sichtbaren Layer durchsucht.
-     *
-     * @param env
-     *            Bounding-Box
-     * @param mode
-     *            Suchmodus
-     * @return eine leere {@link Hashtable} falls die Bounding-Box {@code null}
-     *         ist
-     */
-    protected boolean findGridCoverageSubsetsAndFireEvents(final Envelope env,
-            final int mode) {
-        final Hashtable<MapLayer, GridCoverage2D> result = findGridCoverageSubsets(
-                env, mode);
-        // Events ausloesen fuer jedes Layer
-        for (final Enumeration<MapLayer> e = result.keys(); e.hasMoreElements();) {
-            final MapLayer layer = e.nextElement();
-            final GridCoverage2D subset = result.get(layer);
-            if (subset != null)
-                fireMapPaneEvent(new GridCoverageSelectedEvent(this, layer,
-                        env, subset));
-        }
-        return !result.isEmpty();
-    }
+	/**
+	 * SLD Rules können die Paramter MinScaleDenominator und MaxScaleDenominator
+	 * enthalten. Dadurch können Elemente für manche Zoom-Stufen deaktiviert
+	 * werden.
+	 * 
+	 * @param fc
+	 *            Die zu filternde FeatureCollection. Diese wird nicht
+	 *            verändert.
+	 * @param style
+	 *            Der Style, mit dem die Features gerendert werden (z.b.
+	 *            layer.getStyle() )
+	 * 
+	 * @return Eine FeatureCollection in welcher nur die Features enthalten
+	 *         sind, welche bei aktuellen Scale mit dem übergebenen Style
+	 *         gerendert werden.
+	 * 
+	 * @author <a href="mailto:skpublic at wikisquare.de">Stefan Alfons
+	 *         Kr&uuml;ger</a>
+	 */
+	private MemoryFeatureCollection filterSLDVisibleOnly(
+			final FeatureCollection fc, final Style style) {
 
-    /**
-     * Ermittelt alle Raster-Werte, die an einer bestimmten Geo-Position liegen.
-     * Beim Modus {@link #SELECT_TOP} wird nur das oberste sichtbare Layer
-     * durchsucht. Beim Modus {@link #SELECT_ALL} werden alle sichtbaren Layer
-     * durchsucht.
-     * <p>
-     * SK: 28.09.2007 Da ein Rasterlayer auch mehrere Baender haben kann, ist es
-     * sinnvoll, nicht <code>Hashtable MapLayer,Double </code> sondern
-     * <code>Hashtable MapLayer,Double[] </code> zurueckzugeben.
-     *
-     * @param point
-     *            Geo-Referenzgeop
-     * @param mode
-     *            Suchmodus
-     * @return eine leere {@link Hashtable} falls keine Werte ermittelt werden
-     *         konnten
-     *
-     * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a>
-     *         (University of Bonn/Germany)
-     * @author <a href="mailto:skpublic at wikisquare.de">Stefan Alfons
-     *         Kr&uuml;ger</a>
-     */
-    protected Hashtable<MapLayer, double[]> findGridCoverageValues(
-            Point2D point, int mode) {
-        Hashtable<MapLayer, double[]> result = new Hashtable<MapLayer, double[]>();
+		// Der "scaleDenominator" der aktuellen JMapPane
+		Double scaleDenominator = RendererUtilities
+				.calculateOGCScale(new ReferencedEnvelope(getMapArea(),
+						getContext().getCoordinateReferenceSystem()),
+						getSize().width, null);
 
-        if (point == null)
-            return result;
+		return StylingUtil.filterSLDVisibleOnly(fc, style, scaleDenominator);
+	}
 
-        MapContext context = getContext();
-        // Je nach Modus: Alle oder nur das oberste Layer
-        MapLayer[] layerList = context.getLayers();
-        for (int i = layerList.length - 1; i >= 0; i--) {
-            MapLayer layer = layerList[i];
-            if (!layer.isVisible())
-                continue;
-            Object layerObj = getLayerSourceObject(layer);
+	/**
+	 * Ermittelt alle Features, die in einem Bereich liegen und erzeugt
+	 * entsprechende {@link FeatureSelectedEvent FeatureSelectedEvents}. Beim
+	 * Modus {@link #SELECT_TOP} wird nur das oberste sichtbare Layer
+	 * durchsucht. Beim Modus {@link #SELECT_ALL} werden alle sichtbaren Layer
+	 * durchsucht.
+	 * 
+	 * @param filterGenerator
+	 *            adapts a filter to a concrete {@link FeatureSource}
+	 * @param mode
+	 *            Suchmodus
+	 * @param env
+	 *            Bereich der durchsucht wird (fuer das Filtern irrelevant; wird
+	 *            nur fuer Events benoetigt!)
+	 */
+	protected boolean findFeaturesAndFireEvents(
+			GeomFilterGenerator filterGenerator, int mode, Envelope env) {
+		Hashtable<MapLayer, FeatureCollection> result = findVisibleFeatures(
+				filterGenerator, mode, env);
 
-            // LOGGER.info("layerObj = "+layerObj.getClass().getSimpleName());
+		// Events ausloesen fuer jedes Layer
+		for (final Enumeration<MapLayer> e = result.keys(); e.hasMoreElements();) {
+			final MapLayer layer = e.nextElement();
+			final FeatureCollection fc = result.get(layer);
+			if (fc != null && !fc.isEmpty())
+				fireMapPaneEvent(new FeatureSelectedEvent(this, layer, env, fc));
+		}
+		return !result.isEmpty();
+	}
 
-            // SK 29.9.2007 Vorher:
-            // // Bei einem Nicht-Raster-Layer, das den Punkt beinhaltet,
-            // abbrechen, wenn nur im
-            // // obersten (sichtbaren) Layer gesucht wird.
-            // // Ansonsten Nicht-Raster-Layer einfach uebergehen.
-            // if ( !(layerObj instanceof GridCoverage2D) ) {
-            // if ( mode == SELECT_TOP &&
-            // featureLayerIntersectsEnvelope(layer,new
-            // Envelope(point.getX(),point.getX(),point.getY(),point.getY())) )
-            // break;
-            // continue;
-            // }
+	/**
+	 * Ermittelt alle Teil-Raster, die in einem Bereich liegen.
+	 * BefindFeaturesAndFireEventsim Modus {@link #SELECT_TOP} wird nur das
+	 * oberste sichtbare Layer durchsucht. Beim Modus {@link #SELECT_ALL} werden
+	 * alle sichtbaren Layer durchsucht.
+	 * 
+	 * @param env
+	 *            Bounding-Box
+	 * @param mode
+	 *            Suchmodus
+	 * @return eine leere {@link Hashtable} falls die Bounding-Box {@code null}
+	 *         ist
+	 */
+	protected Hashtable<MapLayer, GridCoverage2D> findGridCoverageSubsets(
+			Envelope env, int mode) {
+		Hashtable<MapLayer, GridCoverage2D> result = new Hashtable<MapLayer, GridCoverage2D>();
+		if (env == null)
+			return result;
 
-            // Bei einem Nicht-Raster-Layer, das den Punkt beinhaltet,
-            // abbrechen, wenn nur im
-            // obersten (sichtbaren) Layer gesucht wird.
-            // Ansonsten Nicht-Raster-Layer einfach uebergehen.
-            // SK 29.9.07: Ein AbstractGridCoverage2DReader ist auch ein Raster
-            if (!(layerObj instanceof GridCoverage2D || layerObj instanceof AbstractGridCoverage2DReader)) {
-                final Envelope pointAsEnvelope = new Envelope(point.getX(),
-                        point.getX(), point.getY(), point.getY());
-                if (mode == SELECT_TOP
-                        && featureLayerIntersectsEnvelope(layer,
-                                pointAsEnvelope)) {
-                }
-                continue;
-            }
+		MapContext context = getContext();
+		// Je nach Modus: Alle oder nur das oberste Layer
+		MapLayer[] layerList = context.getLayers();
+		for (int i = layerList.length - 1; i >= 0; i--) {
+			MapLayer layer = layerList[i];
+			Object layerObj = getLayerSourceObject(layer);
+			if (!layer.isVisible())
+				continue;
 
-            GridCoverage2D sourceGrid;
+			// Bei einem Nicht-Raster-Layer, das die BB schneidet, abbrechen,
+			// wenn nur im obersten (sichtbaren) Layer gesucht wird.
+			// Ansonsten Nicht-Raster-Layer einfach uebergehen.
+			if (!(layerObj instanceof GridCoverage2D)) {
+				if ((mode == SELECT_TOP || mode == SELECT_ONE_FROM_TOP)
+						&& featureLayerIntersectsEnvelope(layer, env))
+					break;
+				continue;
+			}
 
-            if (layerObj instanceof AbstractGridCoverage2DReader) {
-                // LOGGER.info("layerObj instanceof AbstractGridCoverage2DReader"
-                // );
-                AbstractGridCoverage2DReader reader = (AbstractGridCoverage2DReader) layerObj;
-                Parameter readGG = new Parameter(
-                        AbstractGridFormat.READ_GRIDGEOMETRY2D);
+			GridCoverage2D sourceGrid = (GridCoverage2D) layerObj;
+			com.vividsolutions.jts.geom.Envelope jtsEnv = env;
+			org.geotools.geometry.Envelope2D gtEnv2D = JTS.getEnvelope2D(
+					jtsEnv, sourceGrid.getCoordinateReferenceSystem());
+			// org.opengis.spatialschema.geometry.Envelope gtGenEnv = new
+			// GeneralEnvelope
+			// ((org.opengis.spatialschema.geometry.Envelope)gtEnv2D); //
+			// gt2-2.3.4
+			org.opengis.geometry.Envelope gtGenEnv = new GeneralEnvelope(
+					(org.opengis.geometry.Envelope) gtEnv2D); // gt2-2.4.2
 
-                ReferencedEnvelope mapExtend = new org.geotools.geometry.jts.ReferencedEnvelope(
-                        mapArea, context.getCoordinateReferenceSystem());
+			// GridCoverage2D subsetGrid =
+			// (GridCoverage2D)Operations.DEFAULT.crop(sourceGrid,gtGenEnv);
+			GridCoverage2D subsetGrid = GridUtil.createGridCoverage(sourceGrid,
+					gtGenEnv);
+			if (subsetGrid != null)
+				result.put(layer, subsetGrid);
+			// Beim Modus "oberstes Layer selektieren" die Schleife beenden
+			if (mode == SELECT_TOP || mode == SELECT_ONE_FROM_TOP)
+				break;
+		}
+		return result;
+	}
 
-                readGG.setValue(new GridGeometry2D(new GeneralGridRange(
-                        getBounds()), mapExtend));
+	/**
+	 * Ermittelt alle Teil-Raster, die in einem Bereich liegen und erzeugt
+	 * entsprechende {@link GridCoverageSelectedEvent
+	 * GridCoverageSelectedEvents}. Beim Modus {@link #SELECT_TOP} wird nur das
+	 * oberste sichtbare Layer durchsucht. Beim Modus {@link #SELECT_ALL} werden
+	 * alle sichtbaren Layer durchsucht.
+	 * 
+	 * @param env
+	 *            Bounding-Box
+	 * @param mode
+	 *            Suchmodus
+	 * @return eine leere {@link Hashtable} falls die Bounding-Box {@code null}
+	 *         ist
+	 */
+	protected boolean findGridCoverageSubsetsAndFireEvents(final Envelope env,
+			final int mode) {
+		final Hashtable<MapLayer, GridCoverage2D> result = findGridCoverageSubsets(
+				env, mode);
+		// Events ausloesen fuer jedes Layer
+		for (final Enumeration<MapLayer> e = result.keys(); e.hasMoreElements();) {
+			final MapLayer layer = e.nextElement();
+			final GridCoverage2D subset = result.get(layer);
+			if (subset != null)
+				fireMapPaneEvent(new GridCoverageSelectedEvent(this, layer,
+						env, subset));
+		}
+		return !result.isEmpty();
+	}
 
-                try {
-                    sourceGrid = (GridCoverage2D) reader
-                            .read(new GeneralParameterValue[] { readGG });
-                } catch (Exception e) {
-                    LOGGER.error("read(new GeneralParameterValue[] { readGG })", e);
-                    continue;
-                }
-            } else {
-                // Ein instanceof ist nicht noetig, da sonst schon break oder
-                // continue aufgerufen worden waere
-                sourceGrid = (GridCoverage2D) layerObj;
-            }
+	/**
+	 * Ermittelt alle Raster-Werte, die an einer bestimmten Geo-Position liegen.
+	 * Beim Modus {@link #SELECT_TOP} wird nur das oberste sichtbare Layer
+	 * durchsucht. Beim Modus {@link #SELECT_ALL} werden alle sichtbaren Layer
+	 * durchsucht.
+	 * <p>
+	 * SK: 28.09.2007 Da ein Rasterlayer auch mehrere Baender haben kann, ist es
+	 * sinnvoll, nicht <code>Hashtable MapLayer,Double </code> sondern
+	 * <code>Hashtable MapLayer,Double[] </code> zurueckzugeben.
+	 * 
+	 * @param point
+	 *            Geo-Referenzgeop
+	 * @param mode
+	 *            Suchmodus
+	 * @return eine leere {@link Hashtable} falls keine Werte ermittelt werden
+	 *         konnten
+	 * 
+	 * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a>
+	 *         (University of Bonn/Germany)
+	 * @author <a href="mailto:skpublic at wikisquare.de">Stefan Alfons
+	 *         Kr&uuml;ger</a>
+	 */
+	protected Hashtable<MapLayer, double[]> findGridCoverageValues(
+			Point2D point, int mode) {
+		Hashtable<MapLayer, double[]> result = new Hashtable<MapLayer, double[]>();
 
-            // vorher: double[] value = new double[2];
+		if (point == null)
+			return result;
 
-            // getNumSampleDimensions gibt die Anzahl der Baender des Rasters
-            // zurueck.
-            double[] values = new double[sourceGrid.getNumSampleDimensions()];
+		MapContext context = getContext();
+		// Je nach Modus: Alle oder nur das oberste Layer
+		MapLayer[] layerList = context.getLayers();
+		for (int i = layerList.length - 1; i >= 0; i--) {
+			MapLayer layer = layerList[i];
+			if (!layer.isVisible())
+				continue;
+			Object layerObj = getLayerSourceObject(layer);
 
-            try {
-                // Grid an Geo-Position auswerten
-                sourceGrid.evaluate(point, values);
-            } catch (CannotEvaluateException err) {
-                // z.B. Punkt ausserhalb des Rasters --> Layer uebergehen
-                continue;
-            } catch (Exception e) {
-                LOGGER.error("sourceGrid.evaluate(point, values);", e);
-                continue;
-            }
+			// LOGGER.info("layerObj = "+layerObj.getClass().getSimpleName());
 
-            // SK: voher wurde nur der erste Wert zurueckgegeben
-            // result.put(layer,value[0]);
-            // jetzt werden alle werte zueuckgegeben
+			// SK 29.9.2007 Vorher:
+			// // Bei einem Nicht-Raster-Layer, das den Punkt beinhaltet,
+			// abbrechen, wenn nur im
+			// // obersten (sichtbaren) Layer gesucht wird.
+			// // Ansonsten Nicht-Raster-Layer einfach uebergehen.
+			// if ( !(layerObj instanceof GridCoverage2D) ) {
+			// if ( mode == SELECT_TOP &&
+			// featureLayerIntersectsEnvelope(layer,new
+			// Envelope(point.getX(),point.getX(),point.getY(),point.getY())) )
+			// break;
+			// continue;
+			// }
 
-            result.put(layer, values);
-            // Beim Modus "oberstes Layer selektieren" die Schleife beenden
-            if (mode == SELECT_TOP)
-                break;
-        }
-        return result;
-    }
+			// Bei einem Nicht-Raster-Layer, das den Punkt beinhaltet,
+			// abbrechen, wenn nur im
+			// obersten (sichtbaren) Layer gesucht wird.
+			// Ansonsten Nicht-Raster-Layer einfach uebergehen.
+			// SK 29.9.07: Ein AbstractGridCoverage2DReader ist auch ein Raster
+			if (!(layerObj instanceof GridCoverage2D || layerObj instanceof AbstractGridCoverage2DReader)) {
+				final Envelope pointAsEnvelope = new Envelope(point.getX(),
+						point.getX(), point.getY(), point.getY());
+				if (mode == SELECT_TOP
+						&& featureLayerIntersectsEnvelope(layer,
+								pointAsEnvelope)) {
+				}
+				continue;
+			}
 
-    /**
-     * Ermittelt die Raster-Werte, die an einem Punkt liegen und erzeugt
-     * entsprechende {@link GridCoverageValueSelectedEvent
-     * GridCoverageValueSelectedEvents}. Beim Modus {@link #SELECT_TOP} wird nur
-     * das oberste sichtbare Layer durchsucht. Beim Modus {@link #SELECT_ALL}
-     * werden alle sichtbaren Layer durchsucht.
-     * <p>
-     * SK: 28.09.2007 Da ein Rasterlayer auch mehrere Baender haben kann, ist es
-     * sinnvoll, nicht <code>Hashtable MapLayer,Double </code> sondern
-     * <code>Hashtable MapLayer,Double[] </code> zurueckzugeben.
-     *
-     * @param point
-     *            Geo-Referenz
-     * @param mode
-     *            Suchmodus
-     * @return eine leere {@link Hashtable} falls der Punkt {@code null} ist
-     *
-     * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a>
-     *         (University of Bonn/Germany)
-     * @author <a href="mailto:skpublic at wikisquare.de">Stefan Alfons
-     *         Kr&uuml;ger</a>
-     */
-    protected boolean findGridCoverageValuesAndFireEvents(Point2D point,
-            int mode) {
-        Hashtable<MapLayer, double[]> result = findGridCoverageValues(point,
-                mode);
+			GridCoverage2D sourceGrid;
 
-        // Events ausloesen fuer jedes Layer
-        for (Enumeration<MapLayer> e = result.keys(); e.hasMoreElements();) {
-            MapLayer layer = e.nextElement();
-            double[] values = result.get(layer);
-            fireMapPaneEvent(new GridCoverageValueSelectedEvent(this, layer,
-                    point, values));
-        }
-        return !result.isEmpty();
-    }
+			if (layerObj instanceof AbstractGridCoverage2DReader) {
+				// LOGGER.info("layerObj instanceof AbstractGridCoverage2DReader"
+				// );
+				AbstractGridCoverage2DReader reader = (AbstractGridCoverage2DReader) layerObj;
+				Parameter readGG = new Parameter(
+						AbstractGridFormat.READ_GRIDGEOMETRY2D);
 
-//  /**
-//   * Bereitet einen BoundingBox-Filter vor. Das "linke" Attribut der
-//   * Expression (das Feature-Attribut, auf das der Filter angewendet wird),
-//   * wird dabei noch nicht belegt. Dies geschieht erst bei der Auswertung
-//   * entsprechend des jeweiligen Layers
-//   *
-//   * @param env
-//   *            Bounding-Box
-//   */
-//  private static GeometryFilterImpl createBoundingBoxFilter(Envelope env) {
-//      // Filter fuer Envelope zusammenstellen
-//      Expression bbox = ff.createBBoxExpression(env);
-//      GeometryFilterImpl bboxFilter = (GeometryFilterImpl) ff
-//              .createGeometryFilter(AbstractFilter.GEOMETRY_BBOX);
-//      // GeometryFilterImpl bboxFilter =
-//      // (GeometryFilterImpl)ff.createGeometryFilter
-//      // (AbstractFilter.GEOMETRY_WITHIN);
-//      bboxFilter.setExpression2(bbox);
-//      return bboxFilter;
-//  }
-//
-//  /**
-//   * Bereitet einen Punkt-Filter vor. Das "linke" Attribut der Expression (das
-//   * Feature-Attribut, auf das der Filter angewendet wird), wird dabei noch
-//   * nicht belegt. Dies geschieht erst bei der Auswertung entsprechend des
-//   * jeweiligen Layers
-//   *
-//   * @param point
-//   *            Geo-Koordinate
-//   */
-//  private static GeometryFilterImpl createPointFilter(Point2D point) {
-//      // Filter fuer Envelope zusammenstellen
-//      Geometry geometry = gf.createPoint(new Coordinate(point.getX(), point
-//              .getY()));
-//      GeometryFilterImpl pointFilter = (GeometryFilterImpl) ff
-//              .createGeometryFilter(GeometryFilterImpl.GEOMETRY_CONTAINS);
-//      pointFilter.setExpression2(ff.createLiteralExpression(geometry));
-//      return pointFilter;
-//  }
-//
-//  /**
-//   * Bereitet einen "InDerNaehe von" Distance-Filter vor. Das "linke" Attribut
-//   * der Expression (das Feature-Attribut, auf das der Filter angewendet
-//   * wird), wird dabei noch nicht belegt. Dies geschieht erst bei der
-//   * Auswertung entsprechend des jeweiligen Layers
-//   *
-//   * Wird benoetigt, um mit der Maus einen Punkt zu treffen.
-//   *
-//   * @param point
-//   *            Geo-Koordinate
-//   * @param dist
-//   *            Distanz zum Punkt in Einheiten des Layers
-//   *
-//   *            TODO SK Auf FilterFactory2 ändern... Beispiel von
-//   *            http://docs.codehaus.org/display/GEOTDOC/Filter+Examples
-//   *            funktioniert erst ab 2.5 ?? Vor dem Distcheck einen BBOX check
-//   *            sollte die geschwindigkeit erhöhen.
-//   *
-//   * @author <a href="mailto:skpublic at wikisquare.de">Stefan Alfons
-//   *         Kr&uuml;ger</a>
-//   */
-//  private static GeometryFilterImpl createNearPointFilter(
-//          final Point2D point, final Double dist) {
-//      // Filter fuer Envelope zusammenstellen
-//      final Geometry geometry = gf.createPoint(new Coordinate(point.getX(),
-//              point.getY()));
-//
-//      final DWithinImpl dwithinFilter = (DWithinImpl) ff
-//              .createGeometryDistanceFilter(DWithinImpl.GEOMETRY_DWITHIN);
-//
-//      dwithinFilter.setDistance(dist);
-//
-//      dwithinFilter.setExpression2(ff.createLiteralExpression(geometry));
-//
-//      return dwithinFilter;
-//  }
+				ReferencedEnvelope mapExtend = new org.geotools.geometry.jts.ReferencedEnvelope(
+						mapArea, context.getCoordinateReferenceSystem());
 
-    /**
-     * Prueft, ob es sich bei einem Layer um ein Raster-Layer handelt.
-     * Raster-Layer zeichnen sich dadurch aus, dass die zugrunde liegende
-     * {@link FeatureCollection} nur ein Feature enthaelt, das genau ein
-     * Attribut mit dem Namen "GridCoverage" hat.
-     *
-     * SK: Pyramidenlayer aka AbstractGridCoverage2DReader geben auch true
-     * zurück.
-     *
-     * @param layer
-     *            zu ueberpruefendes Layer
-     */
-    public static boolean isGridCoverageLayer(MapLayer layer) {
-        final Object layerSourceObject = getLayerSourceObject(layer);
-        boolean b = (layerSourceObject instanceof GridCoverage2D)
-                || (layerSourceObject instanceof AbstractGridCoverage2DReader);
-        // if (!b && layerSourceObject instanceof DefaultFeatureResults){
-        // DefaultFeatureResults dfr = (DefaultFeatureResults)
-        // layerSourceObject;
-        // }
-        // LOGGER.debug(b+"= "+layerSourceObject.getClass().getSimpleName()+" "+
-        // layer.getTitle());
-        return b;
-        // try {
-        // FeatureCollection fc = layer.getFeatureSource().getFeatures();
-        // // Layer muss genau ein Feature beinhalten
-        // if ( fc == null || fc.size() != 1 )
-        // return false;
-        // // Feature muss genau 1 Attribut mit dem Namen "GridCoverage" haben
-        // FeatureType ftype = fc.getFeatureType();
-        // if ( ftype == null || ftype.getAttributeCount() != 1 ||
-        // !"GridCoverage".equalsIgnoreCase(ftype.getAttributeType(0).getName())
-        // )
-        // return false;
-        // } catch (Exception err) {
-        // }
-        // return true;
-    }
+				readGG.setValue(new GridGeometry2D(new GeneralGridRange(
+						getBounds()), mapExtend));
 
-    /**
-     * Liefert das Objekt ({@link GridCoverage2D} oder {@link FeatureCollection}
-     * oder {@link AbstractGridCoverageReader} auf dem ein Layer basiert. Ein
-     * Raster-Layer zeichnen sich dadurch aus, dass die zugrunde liegende
-     * {@link FeatureCollection} nur ein Feature enthaelt, das genau ein
-     * Attribut mit Namen "GridCoverage" und Typ {@code GridCoverage2D} oder
-     * {@link AbstractGridCoverageReader} hat. Sind diese Bedingungen erfuellt,
-     * wird das 2. Attribut zurueckgegeben, ansonsten die
-     * {@link FeatureCollection}.
-     *
-     * @param layer
-     *            ein Layer
-     * @return {@code null}, falls das Objekt nicht ermittelt werden kann (da
-     *         ein Fehler aufgetreten ist).
-     */
-    public static Object getLayerSourceObject(MapLayer layer) {
-        try {
-            final FeatureSource featureSource = layer.getFeatureSource();
-            FeatureCollection fc = featureSource.getFeatures();
-            // RasterLayer muss genau ein Feature beinhalten
-            // Ist dies nicht der Fall wird die FeatureCollection zurueckgegeben
-            if (fc == null || fc.size() != 1) {
+				try {
+					sourceGrid = (GridCoverage2D) reader
+							.read(new GeneralParameterValue[] { readGG });
+				} catch (Exception e) {
+					LOGGER.error(
+							"read(new GeneralParameterValue[] { readGG })", e);
+					continue;
+				}
+			} else {
+				// Ein instanceof ist nicht noetig, da sonst schon break oder
+				// continue aufgerufen worden waere
+				sourceGrid = (GridCoverage2D) layerObj;
+			}
 
-                return fc;
-            }
-            // FeatureType des RasterLayer muss genau 1 Attribut mit Namen
-            // "GridCoverage"
-            // Ist dies nicht der Fall wird die FeatureCollection zurueckgegeben
-            FeatureType ftype = fc.getFeatureType();
-            if (ftype == null
-                    || ftype.getAttributeCount() != 1
-                    || !"GridCoverage".equalsIgnoreCase(ftype.getAttributeType(
-                            0).getLocalName()))
-                return fc;
-            // (Einziges) Feature muss genau 2 Attribute besitzen, wobei das
-            // erste vom
-            // Typ Geometry ist und das zweite vom Typ GridCoverage2D
-            // sonst: FeatureCollextion zurueckgeben
+			// vorher: double[] value = new double[2];
 
-            /** CHANGE SK 9.8.08 BEGIN */
-            Feature f = fc.features().next();
-            if ((f.getFeatureType().getTypeName().equals("GridCoverage") && f
-                    .getNumberOfAttributes() >= 2)) {
-                // I am sure, that it is a raster some. We do not have to cast
-                // it to either cridcoverage or abstractReader, as the results
-                // are tested anyway...
-                return f.getAttribute(1);
-            }
-            /** CHANGE SK 9.8.08 END */
+			// getNumSampleDimensions gibt die Anzahl der Baender des Rasters
+			// zurueck.
+			double[] values = new double[sourceGrid.getNumSampleDimensions()];
 
-            if (f.getNumberOfAttributes() != 2
-                    || // Geaendert, da es bei AbstractGridCoverageReader 3 sind
-                    // (SK, 19.08.07)
-                    !(f.getAttribute(0) instanceof com.vividsolutions.jts.geom.Geometry)
-                    || !(f.getAttribute(1) instanceof GridCoverage2D))
-                return fc;
+			try {
+				// Grid an Geo-Position auswerten
+				sourceGrid.evaluate(point, values);
+			} catch (CannotEvaluateException err) {
+				// z.B. Punkt ausserhalb des Rasters --> Layer uebergehen
+				continue;
+			} catch (Exception e) {
+				LOGGER.error("sourceGrid.evaluate(point, values);", e);
+				continue;
+			}
 
-            // Objekt ist ein Raster!
-            return (GridCoverage2D) f.getAttribute(1);
-        } catch (Exception err) {
-            LOGGER.warn(err.getMessage(), err);
-            return null;
-        }
-    }
+			// SK: voher wurde nur der erste Wert zurueckgegeben
+			// result.put(layer,value[0]);
+			// jetzt werden alle werte zueuckgegeben
 
-    /**
-     * 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>
-     */
+			result.put(layer, values);
+			// Beim Modus "oberstes Layer selektieren" die Schleife beenden
+			if (mode == SELECT_TOP)
+				break;
+		}
+		return result;
+	}
 
-    public void dispose() {
-        if (isDisposed())
-            return;
+	/**
+	 * Ermittelt die Raster-Werte, die an einem Punkt liegen und erzeugt
+	 * entsprechende {@link GridCoverageValueSelectedEvent
+	 * GridCoverageValueSelectedEvents}. Beim Modus {@link #SELECT_TOP} wird nur
+	 * das oberste sichtbare Layer durchsucht. Beim Modus {@link #SELECT_ALL}
+	 * werden alle sichtbaren Layer durchsucht.
+	 * <p>
+	 * SK: 28.09.2007 Da ein Rasterlayer auch mehrere Baender haben kann, ist es
+	 * sinnvoll, nicht <code>Hashtable MapLayer,Double </code> sondern
+	 * <code>Hashtable MapLayer,Double[] </code> zurueckzugeben.
+	 * 
+	 * @param point
+	 *            Geo-Referenz
+	 * @param mode
+	 *            Suchmodus
+	 * @return eine leere {@link Hashtable} falls der Punkt {@code null} ist
+	 * 
+	 * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a>
+	 *         (University of Bonn/Germany)
+	 * @author <a href="mailto:skpublic at wikisquare.de">Stefan Alfons
+	 *         Kr&uuml;ger</a>
+	 */
+	protected boolean findGridCoverageValuesAndFireEvents(Point2D point,
+			int mode) {
+		Hashtable<MapLayer, double[]> result = findGridCoverageValues(point,
+				mode);
 
-        if (dragWaitCursorListener != null)
-            this.removeMouseListener(dragWaitCursorListener);
-        if (mouseWheelZoomListener != null)
-            this.removeMouseWheelListener(mouseWheelZoomListener);
+		// Events ausloesen fuer jedes Layer
+		for (Enumeration<MapLayer> e = result.keys(); e.hasMoreElements();) {
+			MapLayer layer = e.nextElement();
+			double[] values = result.get(layer);
+			fireMapPaneEvent(new GridCoverageValueSelectedEvent(this, layer,
+					point, values));
+		}
+		return !result.isEmpty();
+	}
 
-        // Alle mapPaneListener entfernen
-        mapPaneListeners.clear();
+	// /**
+	// * Bereitet einen BoundingBox-Filter vor. Das "linke" Attribut der
+	// * Expression (das Feature-Attribut, auf das der Filter angewendet wird),
+	// * wird dabei noch nicht belegt. Dies geschieht erst bei der Auswertung
+	// * entsprechend des jeweiligen Layers
+	// *
+	// * @param env
+	// * Bounding-Box
+	// */
+	// private static GeometryFilterImpl createBoundingBoxFilter(Envelope env) {
+	// // Filter fuer Envelope zusammenstellen
+	// Expression bbox = ff.createBBoxExpression(env);
+	// GeometryFilterImpl bboxFilter = (GeometryFilterImpl) ff
+	// .createGeometryFilter(AbstractFilter.GEOMETRY_BBOX);
+	// // GeometryFilterImpl bboxFilter =
+	// // (GeometryFilterImpl)ff.createGeometryFilter
+	// // (AbstractFilter.GEOMETRY_WITHIN);
+	// bboxFilter.setExpression2(bbox);
+	// return bboxFilter;
+	// }
+	//
+	// /**
+	// * Bereitet einen Punkt-Filter vor. Das "linke" Attribut der Expression
+	// (das
+	// * Feature-Attribut, auf das der Filter angewendet wird), wird dabei noch
+	// * nicht belegt. Dies geschieht erst bei der Auswertung entsprechend des
+	// * jeweiligen Layers
+	// *
+	// * @param point
+	// * Geo-Koordinate
+	// */
+	// private static GeometryFilterImpl createPointFilter(Point2D point) {
+	// // Filter fuer Envelope zusammenstellen
+	// Geometry geometry = gf.createPoint(new Coordinate(point.getX(), point
+	// .getY()));
+	// GeometryFilterImpl pointFilter = (GeometryFilterImpl) ff
+	// .createGeometryFilter(GeometryFilterImpl.GEOMETRY_CONTAINS);
+	// pointFilter.setExpression2(ff.createLiteralExpression(geometry));
+	// return pointFilter;
+	// }
+	//
+	// /**
+	// * Bereitet einen "InDerNaehe von" Distance-Filter vor. Das "linke"
+	// Attribut
+	// * der Expression (das Feature-Attribut, auf das der Filter angewendet
+	// * wird), wird dabei noch nicht belegt. Dies geschieht erst bei der
+	// * Auswertung entsprechend des jeweiligen Layers
+	// *
+	// * Wird benoetigt, um mit der Maus einen Punkt zu treffen.
+	// *
+	// * @param point
+	// * Geo-Koordinate
+	// * @param dist
+	// * Distanz zum Punkt in Einheiten des Layers
+	// *
+	// * TODO SK Auf FilterFactory2 ändern... Beispiel von
+	// * http://docs.codehaus.org/display/GEOTDOC/Filter+Examples
+	// * funktioniert erst ab 2.5 ?? Vor dem Distcheck einen BBOX check
+	// * sollte die geschwindigkeit erhöhen.
+	// *
+	// * @author <a href="mailto:skpublic at wikisquare.de">Stefan Alfons
+	// * Kr&uuml;ger</a>
+	// */
+	// private static GeometryFilterImpl createNearPointFilter(
+	// final Point2D point, final Double dist) {
+	// // Filter fuer Envelope zusammenstellen
+	// final Geometry geometry = gf.createPoint(new Coordinate(point.getX(),
+	// point.getY()));
+	//
+	// final DWithinImpl dwithinFilter = (DWithinImpl) ff
+	// .createGeometryDistanceFilter(DWithinImpl.GEOMETRY_DWITHIN);
+	//
+	// dwithinFilter.setDistance(dist);
+	//
+	// dwithinFilter.setExpression2(ff.createLiteralExpression(geometry));
+	//
+	// return dwithinFilter;
+	// }
 
-        getContext().clearLayerList();
+	/**
+	 * Prueft, ob es sich bei einem Layer um ein Raster-Layer handelt.
+	 * Raster-Layer zeichnen sich dadurch aus, dass die zugrunde liegende
+	 * {@link FeatureCollection} nur ein Feature enthaelt, das genau ein
+	 * Attribut mit dem Namen "GridCoverage" hat.
+	 * 
+	 * SK: Pyramidenlayer aka AbstractGridCoverage2DReader geben auch true
+	 * zurück.
+	 * 
+	 * @param layer
+	 *            zu ueberpruefendes Layer
+	 */
+	public static boolean isGridCoverageLayer(MapLayer layer) {
+		final Object layerSourceObject = getLayerSourceObject(layer);
+		boolean b = (layerSourceObject instanceof GridCoverage2D)
+				|| (layerSourceObject instanceof AbstractGridCoverage2DReader);
+		// if (!b && layerSourceObject instanceof DefaultFeatureResults){
+		// DefaultFeatureResults dfr = (DefaultFeatureResults)
+		// layerSourceObject;
+		// }
+		// LOGGER.debug(b+"= "+layerSourceObject.getClass().getSimpleName()+" "+
+		// layer.getTitle());
+		return b;
+		// try {
+		// FeatureCollection fc = layer.getFeatureSource().getFeatures();
+		// // Layer muss genau ein Feature beinhalten
+		// if ( fc == null || fc.size() != 1 )
+		// return false;
+		// // Feature muss genau 1 Attribut mit dem Namen "GridCoverage" haben
+		// FeatureType ftype = fc.getFeatureType();
+		// if ( ftype == null || ftype.getAttributeCount() != 1 ||
+		// !"GridCoverage".equalsIgnoreCase(ftype.getAttributeType(0).getName())
+		// )
+		// return false;
+		// } catch (Exception err) {
+		// }
+		// return true;
+	}
 
-        removeAll();
-        disposed = true;
-    }
+	/**
+	 * Liefert das Objekt ({@link GridCoverage2D} oder {@link FeatureCollection}
+	 * oder {@link AbstractGridCoverageReader} auf dem ein Layer basiert. Ein
+	 * Raster-Layer zeichnen sich dadurch aus, dass die zugrunde liegende
+	 * {@link FeatureCollection} nur ein Feature enthaelt, das genau ein
+	 * Attribut mit Namen "GridCoverage" und Typ {@code GridCoverage2D} oder
+	 * {@link AbstractGridCoverageReader} hat. Sind diese Bedingungen erfuellt,
+	 * wird das 2. Attribut zurueckgegeben, ansonsten die
+	 * {@link FeatureCollection}.
+	 * 
+	 * @param layer
+	 *            ein Layer
+	 * @return {@code null}, falls das Objekt nicht ermittelt werden kann (da
+	 *         ein Fehler aufgetreten ist).
+	 */
+	public static Object getLayerSourceObject(MapLayer layer) {
+		try {
+			final FeatureSource featureSource = layer.getFeatureSource();
+			FeatureCollection fc = featureSource.getFeatures();
+			// RasterLayer muss genau ein Feature beinhalten
+			// Ist dies nicht der Fall wird die FeatureCollection zurueckgegeben
+			if (fc == null || fc.size() != 1) {
 
-    /**
-     * A flag indicating if dispose() has already been called. If true, then
-     * further use of this {@link JMapPane} is undefined.
-     */
-    private boolean isDisposed() {
-        return disposed;
-    }
+				return fc;
+			}
+			// FeatureType des RasterLayer muss genau 1 Attribut mit Namen
+			// "GridCoverage"
+			// Ist dies nicht der Fall wird die FeatureCollection zurueckgegeben
+			FeatureType ftype = fc.getFeatureType();
+			if (ftype == null
+					|| ftype.getAttributeCount() != 1
+					|| !"GridCoverage".equalsIgnoreCase(ftype.getAttributeType(
+							0).getLocalName()))
+				return fc;
+			// (Einziges) Feature muss genau 2 Attribute besitzen, wobei das
+			// erste vom
+			// Typ Geometry ist und das zweite vom Typ GridCoverage2D
+			// sonst: FeatureCollextion zurueckgeben
 
-    //
-    // /**
-    // * Werden Rasterlayer waehrend einer PAN Aktion versteckt?
-    // * @author <a href="mailto:skpublic at wikisquare.de">Stefan Alfons
-    // Kr&uuml;ger</a>
-    // */
-    // public boolean isHideRasterLayersDuringPan() {
-    // return hideRasterLayersDuringPan;
-    // }
-    //
-    // /**
-    // * Bestimmt, ob Rasterlayer waehrend einer PAN Aktion versteckt werden
-    // soll. Default ist false.
-    // * @param hideRasterLayersDuringPan
-    // * @author <a href="mailto:skpublic at wikisquare.de">Stefan Alfons
-    // Kr&uuml;ger</a>
-    // */
-    // public void setHideRasterLayersDuringPan(boolean
-    // hideRasterLayersDuringPan) {
-    // this.hideRasterLayersDuringPan = hideRasterLayersDuringPan;
-    // }
+			/** CHANGE SK 9.8.08 BEGIN */
+			Feature f = fc.features().next();
+			if ((f.getFeatureType().getTypeName().equals("GridCoverage") && f
+					.getNumberOfAttributes() >= 2)) {
+				// I am sure, that it is a raster some. We do not have to cast
+				// it to either cridcoverage or abstractReader, as the results
+				// are tested anyway...
+				return f.getAttribute(1);
+			}
+			/** CHANGE SK 9.8.08 END */
 
-    public boolean isSetWaitCursorDuringNextRepaint() {
-        return setWaitCursorDuringNextRepaint;
-    }
+			if (f.getNumberOfAttributes() != 2
+					|| // Geaendert, da es bei AbstractGridCoverageReader 3 sind
+					// (SK, 19.08.07)
+					!(f.getAttribute(0) instanceof com.vividsolutions.jts.geom.Geometry)
+					|| !(f.getAttribute(1) instanceof GridCoverage2D))
+				return fc;
 
-    /**
-     * When setting this to true, the next repaint of this component will be
-     * accompanied by a WAIT Cursor
-     *
-     * @author <a href="mailto:skpublic at wikisquare.de">Stefan Alfons
-     *         Kr&uuml;ger</a>
-     */
-    public void setWaitCursorDuringNextRepaint(
-            boolean waitCursorDuringNextRepaint) {
-        this.setWaitCursorDuringNextRepaint = waitCursorDuringNextRepaint;
-    }
+			// Objekt ist ein Raster!
+			return (GridCoverage2D) f.getAttribute(1);
+		} catch (Exception err) {
+			LOGGER.warn(err.getMessage(), err);
+			return null;
+		}
+	}
 
-    /**
-     * Gibt den "normalen" Cursor zurueck. Dieser kann neben dem "pointer" auch
-     * ein Sanduhr-Wartecursor sein.
-     *
-     * @author <a href="mailto:skpublic at wikisquare.de">Stefan Alfons
-     *         Kr&uuml;ger</a>
-     */
-    public Cursor getNormalCursor() {
-        return normalCursor;
-    }
+	/**
+	 * 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>
+	 */
 
-    /**
-     * Setzt den "normalen" Cursor. Dieser kann neben dem default "pointer" z.B.
-     * auch ein Sanduhr-Wartecursor sein.
-     *
-     * @author <a href="mailto:skpublic at wikisquare.de">Stefan Alfons
-     *         Kr&uuml;ger</a>
-     */
-    public void setNormalCursor(Cursor normalCursor) {
-        this.normalCursor = normalCursor;
-    }
+	public void dispose() {
+		if (isDisposed())
+			return;
 
-    // /**
-    // * Prueft, ob es sich bei einem Layer um ein Raster-Layer handelt.
-    // * Raster-Layer zeichnen sich dadurch aus, dass die zugrunde liegende
-    // * {@link FeatureCollection} nur ein Feature enthaelt, das genau ein
-    // Attribut
-    // * vom Type {@link org.geotools.feature.type.FeatureAttributeType} hat,
-    // welches
-    // * wiederum genau zwei Attribute hat:<br>
-    // * Eines vom Typ {@link
-    // org.opengis.spatialschema.geometry.geometry.Polygon}
-    // * und eines vom Typ {@link org.opengis.coverage.grid.GridCoverage}.
-    // * @param layer zu ueberpruefendes Layer
-    // */
-    // public static boolean isGridCoverageLayer(MapLayer layer) {
-    // try {
-    // FeatureCollection fc = layer.getFeatureSource().getFeatures();
-    // // Layer muss genau ein Feature beinhalten
-    // if ( fc == null || fc.size() != 1 )
-    // return false;
-    // // Feature muss genau 1 Attribut vom Typ FeatureAttributeType haben
-    // FeatureType ftype = fc.getFeatureType();
-    // if ( ftype == null || ftype.getAttributeCount() != 1 ||
-    // !(ftype.getAttributeType(0) instanceof
-    // org.geotools.feature.type.FeatureAttributeType) )
-    // return false;
-    // // FeatureAttribute muss genau 2 Atrribute haben
-    // org.geotools.feature.type.FeatureAttributeType atype =
-    // (org.geotools.feature
-    // .type.FeatureAttributeType)ftype.getAttributeType(0);
-    // if ( atype == null || atype.getAttributeCount() != 2 )
-    // return false;
-    // // Typ des ersten Attributs muss Polygon sein
-    // if ( !com.vividsolutions.jts.geom.Polygon.class.isAssignableFrom(
-    // atype.getAttributeType(0).getType() ) )
-    // return false;
-    // // Typ des zweiten Attributs muss GridCoverage sein
-    // if ( !org.opengis.coverage.grid.GridCoverage.class.isAssignableFrom(
-    // atype.getAttributeType(1).getType() ) )
-    // return false;
-    //
-    // } catch (Exception err) {
-    // }
-    // return true;
-    // }
+		if (dragWaitCursorListener != null)
+			this.removeMouseListener(dragWaitCursorListener);
+		if (mouseWheelZoomListener != null)
+			this.removeMouseWheelListener(mouseWheelZoomListener);
 
-    /**
-     * Nuetzlich wenn die Componente gedruckt (z.B. wenn ein Screenshot gemacht wird) wird. Dann werden wird der
-     * Hintergrund auf WEISS gesetzt.
-     *
-     * @author <a href="mailto:skpublic at wikisquare.de">Stefan Alfons
-     *         Kr&uuml;ger</a>
-     */
-    @Override
-    public void print(Graphics g) {
-        Color orig = getBackground();
-        setBackground(Color.WHITE);
+		// Alle mapPaneListener entfernen
+		mapPaneListeners.clear();
 
-        // wrap in try/finally so that we always restore the state
-        try {
-            super.print(g);
-        } finally {
-            setBackground(orig);
-        }
-    }
+		getContext().clearLayerList();
 
-    /**
-     * Sets the mapArea to smartly present the given features. Note: The method
-     * does not call {@link #repaint()} on the {@link JMapPane}.
-     */
-    public void zoomTo(org.geotools.feature.Feature feature) {
-        final MemoryFeatureCollection mfc = new MemoryFeatureCollection(feature
-                .getFeatureType());
-        mfc.add(feature);
-        zoomTo(mfc);
-    }
+		removeAll();
+		disposed = true;
+	}
 
-    /**
-     * Sets the mapArea to best possibly present the given features. If only one
-     * single point is given, the window is moved over the point.
-     *
-     * Note: The method does not call {@link #repaint()} on the {@link JMapPane}
-     * .
-     *
-     * @param features
-     *            if <code>null</code> or size==0, the function doesn nothing.
-     */
-    public void zoomTo(FeatureCollection features) {
+	/**
+	 * A flag indicating if dispose() has already been called. If true, then
+	 * further use of this {@link JMapPane} is undefined.
+	 */
+	private boolean isDisposed() {
+		return disposed;
+	}
 
-        CoordinateReferenceSystem mapCRS = getContext()
-                .getCoordinateReferenceSystem();
-        CoordinateReferenceSystem fCRS = features.getSchema()
-                .getDefaultGeometry().getCoordinateSystem();
-        // if (! mapCRS.equals(fCRS)) {
-        // throw new
-        // RuntimeException("Projecting the features to show to the map CRS is not yet implemented.");
-        // }
+	//
+	// /**
+	// * Werden Rasterlayer waehrend einer PAN Aktion versteckt?
+	// * @author <a href="mailto:skpublic at wikisquare.de">Stefan Alfons
+	// Kr&uuml;ger</a>
+	// */
+	// public boolean isHideRasterLayersDuringPan() {
+	// return hideRasterLayersDuringPan;
+	// }
+	//
+	// /**
+	// * Bestimmt, ob Rasterlayer waehrend einer PAN Aktion versteckt werden
+	// soll. Default ist false.
+	// * @param hideRasterLayersDuringPan
+	// * @author <a href="mailto:skpublic at wikisquare.de">Stefan Alfons
+	// Kr&uuml;ger</a>
+	// */
+	// public void setHideRasterLayersDuringPan(boolean
+	// hideRasterLayersDuringPan) {
+	// this.hideRasterLayersDuringPan = hideRasterLayersDuringPan;
+	// }
 
-        double width = mapArea.getWidth();
-        double height = mapArea.getHeight();
-        double ratio = height / width;
+	public boolean isSetWaitCursorDuringNextRepaint() {
+		return setWaitCursorDuringNextRepaint;
+	}
 
-        if (features == null || features.size() == 0) {
-            // feature count == 0 Zoom to the full extend
-            return;
-        } else if (features.size() == 1) {
+	/**
+	 * When setting this to true, the next repaint of this component will be
+	 * accompanied by a WAIT Cursor
+	 * 
+	 * @author <a href="mailto:skpublic at wikisquare.de">Stefan Alfons
+	 *         Kr&uuml;ger</a>
+	 */
+	public void setWaitCursorDuringNextRepaint(
+			boolean waitCursorDuringNextRepaint) {
+		this.setWaitCursorDuringNextRepaint = waitCursorDuringNextRepaint;
+	}
 
-            // feature count == 1 Just move the window to the point and zoom 'a
-            // bit'
-            Feature singleFeature = (Feature) features.iterator().next();
+	/**
+	 * Gibt den "normalen" Cursor zurueck. Dieser kann neben dem "pointer" auch
+	 * ein Sanduhr-Wartecursor sein.
+	 * 
+	 * @author <a href="mailto:skpublic at wikisquare.de">Stefan Alfons
+	 *         Kr&uuml;ger</a>
+	 */
+	public Cursor getNormalCursor() {
+		return normalCursor;
+	}
 
-            if (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;
-            }
+	/**
+	 * Setzt den "normalen" Cursor. Dieser kann neben dem default "pointer" z.B.
+	 * auch ein Sanduhr-Wartecursor sein.
+	 * 
+	 * @author <a href="mailto:skpublic at wikisquare.de">Stefan Alfons
+	 *         Kr&uuml;ger</a>
+	 */
+	public void setNormalCursor(Cursor normalCursor) {
+		this.normalCursor = normalCursor;
+	}
 
-            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 (FactoryException e) {
-                    LOGGER.error("Looking for a Math transform", e);
-                } catch (TransformException e) {
-                    LOGGER.error("Looking for a Math transform", e);
-                }
-            }
+	// /**
+	// * Prueft, ob es sich bei einem Layer um ein Raster-Layer handelt.
+	// * Raster-Layer zeichnen sich dadurch aus, dass die zugrunde liegende
+	// * {@link FeatureCollection} nur ein Feature enthaelt, das genau ein
+	// Attribut
+	// * vom Type {@link org.geotools.feature.type.FeatureAttributeType} hat,
+	// welches
+	// * wiederum genau zwei Attribute hat:<br>
+	// * Eines vom Typ {@link
+	// org.opengis.spatialschema.geometry.geometry.Polygon}
+	// * und eines vom Typ {@link org.opengis.coverage.grid.GridCoverage}.
+	// * @param layer zu ueberpruefendes Layer
+	// */
+	// public static boolean isGridCoverageLayer(MapLayer layer) {
+	// try {
+	// FeatureCollection fc = layer.getFeatureSource().getFeatures();
+	// // Layer muss genau ein Feature beinhalten
+	// if ( fc == null || fc.size() != 1 )
+	// return false;
+	// // Feature muss genau 1 Attribut vom Typ FeatureAttributeType haben
+	// FeatureType ftype = fc.getFeatureType();
+	// if ( ftype == null || ftype.getAttributeCount() != 1 ||
+	// !(ftype.getAttributeType(0) instanceof
+	// org.geotools.feature.type.FeatureAttributeType) )
+	// return false;
+	// // FeatureAttribute muss genau 2 Atrribute haben
+	// org.geotools.feature.type.FeatureAttributeType atype =
+	// (org.geotools.feature
+	// .type.FeatureAttributeType)ftype.getAttributeType(0);
+	// if ( atype == null || atype.getAttributeCount() != 2 )
+	// return false;
+	// // Typ des ersten Attributs muss Polygon sein
+	// if ( !com.vividsolutions.jts.geom.Polygon.class.isAssignableFrom(
+	// atype.getAttributeType(0).getType() ) )
+	// return false;
+	// // Typ des zweiten Attributs muss GridCoverage sein
+	// if ( !org.opengis.coverage.grid.GridCoverage.class.isAssignableFrom(
+	// atype.getAttributeType(1).getType() ) )
+	// return false;
+	//
+	// } catch (Exception err) {
+	// }
+	// return true;
+	// }
 
-            Coordinate newLeftBottom = new Coordinate(centre.x - width / 2.,
-                    centre.y - height / 2.);
-            Coordinate newTopRight = new Coordinate(centre.x + width / 2.,
-                    centre.y + height / 2.);
+	/**
+	 * Nuetzlich wenn die Componente gedruckt (z.B. wenn ein Screenshot gemacht
+	 * wird) wird. Dann werden wird der Hintergrund auf WEISS gesetzt.
+	 * 
+	 * @author <a href="mailto:skpublic at wikisquare.de">Stefan Alfons
+	 *         Kr&uuml;ger</a>
+	 */
+	@Override
+	public void print(Graphics g) {
+		Color orig = getBackground();
+		setBackground(Color.WHITE);
 
-            Envelope newMapArea = new Envelope(newLeftBottom, newTopRight);
+		// wrap in try/finally so that we always restore the state
+		try {
+			super.print(g);
+		} finally {
+			setBackground(orig);
+		}
+	}
 
-            setMapArea(newMapArea);
+	/**
+	 * Sets the mapArea to smartly present the given features. Note: The method
+	 * does not call {@link #repaint()} on the {@link JMapPane}.
+	 */
+	public void zoomTo(org.geotools.feature.Feature feature) {
+		final MemoryFeatureCollection mfc = new MemoryFeatureCollection(feature
+				.getFeatureType());
+		mfc.add(feature);
+		zoomTo(mfc);
+	}
 
-        } else {
-            ReferencedEnvelope fBounds = features.getBounds();
+	/**
+	 * Sets the mapArea to best possibly present the given features. If only one
+	 * single point is given, the window is moved over the point.
+	 * 
+	 * Note: The method does not call {@link #repaint()} on the {@link JMapPane}
+	 * .
+	 * 
+	 * @param features
+	 *            if <code>null</code> or size==0, the function doesn nothing.
+	 */
+	public void zoomTo(FeatureCollection features) {
 
-            Envelope bounds;
-            if (!mapCRS.equals(fCRS)) {
-                bounds = JTSUtil.transformEnvelope(fBounds, fCRS, mapCRS);
-            } else {
-                bounds = fBounds;
-            }
-            // BB umrechnen von Layer-CRS in Map-CRS
+		CoordinateReferenceSystem mapCRS = getContext()
+				.getCoordinateReferenceSystem();
+		CoordinateReferenceSystem fCRS = features.getSchema()
+				.getDefaultGeometry().getCoordinateSystem();
+		// if (! mapCRS.equals(fCRS)) {
+		// throw new
+		// RuntimeException("Projecting the features to show to the map CRS is not yet implemented.");
+		// }
 
-            // Expand a bit
-            bounds.expandBy(bounds.getWidth() / 6., bounds.getHeight() / 6.);
+		double width = mapArea.getWidth();
+		double height = mapArea.getHeight();
+		double ratio = height / width;
 
-            setMapArea(bounds);
-        }
-    }
+		if (features == null || features.size() == 0) {
+			// feature count == 0 Zoom to the full extend
+			return;
+		} else if (features.size() == 1) {
 
-    /**
-     * The {@link GeomFilterGenerator} prepares a {@link BinarySpatialOperator} filter
-     * for multiple use. Only the "right" argument is prepared. The "left" argument
-     * (the geometry attribute of the {@link FeatureSource} to filter) is
-     * first set on calling {@link #adaptFilter(FeatureSource)} for a specific
-     * {@link FeatureSource}. This method also takes care to recreate the filter
-     * (or its "right" argument) if the given {@link FeatureSource} has another
-     * {@link CoordinateReferenceSystem} than the base constraint.<br>
-     * The type of filter (e.g. distance or bounding box) is specified by
-     * the subclass implemenation of {@link #prepareFilter(CoordinateReferenceSystem)}.
-     * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a>
-     */
-    private static abstract class GeomFilterGenerator {
-      /** Holds the {@link CoordinateReferenceSystem} the filter constraint
-       *  bases on. */
-      protected CoordinateReferenceSystem baseCRS = null;
-      /** Caches the base filter constraint for several
-       *  {@link CoordinateReferenceSystem CoordinateReferenceSystems}. */
-      protected Map<CoordinateReferenceSystem, GeometryFilterImpl> filterCache = new HashMap<CoordinateReferenceSystem, GeometryFilterImpl>();
+			// feature count == 1 Just move the window to the point and zoom 'a
+			// bit'
+			Feature singleFeature = (Feature) features.iterator().next();
 
-      /**
-       * Creates a new filter generator
-       * @param crs {@link CoordinateReferenceSystem} the base constraint ("right"
-       *            filter argument is relative to)
-       */
-      public GeomFilterGenerator(CoordinateReferenceSystem crs) {
-        this.baseCRS = crs;
-      }
+			if (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;
+			}
 
-      /**
-       * Creates a filter containing the base constraint ("right" argument)
-       * transformed to the given {@link CoordinateReferenceSystem}.
-       * @param crs the {@link CoordinateReferenceSystem} the base constraint is
-       *            transformed to
-       */
-      protected abstract GeometryFilterImpl prepareFilter(CoordinateReferenceSystem crs);
+			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 (FactoryException e) {
+					LOGGER.error("Looking for a Math transform", e);
+				} catch (TransformException e) {
+					LOGGER.error("Looking for a Math transform", e);
+				}
+			}
 
-      /**
-       * Completes the filter with its "left" argument for a concrete
-       * {@link FeatureSource}. If the {@link FeatureSource FeatureSource's}
-       * CRS differs from the CRS the base constraint is specified in, first
-       * a new filter is created by calling {@link #prepareFilter(CoordinateReferenceSystem)}.
-       * @param fs {@link FeatureSource} the filter is adaped to
-       * @return
-       */
-      public GeometryFilterImpl adaptFilter(FeatureSource fs) {
-        GeometryAttributeType     geomAttr = fs.getSchema().getDefaultGeometry();
-        CoordinateReferenceSystem fsCRS    = geomAttr.getCoordinateSystem();
-        GeometryFilterImpl        filter   = filterCache.get(fsCRS);
-        if ( filter == null ) {
-          filter = prepareFilter(fsCRS);
-          filterCache.put(fsCRS, filter);
-        }
-        Expression geometry = ff.createAttributeExpression(geomAttr.getLocalName());
-        filter.setExpression1(geometry);
-        return filter;
-      }
+			Coordinate newLeftBottom = new Coordinate(centre.x - width / 2.,
+					centre.y - height / 2.);
+			Coordinate newTopRight = new Coordinate(centre.x + width / 2.,
+					centre.y + height / 2.);
 
-    }
+			Envelope newMapArea = new Envelope(newLeftBottom, newTopRight);
 
-    /**
-     * {@link GeomFilterGenerator} for a bounding box constraint.
-     * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a>
-     */
-    private static class BoundingBoxFilterGenerator extends GeomFilterGenerator {
-      /** Holds the base constraint (bounding box {@link Envelope}) relative to
-       *  the {@linkplain GeomFilterGenerator#baseCRS base CRS}. */
-      protected Envelope baseEnv = null;
+			setMapArea(newMapArea);
 
-      /**
-       * Creates a new filter generator.
-       * @param baseEnv defines the bounding box
-       * @param crs     defines the CRS of the bounding box
-       */
-      public BoundingBoxFilterGenerator(Envelope baseEnv, CoordinateReferenceSystem crs) {
-        super(crs);
-        this.baseEnv = baseEnv;
-      }
+		} else {
+			ReferencedEnvelope fBounds = features.getBounds();
 
-      /**
-       * Prepares a filter with the bounding box transformed to the
-       * given {@link CoordinateReferenceSystem} as the "right" argument.
-       * @param crs the {@link CoordinateReferenceSystem} the bounding box is
-       *            transformed to
-       */
-      protected GeometryFilterImpl prepareFilter(CoordinateReferenceSystem crs) {
-        Envelope bbEnv = baseEnv;
-        if ( !baseCRS.equals(crs) )
-          bbEnv = JTSUtil.transformEnvelope(baseEnv, baseCRS, crs);
-        // Filter fuer Envelope zusammenstellen
-        Expression bbox = FilterUtil.FILTER_FAC.createBBoxExpression(bbEnv);
-        GeometryFilterImpl bboxFilter = (GeometryFilterImpl) FilterUtil.FILTER_FAC.createGeometryFilter(AbstractFilter.GEOMETRY_BBOX);
-        // GeometryFilterImpl bboxFilter = (GeometryFilterImpl)ff.createGeometryFilter(AbstractFilter.GEOMETRY_WITHIN);
-        bboxFilter.setExpression2(bbox);
-        return bboxFilter;
-      }
-    }
+			Envelope bounds;
+			if (!mapCRS.equals(fCRS)) {
+				bounds = JTSUtil.transformEnvelope(fBounds, fCRS, mapCRS);
+			} else {
+				bounds = fBounds;
+			}
+			// BB umrechnen von Layer-CRS in Map-CRS
 
-    /**
-     * {@link GeomFilterGenerator} for a "near distance" constraint.
-     * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a>
-     */
-    private static class NearPointFilterGenerator extends GeomFilterGenerator {
-      /** Holds the base constraint (coordinate) relative to
-       *  the {@linkplain GeomFilterGenerator#baseCRS base CRS}. */
-      protected Coordinate basePoint = null;
-      /** Holds the distance "around" the base point relative to
-       *  the {@linkplain GeomFilterGenerator#baseCRS base CRS}. */
-      protected double     baseDist  = 0.0;
-      /** Holds a point which is in distance {@link #baseDist} to the
-       * {@link #basePoint}. */
-      protected Coordinate basePoint2 = null;
+			// Expand a bit
+			bounds.expandBy(bounds.getWidth() / 6., bounds.getHeight() / 6.);
 
-      /**
-       * Creates a new filter generator.
-       * @param basePoint defines the point for the "near point" constraint
-       * @param dist      defines the distance around the base point
-       * @param crs       defines the CRS of base point
-       */
-      public NearPointFilterGenerator(Coordinate basePoint, double dist, CoordinateReferenceSystem crs) {
-        super(crs);
-        this.basePoint  = basePoint;
-        this.baseDist   = dist;
-        // Create a point which is in distance "dist" to the base point
-        this.basePoint2 = new Coordinate(basePoint.x+dist, basePoint.y);
-      }
+			setMapArea(bounds);
+		}
+	}
 
-      /**
-       * Creates a new filter generator.
-       * @param basePoint defines the point for the "near point" constraint
-       * @param dist      defines the distance around the base point
-       * @param crs       defines the CRS of base point
-       */
-      public NearPointFilterGenerator(Point2D basePoint, double dist, CoordinateReferenceSystem crs) {
-        this( new Coordinate(basePoint.getX(),basePoint.getY()),dist,crs);
-      }
+	/**
+	 * The {@link GeomFilterGenerator} prepares a {@link BinarySpatialOperator}
+	 * filter for multiple use. Only the "right" argument is prepared. The
+	 * "left" argument (the geometry attribute of the {@link FeatureSource} to
+	 * filter) is first set on calling {@link #adaptFilter(FeatureSource)} for a
+	 * specific {@link FeatureSource}. This method also takes care to recreate
+	 * the filter (or its "right" argument) if the given {@link FeatureSource}
+	 * has another {@link CoordinateReferenceSystem} than the base constraint.<br>
+	 * The type of filter (e.g. distance or bounding box) is specified by the
+	 * subclass implemenation of
+	 * {@link #prepareFilter(CoordinateReferenceSystem)}.
+	 * 
+	 * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a>
+	 */
+	private static abstract class GeomFilterGenerator {
+		/**
+		 * Holds the {@link CoordinateReferenceSystem} the filter constraint
+		 * bases on.
+		 */
+		protected CoordinateReferenceSystem baseCRS = null;
+		/**
+		 * Caches the base filter constraint for several
+		 * {@link CoordinateReferenceSystem CoordinateReferenceSystems}.
+		 */
+		protected Map<CoordinateReferenceSystem, GeometryFilterImpl> filterCache = new HashMap<CoordinateReferenceSystem, GeometryFilterImpl>();
 
-      /**
-       * Prepares a filter with the base point and distance transformed to the
-       * given {@link CoordinateReferenceSystem} as the "right" argument.
-       * @param crs the {@link CoordinateReferenceSystem} the point and distance is
-       *            transformed to
-       */
-      protected GeometryFilterImpl prepareFilter(CoordinateReferenceSystem crs) {
-        Coordinate nearPoint = basePoint;
-        double     nearDist  = baseDist;
-        if ( !baseCRS.equals(crs) ) {
-          nearPoint = JTSUtil.transformCoordinate(basePoint, baseCRS, crs);
-          // Transform the distance (maybe "dirty")
-          // --> transform the point2 and calculate the
-          //     distance to the tranformed base point
-          Coordinate nearPoint2 = JTSUtil.transformCoordinate(basePoint2, baseCRS, crs);
-          
-          if (nearPoint == null || nearPoint2 == null) throw new RuntimeException("Unable to transform CRS from "+baseCRS+" to "+crs);
-          
-          nearDist = Math.abs(nearPoint.x - nearPoint2.x);
-        }
-        // Filter fuer Point zusammenstellen
-        final Geometry    geometry      = FilterUtil.GEOMETRY_FAC.createPoint(nearPoint);
-        final DWithinImpl dwithinFilter = (DWithinImpl)FilterUtil.FILTER_FAC.createGeometryDistanceFilter(DWithinImpl.GEOMETRY_DWITHIN);
-        dwithinFilter.setDistance(nearDist);
-        dwithinFilter.setExpression2(FilterUtil.FILTER_FAC.createLiteralExpression(geometry));
+		/**
+		 * Creates a new filter generator
+		 * 
+		 * @param crs
+		 *            {@link CoordinateReferenceSystem} the base constraint
+		 *            ("right" filter argument is relative to)
+		 */
+		public GeomFilterGenerator(CoordinateReferenceSystem crs) {
+			this.baseCRS = crs;
+		}
 
-        return dwithinFilter;
-      }
+		/**
+		 * Creates a filter containing the base constraint ("right" argument)
+		 * transformed to the given {@link CoordinateReferenceSystem}.
+		 * 
+		 * @param crs
+		 *            the {@link CoordinateReferenceSystem} the base constraint
+		 *            is transformed to
+		 */
+		protected abstract GeometryFilterImpl prepareFilter(
+				CoordinateReferenceSystem crs);
 
-    }
+		/**
+		 * Completes the filter with its "left" argument for a concrete
+		 * {@link FeatureSource}. If the {@link FeatureSource FeatureSource's}
+		 * CRS differs from the CRS the base constraint is specified in, first a
+		 * new filter is created by calling
+		 * {@link #prepareFilter(CoordinateReferenceSystem)}.
+		 * 
+		 * @param fs
+		 *            {@link FeatureSource} the filter is adaped to
+		 * @return
+		 */
+		public GeometryFilterImpl adaptFilter(FeatureSource fs) {
+			GeometryAttributeType geomAttr = fs.getSchema()
+					.getDefaultGeometry();
+			CoordinateReferenceSystem fsCRS = geomAttr.getCoordinateSystem();
+			GeometryFilterImpl filter = filterCache.get(fsCRS);
+			if (filter == null) {
+				filter = prepareFilter(fsCRS);
+				filterCache.put(fsCRS, filter);
+			}
+			Expression geometry = ff.createAttributeExpression(geomAttr
+					.getLocalName());
+			filter.setExpression1(geometry);
+			return filter;
+		}
+
+	}
+
+	/**
+	 * {@link GeomFilterGenerator} for a bounding box constraint.
+	 * 
+	 * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a>
+	 */
+	private static class BoundingBoxFilterGenerator extends GeomFilterGenerator {
+		/**
+		 * Holds the base constraint (bounding box {@link Envelope}) relative to
+		 * the {@linkplain GeomFilterGenerator#baseCRS base CRS}.
+		 */
+		protected Envelope baseEnv = null;
+
+		/**
+		 * Creates a new filter generator.
+		 * 
+		 * @param baseEnv
+		 *            defines the bounding box
+		 * @param crs
+		 *            defines the CRS of the bounding box
+		 */
+		public BoundingBoxFilterGenerator(Envelope baseEnv,
+				CoordinateReferenceSystem crs) {
+			super(crs);
+			this.baseEnv = baseEnv;
+		}
+
+		/**
+		 * Prepares a filter with the bounding box transformed to the given
+		 * {@link CoordinateReferenceSystem} as the "right" argument.
+		 * 
+		 * @param crs
+		 *            the {@link CoordinateReferenceSystem} the bounding box is
+		 *            transformed to
+		 */
+		protected GeometryFilterImpl prepareFilter(CoordinateReferenceSystem crs) {
+			Envelope bbEnv = baseEnv;
+			if (!baseCRS.equals(crs))
+				bbEnv = JTSUtil.transformEnvelope(baseEnv, baseCRS, crs);
+			// Filter fuer Envelope zusammenstellen
+			Expression bbox = FilterUtil.FILTER_FAC.createBBoxExpression(bbEnv);
+			GeometryFilterImpl bboxFilter = (GeometryFilterImpl) FilterUtil.FILTER_FAC
+					.createGeometryFilter(AbstractFilter.GEOMETRY_BBOX);
+			// GeometryFilterImpl bboxFilter =
+			// (GeometryFilterImpl)ff.createGeometryFilter(AbstractFilter.GEOMETRY_WITHIN);
+			bboxFilter.setExpression2(bbox);
+			return bboxFilter;
+		}
+	}
+
+	/**
+	 * {@link GeomFilterGenerator} for a "near distance" constraint.
+	 * 
+	 * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a>
+	 */
+	private static class NearPointFilterGenerator extends GeomFilterGenerator {
+		/**
+		 * Holds the base constraint (coordinate) relative to the
+		 * {@linkplain GeomFilterGenerator#baseCRS base CRS}.
+		 */
+		protected Coordinate basePoint = null;
+		/**
+		 * Holds the distance "around" the base point relative to the
+		 * {@linkplain GeomFilterGenerator#baseCRS base CRS}.
+		 */
+		protected double baseDist = 0.0;
+		/**
+		 * Holds a point which is in distance {@link #baseDist} to the
+		 * {@link #basePoint}.
+		 */
+		protected Coordinate basePoint2 = null;
+
+		/**
+		 * Creates a new filter generator.
+		 * 
+		 * @param basePoint
+		 *            defines the point for the "near point" constraint
+		 * @param dist
+		 *            defines the distance around the base point
+		 * @param crs
+		 *            defines the CRS of base point
+		 */
+		public NearPointFilterGenerator(Coordinate basePoint, double dist,
+				CoordinateReferenceSystem crs) {
+			super(crs);
+			this.basePoint = basePoint;
+			this.baseDist = dist;
+			// Create a point which is in distance "dist" to the base point
+			this.basePoint2 = new Coordinate(basePoint.x + dist, basePoint.y);
+		}
+
+		/**
+		 * Creates a new filter generator.
+		 * 
+		 * @param basePoint
+		 *            defines the point for the "near point" constraint
+		 * @param dist
+		 *            defines the distance around the base point
+		 * @param crs
+		 *            defines the CRS of base point
+		 */
+		public NearPointFilterGenerator(Point2D basePoint, double dist,
+				CoordinateReferenceSystem crs) {
+			this(new Coordinate(basePoint.getX(), basePoint.getY()), dist, crs);
+		}
+
+		/**
+		 * Prepares a filter with the base point and distance transformed to the
+		 * given {@link CoordinateReferenceSystem} as the "right" argument.
+		 * 
+		 * @param crs
+		 *            the {@link CoordinateReferenceSystem} the point and
+		 *            distance is transformed to
+		 */
+		protected GeometryFilterImpl prepareFilter(CoordinateReferenceSystem crs) {
+			Coordinate nearPoint = basePoint;
+			double nearDist = baseDist;
+			if (!baseCRS.equals(crs)) {
+				nearPoint = JTSUtil
+						.transformCoordinate(basePoint, baseCRS, crs);
+				// Transform the distance (maybe "dirty")
+				// --> transform the point2 and calculate the
+				// distance to the tranformed base point
+				Coordinate nearPoint2 = JTSUtil.transformCoordinate(basePoint2,
+						baseCRS, crs);
+
+				if (nearPoint == null || nearPoint2 == null)
+					throw new RuntimeException("Unable to transform CRS from "
+							+ baseCRS + " to " + crs);
+
+				nearDist = Math.abs(nearPoint.x - nearPoint2.x);
+			}
+			// Filter fuer Point zusammenstellen
+			final Geometry geometry = FilterUtil.GEOMETRY_FAC
+					.createPoint(nearPoint);
+			final DWithinImpl dwithinFilter = (DWithinImpl) FilterUtil.FILTER_FAC
+					.createGeometryDistanceFilter(DWithinImpl.GEOMETRY_DWITHIN);
+			dwithinFilter.setDistance(nearDist);
+			dwithinFilter.setExpression2(FilterUtil.FILTER_FAC
+					.createLiteralExpression(geometry));
+
+			return dwithinFilter;
+		}
+
+	}
+
+	/**
+	 * Allows to optionally supply the {@link JMapPane} with meta information
+	 * about layers. This is used (when supplied) for the algorithm that selects
+	 * features with a mouse click.
+	 * 
+	 * @param layerID
+	 * @param atm
+	 */
+	public void setAttributeMetaDataFor(String layerID,
+			Map<Integer, AttributeMetaData> aMDMap) {
+		attributeMetaDataMapCache.put(layerID, aMDMap);
+	}
 }

Modified: trunk/src/skrueger/AttributeMetaData.java
===================================================================
--- trunk/src/skrueger/AttributeMetaData.java	2009-08-18 12:01:45 UTC (rev 303)
+++ trunk/src/skrueger/AttributeMetaData.java	2009-08-19 12:03:12 UTC (rev 304)
@@ -64,7 +64,7 @@
 		this.title = title;
 		this.desc = desc;
 		if (colIdx == 0){
-			// The first attribut is THE_GEOM and shall never be visible!
+			// The first attribute is THE_GEOM and shall never be visible!
 			this.visible = false;
 		}else
 			this.visible = visible;



More information about the Schmitzm-commits mailing list