[Schmitzm-commits] r607 - in branches/2.0-RC1: src/schmitzm/data src/schmitzm/geotools src/schmitzm/geotools/feature src/schmitzm/geotools/gui src/schmitzm/geotools/io src/schmitzm/geotools/styling src/schmitzm/io src/schmitzm/lang/tree src/schmitzm/swing src/schmitzm/swing/resource/locales src/skrueger src/skrueger/geotools src/skrueger/geotools/labelsearch src/skrueger/geotools/selection src/skrueger/i8n src/skrueger/swing src_junit/skrueger/i8n

scm-commit@wald.intevation.org scm-commit at wald.intevation.org
Wed Dec 9 16:13:54 CET 2009


Author: alfonx
Date: 2009-12-09 16:13:42 +0100 (Wed, 09 Dec 2009)
New Revision: 607

Modified:
   branches/2.0-RC1/src/schmitzm/data/RasterCalculator.java
   branches/2.0-RC1/src/schmitzm/data/RasterOperationTreeParser.java
   branches/2.0-RC1/src/schmitzm/geotools/GTUtil.java
   branches/2.0-RC1/src/schmitzm/geotools/JTSUtil.java
   branches/2.0-RC1/src/schmitzm/geotools/feature/CQLFilterParser.java
   branches/2.0-RC1/src/schmitzm/geotools/feature/FeatureOperationTreeParser.java
   branches/2.0-RC1/src/schmitzm/geotools/feature/FilterParser.java
   branches/2.0-RC1/src/schmitzm/geotools/gui/FeatureCollectionFilterPanel.java
   branches/2.0-RC1/src/schmitzm/geotools/gui/FeatureFilterPanel.java
   branches/2.0-RC1/src/schmitzm/geotools/gui/FeatureLayerFilterDialog.java
   branches/2.0-RC1/src/schmitzm/geotools/gui/FeatureTablePane.java
   branches/2.0-RC1/src/schmitzm/geotools/gui/GeoMapPane.java
   branches/2.0-RC1/src/schmitzm/geotools/gui/GridPanel.java
   branches/2.0-RC1/src/schmitzm/geotools/gui/GridPanelFormatter_LatLon1.java
   branches/2.0-RC1/src/schmitzm/geotools/gui/JEditorPane.java
   branches/2.0-RC1/src/schmitzm/geotools/gui/JEditorToolBar.java
   branches/2.0-RC1/src/schmitzm/geotools/gui/LayeredMapFrame.java
   branches/2.0-RC1/src/schmitzm/geotools/gui/MapContextControlPane.java
   branches/2.0-RC1/src/schmitzm/geotools/gui/SelectableFeatureTablePane.java
   branches/2.0-RC1/src/schmitzm/geotools/gui/SelectableXMapPane.java
   branches/2.0-RC1/src/schmitzm/geotools/io/GeoExportUtil.java
   branches/2.0-RC1/src/schmitzm/geotools/styling/StylingUtil.java
   branches/2.0-RC1/src/schmitzm/io/IOUtil.java
   branches/2.0-RC1/src/schmitzm/lang/tree/OperationTreeParser.java
   branches/2.0-RC1/src/schmitzm/swing/ExceptionDialog.java
   branches/2.0-RC1/src/schmitzm/swing/OperationTreePanel.java
   branches/2.0-RC1/src/schmitzm/swing/StatusDialog.java
   branches/2.0-RC1/src/schmitzm/swing/SwingUtil.java
   branches/2.0-RC1/src/schmitzm/swing/resource/locales/SwingResourceBundle.properties
   branches/2.0-RC1/src/schmitzm/swing/resource/locales/SwingResourceBundle_de.properties
   branches/2.0-RC1/src/schmitzm/swing/resource/locales/SwingResourceBundle_fr.properties
   branches/2.0-RC1/src/skrueger/RasterLegendData.java
   branches/2.0-RC1/src/skrueger/geotools/GeomFilterGenerator.java
   branches/2.0-RC1/src/skrueger/geotools/MapContextManagerInterface.java
   branches/2.0-RC1/src/skrueger/geotools/MapPaneToolBar.java
   branches/2.0-RC1/src/skrueger/geotools/RenderingExecutor.java
   branches/2.0-RC1/src/skrueger/geotools/SelectXMapPaneMouseListener.java
   branches/2.0-RC1/src/skrueger/geotools/StyledFS.java
   branches/2.0-RC1/src/skrueger/geotools/StyledFeatureCollectionTableModel.java
   branches/2.0-RC1/src/skrueger/geotools/StyledLayerUtil.java
   branches/2.0-RC1/src/skrueger/geotools/XMapPane.java
   branches/2.0-RC1/src/skrueger/geotools/ZoomXMapPaneMouseListener.java
   branches/2.0-RC1/src/skrueger/geotools/labelsearch/LabelSearch.java
   branches/2.0-RC1/src/skrueger/geotools/selection/FeatureMapLayerSelectionSynchronizer.java
   branches/2.0-RC1/src/skrueger/i8n/SwitchLanguageDialog.java
   branches/2.0-RC1/src/skrueger/i8n/Translation.java
   branches/2.0-RC1/src/skrueger/swing/CancellableDialogAdapter.java
   branches/2.0-RC1/src/skrueger/swing/HeapBar.java
   branches/2.0-RC1/src_junit/skrueger/i8n/SwitchLanguageDialogTest.java
Log:
Keine Ahnung was er da gebrancht hat.. der stand der dateien war weder trunk, noch der 1.0-gt26 branch... ich hab die dateien jetzt h?\195?\164ndisch auf den richtigen stand gebracht und comitte


Modified: branches/2.0-RC1/src/schmitzm/data/RasterCalculator.java
===================================================================
--- branches/2.0-RC1/src/schmitzm/data/RasterCalculator.java	2009-12-09 14:46:29 UTC (rev 606)
+++ branches/2.0-RC1/src/schmitzm/data/RasterCalculator.java	2009-12-09 15:13:42 UTC (rev 607)
@@ -38,6 +38,9 @@
  * @version 1.0
  */
 public class RasterCalculator {
+  /** Instanz des Parsers. */
+  public static final RasterOperationTreeParser RASTER_CALC_PARSER = new RasterOperationTreeParser();
+
   /////////////////////////////////////////////////////////////////////
   /////////////////////   FORMEL AUSFUEHREN   /////////////////////////
   /////////////////////////////////////////////////////////////////////
@@ -54,7 +57,7 @@
    * @see RasterOperationTreeParser
    */
   public static void calculate(String rule, ReadableGrid[] inRaster, RasterFilter[] inFilter, WritableGrid outRaster ) {
-    RasterOperationTree opTree = new RasterOperationTreeParser().parse(rule);
+    RasterOperationTree opTree = RASTER_CALC_PARSER.parse(rule);
     if ( opTree == null )
       return;
 
@@ -104,6 +107,6 @@
    * @exception IllegalArgumentException bei einem Fehler
    */
   public static void checkRuleAndError(String rule) {
-    new RasterOperationTreeParser().parse(rule);
+    RASTER_CALC_PARSER.parse(rule);
   }
 }

Modified: branches/2.0-RC1/src/schmitzm/data/RasterOperationTreeParser.java
===================================================================
--- branches/2.0-RC1/src/schmitzm/data/RasterOperationTreeParser.java	2009-12-09 14:46:29 UTC (rev 606)
+++ branches/2.0-RC1/src/schmitzm/data/RasterOperationTreeParser.java	2009-12-09 15:13:42 UTC (rev 607)
@@ -118,5 +118,42 @@
     pushbackWithWSToken();
     return super.parseLiteral();
   }
+  
+  ////////////////////////////////////////////////////////////////
+  /////////////////   ParserOperatorsHints   /////////////////////
+  ////////////////////////////////////////////////////////////////
+  /**
+   * Initialises the list of available operators.
+   * @see #getOperators()
+   * @see #avOperators
+   */
+  @Override
+  protected void initOperatorList() {
+    super.initOperatorList();
+    // Zur Verfuegung stehende Operatoren erweitern
+    avOperators.add("X");           
+    avOperators.add("Y");           
+    avOperators.add("NoData");   
+    avOperators.add("isNoData");   
+    
+    // Keys fuer Lokalisation neu aufbauen
+    initOperatorKeys();
+  }
+  
+  /**
+   * Liefert die Anzahl an geklammerten Parametern, die ein Operator hat.
+   * Erweitert die Methode der Oberklasse um den Operator {@code isNoData(.)}
+   * und die Filter-Referenz {@code F.}.
+   * @param op Operator
+   * @return 1 fuer {@code isNoData} und {@code F..}, sonst den Wert der {@code super}-Methode
+   */
+  @Override
+  public int getOperatorParameterCount(String op) {
+    // Funktionen mit einem geklammerten Parameter
+    if (op.equalsIgnoreCase("isNoData") || op.charAt(0) == 'F')
+      return 1;
+    return super.getOperatorParameterCount(op);
+  }
+
 }
 

Modified: branches/2.0-RC1/src/schmitzm/geotools/GTUtil.java
===================================================================
--- branches/2.0-RC1/src/schmitzm/geotools/GTUtil.java	2009-12-09 14:46:29 UTC (rev 606)
+++ branches/2.0-RC1/src/schmitzm/geotools/GTUtil.java	2009-12-09 15:13:42 UTC (rev 607)
@@ -366,15 +366,15 @@
 
 		defaultRendererHints.put(StreamingRenderer.OPTIMIZE_FTS_RENDERING_KEY,
 				Boolean.TRUE);
+//
+//		if (renderer instanceof ShapefileRenderer) {
+//			defaultRendererHints.put(StreamingRenderer.MEMORY_PRE_LOADING_KEY,
+//					Boolean.TRUE);
+//		} else {
+//			defaultRendererHints.put(StreamingRenderer.MEMORY_PRE_LOADING_KEY,
+//					Boolean.FALSE);
+//		}
 
-		if (renderer instanceof ShapefileRenderer) {
-			defaultRendererHints.put(StreamingRenderer.MEMORY_PRE_LOADING_KEY,
-					Boolean.TRUE);
-		} else {
-			defaultRendererHints.put(StreamingRenderer.MEMORY_PRE_LOADING_KEY,
-					Boolean.FALSE);
-		}
-
 		defaultRendererHints.put(StreamingRenderer.OPTIMIZED_DATA_LOADING_KEY,
 				Boolean.TRUE);
 

Modified: branches/2.0-RC1/src/schmitzm/geotools/JTSUtil.java
===================================================================
--- branches/2.0-RC1/src/schmitzm/geotools/JTSUtil.java	2009-12-09 14:46:29 UTC (rev 606)
+++ branches/2.0-RC1/src/schmitzm/geotools/JTSUtil.java	2009-12-09 15:13:42 UTC (rev 607)
@@ -43,6 +43,7 @@
 
 import com.vividsolutions.jts.geom.Coordinate;
 import com.vividsolutions.jts.geom.Envelope;
+import com.vividsolutions.jts.geom.Geometry;
 
 /**
  * Diese Klasse enthaelt allgemeine Funktionen fuer die Arbeit mit den in
@@ -122,6 +123,8 @@
 	public static Envelope transformEnvelope(Envelope sourceEnv,
 			CoordinateReferenceSystem sourceCRS,
 			CoordinateReferenceSystem destCRS) {
+		
+		// Sometimes CRS only differ in their metadata... 
 		if (CRS.equalsIgnoreMetadata(sourceCRS, destCRS))
 			return new Envelope(sourceEnv);
 
@@ -151,7 +154,7 @@
 	}
 
 	/**
-	 * Transformiert eine Koordinate von einem CRS in ein anderes.
+	 * Transformiert eine Koordinate von einem CRS in ein anderes. 
 	 * 
 	 * @param sourceCoord
 	 *            Koordinate
@@ -183,7 +186,42 @@
 		}
 		return destCoord;
 	}
+	
+	/**
+	 * Transformiert eine JTS {@link Geometry} von einem CRS in ein anderes. <br>
+	 * Wenn beide CRS semantisch gleich sind wird das selbe Geometrieobect
+	 * zurueckgeliefert.
+	 * 
+	 * @param geometry
+	 *            Koordinate
+	 * @param srcCrs
+	 *            CRS von {@code sourceCoord}
+	 * @param destCrs
+	 *            CRS in das umgerechnet werden soll
+	 * @see CRS#findMathTransform(CoordinateReferenceSystem,CoordinateReferenceSystem)
+	 * @see JTS#transform(Coordinate, Coordinate, MathTransform)
+	 */
+	public static Geometry transformGeometry(Geometry geometry,
+			CoordinateReferenceSystem srcCrs, CoordinateReferenceSystem destCrs) {
+		
+		if (CRS.equalsIgnoreMetadata(srcCrs, destCrs)) return geometry; 
 
+		Geometry destGeometry = null;
+		MathTransform transform;
+		try {
+			transform = CRS.findMathTransform(srcCrs, destCrs, getLenient());
+			destGeometry = JTS.transform(geometry, transform);
+		} catch (FactoryException e) {
+			LOGGER.warn("CRS tranformation for JTS coordinate not successful",
+					e);
+		} catch (TransformException e) {
+			LOGGER.warn("CRS tranformation for JTS coordinate not successful",
+					e);
+		}
+		return destGeometry;
+	}
+
+
 	/**
 	 * Returns an {@link Envelope} that has the same aspect ratio as the given
 	 * rectangle

Modified: branches/2.0-RC1/src/schmitzm/geotools/feature/CQLFilterParser.java
===================================================================
--- branches/2.0-RC1/src/schmitzm/geotools/feature/CQLFilterParser.java	2009-12-09 14:46:29 UTC (rev 606)
+++ branches/2.0-RC1/src/schmitzm/geotools/feature/CQLFilterParser.java	2009-12-09 15:13:42 UTC (rev 607)
@@ -105,7 +105,8 @@
 		try {
 			return CQL.toFilter(rule);
 		} catch (CQLException err) {
-			throw new RuntimeException("Exceptino while parsing : " + rule, err);
+			LOGGER.error("Exception while parsing : " + rule, err);
+			return Filter.INCLUDE;
 		}
 	}
 
@@ -114,7 +115,7 @@
 	 */
 	@Override
 	public String getOperatorDescription(String operator) {
-		return SwingUtil.RESOURCE.getString("OperationTreePanel.OpTooltip."
+		return SwingUtil.RESOURCE.getString("CQLFitlerParser.OpTooltip."
 				+ opKeys.get(operator));
 	}
 
@@ -132,7 +133,7 @@
 	@Override
 	public String getOperatorTitle(String operator) {
 		return SwingUtil.RESOURCE.getString("CQLFitlerParser.OpDesc."
-				+ operator);
+				+ opKeys.get(operator));
 	}
 
 	/**

Modified: branches/2.0-RC1/src/schmitzm/geotools/feature/FeatureOperationTreeParser.java
===================================================================
--- branches/2.0-RC1/src/schmitzm/geotools/feature/FeatureOperationTreeParser.java	2009-12-09 14:46:29 UTC (rev 606)
+++ branches/2.0-RC1/src/schmitzm/geotools/feature/FeatureOperationTreeParser.java	2009-12-09 15:13:42 UTC (rev 607)
@@ -29,8 +29,6 @@
  ******************************************************************************/
 package schmitzm.geotools.feature;
 
-import java.util.Vector;
-
 import org.opengis.filter.Filter;
 
 import schmitzm.lang.tree.BinaryTreeNode;
@@ -100,30 +98,5 @@
       rule = "1";
     return new FeatureOperationTreeFilter(rule);
   }
-
- at Override
-public String getOperatorDescription(String operator) {
-	// TODO Auto-generated method stub
-	return null;
 }
 
- at Override
-public int getOperatorParameterCount(String operator) {
-	// TODO Auto-generated method stub
-	return 0;
-}
-
- at Override
-public String getOperatorTitle(String operator) {
-	// TODO Auto-generated method stub
-	return null;
-}
-
- at Override
-public Vector<String> getOperators() {
-	// TODO Auto-generated method stub
-	return null;
-}
-
-}
-

Modified: branches/2.0-RC1/src/schmitzm/geotools/feature/FilterParser.java
===================================================================
--- branches/2.0-RC1/src/schmitzm/geotools/feature/FilterParser.java	2009-12-09 14:46:29 UTC (rev 606)
+++ branches/2.0-RC1/src/schmitzm/geotools/feature/FilterParser.java	2009-12-09 15:13:42 UTC (rev 607)
@@ -30,8 +30,6 @@
 
 package schmitzm.geotools.feature;
 
-import java.util.Vector;
-
 import org.opengis.filter.Filter;
 
 import schmitzm.swing.ParserOperatorsHints;

Modified: branches/2.0-RC1/src/schmitzm/geotools/gui/FeatureCollectionFilterPanel.java
===================================================================
--- branches/2.0-RC1/src/schmitzm/geotools/gui/FeatureCollectionFilterPanel.java	2009-12-09 14:46:29 UTC (rev 606)
+++ branches/2.0-RC1/src/schmitzm/geotools/gui/FeatureCollectionFilterPanel.java	2009-12-09 15:13:42 UTC (rev 607)
@@ -296,9 +296,11 @@
 				protected void initGUI(boolean geomPreview) {
 					super.initGUI(geomPreview);
 
-					mapPane
-							.setToolTipText(GeotoolsGUIUtil
-									.R(FeatureCollectionFilterPanel.PREVIEW_MAPPANE_TOOLTIP));
+					if (geomPreview){
+						mapPane
+						.setToolTipText(GeotoolsGUIUtil
+								.R(FeatureCollectionFilterPanel.PREVIEW_MAPPANE_TOOLTIP));
+					}
 
 					// nur einzelne Zellen duerfen selektiert werden
 					featuresTable.setColumnSelectionAllowed(true);
@@ -356,6 +358,8 @@
 				 * feature collection (which is rendered in gray).
 				 */
 				protected void showFeaturesInMap() {
+					
+					if (geomPrev == false) return;
 
 					if (getPreviewPanel() == null)
 						return;

Modified: branches/2.0-RC1/src/schmitzm/geotools/gui/FeatureFilterPanel.java
===================================================================
--- branches/2.0-RC1/src/schmitzm/geotools/gui/FeatureFilterPanel.java	2009-12-09 14:46:29 UTC (rev 606)
+++ branches/2.0-RC1/src/schmitzm/geotools/gui/FeatureFilterPanel.java	2009-12-09 15:13:42 UTC (rev 607)
@@ -131,7 +131,7 @@
 	 *            Unterklasse erfolgen!)
 	 */
 	protected FeatureFilterPanel(FilterParser parser, SimpleFeatureType ftype, boolean initGUI) {
-		super(false);
+		super(parser,false);
 		setFilterParser(parser);
 
 		// Zusaetzliche Operatoren und Konstanten

Modified: branches/2.0-RC1/src/schmitzm/geotools/gui/FeatureLayerFilterDialog.java
===================================================================
--- branches/2.0-RC1/src/schmitzm/geotools/gui/FeatureLayerFilterDialog.java	2009-12-09 14:46:29 UTC (rev 606)
+++ branches/2.0-RC1/src/schmitzm/geotools/gui/FeatureLayerFilterDialog.java	2009-12-09 15:13:42 UTC (rev 607)
@@ -126,6 +126,7 @@
 			.getString(DIALOG_TITLE);
 	private SelectableXMapPane mapPane = null;
 	private MapLayer layer = null;
+	private final boolean geomPrev;
 
 	/**
 	 * Erzeugt einen neuen Dialog.
@@ -138,6 +139,7 @@
 	 * @param mapLayer
 	 *            MapLayer, aus dem die FeatureCollection stammt, auf der der
 	 *            Filter definiert wird
+	 * @param geomPrev if true, a geometry mappane will be created
 	 * @exception IOException
 	 *                falls beim Ermitteln der {@link FeatureCollection} aus dem
 	 *                Layer ein Fehler auftritt
@@ -148,8 +150,8 @@
 	 *         Kr&uuml;ger</a>
 	 */
 	public FeatureLayerFilterDialog(Window parent, SelectableXMapPane mapPane,
-			MapLayer mapLayer) {
-		this(parent, mapPane, mapLayer, true);
+			MapLayer mapLayer, boolean geomPrev) {
+		this(parent, mapPane, mapLayer, true, geomPrev);
 	}
 
 	/**
@@ -177,8 +179,9 @@
 	 *         Kr&uuml;ger</a>
 	 */
 	protected FeatureLayerFilterDialog(Component parent, SelectableXMapPane mapPane,
-			MapLayer mapLayer, boolean initGUI) {
+			MapLayer mapLayer, boolean initGUI, boolean geomPrev) {
 		super(SwingUtil.getParentWindow(parent));
+		this.geomPrev = geomPrev;
 		setModal(true);
 		if (mapLayer != null)
 			this.setTitle(frameTitle + " [" + mapLayer.getTitle() + "]");
@@ -224,6 +227,7 @@
 					final Filter fiterInAction = getMapLayer().getQuery()
 							.getFilter();
 
+					
 					if (getMapPane() != null
 							&& !fiterInAction.equals(newFilter)) {
 
@@ -231,7 +235,7 @@
 							FeatureCollection<SimpleFeatureType, SimpleFeature> fc = getFilterPanel()
 									.filterFeatureCollection();
 							FeatureSelectedEvent fse = new FeatureSelectedEvent(
-									getMapPane(), layer, fc.getBounds(), fc,
+									getMapPane(), layer, null, fc,  // SK, 26.11.2009 passing null as the bounds, because getBounds can be very expensive
 									FeatureLayerFilterDialog.this);
 							getMapPane().fireMapPaneEvent(fse);
 						} catch (Exception err) {
@@ -267,7 +271,7 @@
 
 				filterPanel = new FeatureCollectionFilterPanel(FILTER_PARSER,
 						(FeatureCollection<SimpleFeatureType, SimpleFeature>) layer
-								.getFeatureSource().getFeatures(), true, null) {
+								.getFeatureSource().getFeatures(), geomPrev, null) {
 					@Override
 					protected void resetComponentsAfterTest(Throwable err) {
 						super.resetComponentsAfterTest(err);

Modified: branches/2.0-RC1/src/schmitzm/geotools/gui/FeatureTablePane.java
===================================================================
--- branches/2.0-RC1/src/schmitzm/geotools/gui/FeatureTablePane.java	2009-12-09 14:46:29 UTC (rev 606)
+++ branches/2.0-RC1/src/schmitzm/geotools/gui/FeatureTablePane.java	2009-12-09 15:13:42 UTC (rev 607)
@@ -45,21 +45,16 @@
 
 import org.apache.log4j.Logger;
 import org.geotools.feature.FeatureCollection;
-import org.geotools.map.DefaultMapContext;
 import org.geotools.map.DefaultMapLayer;
 import org.geotools.styling.Style;
-import org.geotools.swing.JMapPane;
 import org.opengis.feature.simple.SimpleFeature;
 import org.opengis.feature.simple.SimpleFeatureType;
 
-import schmitzm.geotools.GTUtil;
 import schmitzm.geotools.feature.AttributeTypeFilter;
-import schmitzm.geotools.feature.FeatureUtil;
 import schmitzm.geotools.styling.StylingUtil;
 import schmitzm.swing.JPanel;
 import schmitzm.swing.SortableJTable;
 import schmitzm.swing.SwingUtil;
-import skrueger.geotools.XMapPane;
 
 /**
  * Diese Komponente stellt eine Tabelle dar, in der die Attribute einer

Modified: branches/2.0-RC1/src/schmitzm/geotools/gui/GeoMapPane.java
===================================================================
--- branches/2.0-RC1/src/schmitzm/geotools/gui/GeoMapPane.java	2009-12-09 14:46:29 UTC (rev 606)
+++ branches/2.0-RC1/src/schmitzm/geotools/gui/GeoMapPane.java	2009-12-09 15:13:42 UTC (rev 607)
@@ -37,17 +37,14 @@
 import java.awt.Insets;
 import java.util.HashMap;
 
-import javax.swing.BorderFactory;
-
 import org.geotools.map.MapContext;
-import org.geotools.renderer.GTRenderer;
 import org.geotools.renderer.lite.StreamingRenderer;
 import org.geotools.renderer.shape.ShapefileRenderer;
 
 import schmitzm.geotools.GTUtil;
-import schmitzm.geotools.map.event.MapPaneEvent;
 import schmitzm.geotools.map.event.JMapPaneListener;
 import schmitzm.geotools.map.event.MapAreaChangedEvent;
+import schmitzm.geotools.map.event.MapPaneEvent;
 import schmitzm.geotools.map.event.ScaleChangedEvent;
 import schmitzm.swing.JPanel;
 import schmitzm.swing.SwingUtil;

Modified: branches/2.0-RC1/src/schmitzm/geotools/gui/GridPanel.java
===================================================================
--- branches/2.0-RC1/src/schmitzm/geotools/gui/GridPanel.java	2009-12-09 14:46:29 UTC (rev 606)
+++ branches/2.0-RC1/src/schmitzm/geotools/gui/GridPanel.java	2009-12-09 15:13:42 UTC (rev 607)
@@ -30,7 +30,6 @@
 package schmitzm.geotools.gui;
 
 import java.awt.Color;
-import java.awt.FontMetrics;
 import java.awt.Graphics;
 import java.awt.Graphics2D;
 import java.awt.RenderingHints;

Modified: branches/2.0-RC1/src/schmitzm/geotools/gui/GridPanelFormatter_LatLon1.java
===================================================================
--- branches/2.0-RC1/src/schmitzm/geotools/gui/GridPanelFormatter_LatLon1.java	2009-12-09 14:46:29 UTC (rev 606)
+++ branches/2.0-RC1/src/schmitzm/geotools/gui/GridPanelFormatter_LatLon1.java	2009-12-09 15:13:42 UTC (rev 607)
@@ -32,10 +32,7 @@
 
 import java.awt.Font;
 import java.text.DecimalFormat;
-import java.text.NumberFormat;
 
-import javax.swing.text.NumberFormatter;
-
 import org.geotools.referencing.crs.DefaultGeographicCRS;
 import org.opengis.referencing.crs.CoordinateReferenceSystem;
 

Modified: branches/2.0-RC1/src/schmitzm/geotools/gui/JEditorPane.java
===================================================================
--- branches/2.0-RC1/src/schmitzm/geotools/gui/JEditorPane.java	2009-12-09 14:46:29 UTC (rev 606)
+++ branches/2.0-RC1/src/schmitzm/geotools/gui/JEditorPane.java	2009-12-09 15:13:42 UTC (rev 607)
@@ -48,7 +48,6 @@
 import org.geotools.map.DefaultMapLayer;
 import org.geotools.map.MapContext;
 import org.geotools.map.MapLayer;
-import org.geotools.referencing.crs.DefaultGeographicCRS;
 import org.geotools.renderer.GTRenderer;
 import org.geotools.styling.Style;
 import org.opengis.feature.simple.SimpleFeature;

Modified: branches/2.0-RC1/src/schmitzm/geotools/gui/JEditorToolBar.java
===================================================================
--- branches/2.0-RC1/src/schmitzm/geotools/gui/JEditorToolBar.java	2009-12-09 14:46:29 UTC (rev 606)
+++ branches/2.0-RC1/src/schmitzm/geotools/gui/JEditorToolBar.java	2009-12-09 15:13:42 UTC (rev 607)
@@ -45,10 +45,10 @@
 
 import schmitzm.geotools.gui.JEditorPane.EditorMode;
 import schmitzm.geotools.map.event.JEditorPaneEvent;
-import schmitzm.geotools.map.event.MapPaneEvent;
 import schmitzm.geotools.map.event.JMapPaneListener;
 import schmitzm.geotools.map.event.LayerEditCanceledEvent;
 import schmitzm.geotools.map.event.LayerEditFinishedEvent;
+import schmitzm.geotools.map.event.MapPaneEvent;
 import schmitzm.swing.ExceptionDialog;
 import schmitzm.swing.ManualInputOption;
 import schmitzm.swing.MultipleOptionPane;

Modified: branches/2.0-RC1/src/schmitzm/geotools/gui/LayeredMapFrame.java
===================================================================
--- branches/2.0-RC1/src/schmitzm/geotools/gui/LayeredMapFrame.java	2009-12-09 14:46:29 UTC (rev 606)
+++ branches/2.0-RC1/src/schmitzm/geotools/gui/LayeredMapFrame.java	2009-12-09 15:13:42 UTC (rev 607)
@@ -48,8 +48,8 @@
 
 import schmitzm.geotools.map.event.FeatureSelectedEvent;
 import schmitzm.geotools.map.event.GridCoverageSelectedEvent;
+import schmitzm.geotools.map.event.JMapPaneListener;
 import schmitzm.geotools.map.event.MapPaneEvent;
-import schmitzm.geotools.map.event.JMapPaneListener;
 import schmitzm.swing.SelectionInputOption;
 import schmitzm.swing.SwingUtil;
 

Modified: branches/2.0-RC1/src/schmitzm/geotools/gui/MapContextControlPane.java
===================================================================
--- branches/2.0-RC1/src/schmitzm/geotools/gui/MapContextControlPane.java	2009-12-09 14:46:29 UTC (rev 606)
+++ branches/2.0-RC1/src/schmitzm/geotools/gui/MapContextControlPane.java	2009-12-09 15:13:42 UTC (rev 607)
@@ -426,7 +426,7 @@
 			if (filterLayer.isEnabled())
 				try {
 					filterDialog = new FeatureLayerFilterDialog(null, mapPane,
-							layer);
+							layer, true);
 					filterDialog.setModal(false);
 				} catch (Exception err) {
 					LangUtil

Modified: branches/2.0-RC1/src/schmitzm/geotools/gui/SelectableFeatureTablePane.java
===================================================================
--- branches/2.0-RC1/src/schmitzm/geotools/gui/SelectableFeatureTablePane.java	2009-12-09 14:46:29 UTC (rev 606)
+++ branches/2.0-RC1/src/schmitzm/geotools/gui/SelectableFeatureTablePane.java	2009-12-09 15:13:42 UTC (rev 607)
@@ -47,7 +47,6 @@
 import javax.swing.JTable;
 import javax.swing.JToolBar;
 import javax.swing.SortOrder;
-import javax.swing.SwingUtilities;
 import javax.swing.RowSorter.SortKey;
 import javax.swing.event.ListSelectionEvent;
 import javax.swing.event.ListSelectionListener;

Modified: branches/2.0-RC1/src/schmitzm/geotools/gui/SelectableXMapPane.java
===================================================================
--- branches/2.0-RC1/src/schmitzm/geotools/gui/SelectableXMapPane.java	2009-12-09 14:46:29 UTC (rev 606)
+++ branches/2.0-RC1/src/schmitzm/geotools/gui/SelectableXMapPane.java	2009-12-09 15:13:42 UTC (rev 607)
@@ -43,8 +43,6 @@
 import java.util.Hashtable;
 import java.util.Map;
 
-import javax.swing.JList;
-
 import org.apache.log4j.Logger;
 import org.geotools.coverage.grid.GeneralGridEnvelope;
 import org.geotools.coverage.grid.GridCoverage2D;
@@ -53,7 +51,6 @@
 import org.geotools.coverage.grid.io.AbstractGridFormat;
 import org.geotools.data.FeatureSource;
 import org.geotools.data.memory.MemoryFeatureCollection;
-import org.geotools.factory.GeoTools;
 import org.geotools.feature.FeatureCollection;
 import org.geotools.filter.GeometryFilterImpl;
 import org.geotools.geometry.GeneralEnvelope;
@@ -67,7 +64,6 @@
 import org.geotools.renderer.GTRenderer;
 import org.geotools.renderer.lite.StreamingRenderer;
 import org.geotools.resources.image.ImageUtilities;
-import org.geotools.swing.utils.MapLayerUtils;
 import org.opengis.coverage.CannotEvaluateException;
 import org.opengis.feature.simple.SimpleFeature;
 import org.opengis.feature.simple.SimpleFeatureType;
@@ -370,162 +366,7 @@
 	}
 
 
-
 	/**
-	 * Aktiviert oder deaktiviert das AntiAliasing for diese
-	 * {@link SelectableXMapPane}. AntiALiasing ist besonders fuer
-	 * Textbeschriftung sehr schoen, verbraucht aber auch mehr Performance.
-	 * 
-	 * @author <a href="mailto:skpublic at wikisquare.de">Stefan Alfons
-	 *         Kr&uuml;ger</a>
-	 */
-	public void setAntiAliasing(final boolean aa) {
-		// LOGGER.info("Setting AntiAliasing for this JMapPane to " + aa);
-		RenderingHints java2DHints = super.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);
-		super.setJava2dHints(java2DHints);
-	}
-
-	/**
-	 * Setzt den Kartenausschnitt auf die Ausdehnung eines bestimmten Layers.
-	 * Macht nichts, wenn {@code null} uebergeben wird.
-	 * 
-	 * <br>
-	 * 
-	 * @param layer
-	 *            ein Layer
-	 */
-	public void zoomToLayer(MapLayer layer) {
-		if (layer == null)
-			return;
-		try {
-
-			// BB umrechnen von Layer-CRS in Map-CRS
-			final CoordinateReferenceSystem targetCRS = getMapContext()
-					.getCoordinateReferenceSystem();
-			final CoordinateReferenceSystem sourceCRS = layer
-					.getFeatureSource().getSchema()
-					.getCoordinateReferenceSystem();
-
-			Envelope mapAreaNew;
-			if (!CRS.equalsIgnoreMetadata(sourceCRS, targetCRS)) {
-				mapAreaNew = JTSUtil.transformEnvelope(layer.getFeatureSource()
-						.getBounds(), sourceCRS, targetCRS);
-			} else {
-				try {
-					mapAreaNew = layer.getFeatureSource().getBounds();
-				} catch (java.lang.IllegalArgumentException e) {
-					LOGGER.error("Can't calc layers bounds...", e);
-					mapAreaNew = null;
-
-					/**
-					 * 
-					 23.10.2009 11:20:50
-					 * org.geotools.data.shapefile.shp.PolygonHandler read
-					 * WARNUNG: only one hole in this polygon record ERROR
-					 * JMapPane zoomToLayer Zoom to layer did not terminate
-					 * correctly java.lang.IllegalArgumentException: Points of
-					 * LinearRing do not form a closed linestring at
-					 * com.vividsolutions
-					 * .jts.geom.LinearRing.validateConstruction
-					 * (LinearRing.java:105) at
-					 * com.vividsolutions.jts.geom.LinearRing
-					 * .<init>(LinearRing.java:100) at
-					 * com.vividsolutions.jts.geom
-					 * .GeometryFactory.createLinearRing
-					 * (GeometryFactory.java:339) at
-					 * org.geotools.data.shapefile.
-					 * shp.PolygonHandler.read(PolygonHandler.java:188) at
-					 * org.geotools
-					 * .data.shapefile.shp.ShapefileReader$Record.shape
-					 * (ShapefileReader.java:106) at
-					 * org.geotools.data.shapefile.
-					 * ShapefileAttributeReader.next(
-					 * ShapefileAttributeReader.java:157) at
-					 * org.geotools.data.shapefile
-					 * .indexed.IndexedShapefileAttributeReader
-					 * .next(IndexedShapefileAttributeReader.java:122) at
-					 * org.geotools
-					 * .data.FIDFeatureReader.next(FIDFeatureReader.java:96) at
-					 * org.geotools.data.FIDFeatureReader.next(FIDFeatureReader.
-					 * java:55) at org.geotools.data.MaxFeatureReader.next(
-					 * MaxFeatureReader.java:61) at
-					 * org.geotools.data.MaxFeatureReader
-					 * .next(MaxFeatureReader.java:61)
-					 **/
-				}
-			}
-
-			// Kartenbereich um 10% vergroessern, damit z.B. auch ein
-			// Punkt-Layer,
-			// welches nur aus 2 Punnkten besteht, sichtbar ist (Punkte liegen
-			// sonst
-			// genau auf dem Rand der angezeigten Flaeche)
-
-			if (mapAreaNew != null) {
-				mapAreaNew.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.error("Zoom to layer did not terminate correctly", err);
-		}
-	}
-
-	/**
-	 * Zooms the {@link SelectableXMapPane} to the {@link Envelope} of a layer.
-	 * 
-	 * <br>
-	 * A refresh of the map is not done automatically
-	 * 
-	 * @param index
-	 *            Index of the {@link MapLayer} in the {@link MapContext} (from
-	 *            back to top)
-	 * 
-	 * @author <a href="mailto:skpublic at wikisquare.de">Stefan Alfons
-	 *         Kr&uuml;ger</a>
-	 */
-	public void zoomToLayer(int index) {
-		final MapContext context = getMapContext();
-		if (context != null)
-			zoomToLayer(context.getLayer(index));
-	}
-
-	/**
-	 * Zooms the {@link SelectableXMapPane} to the {@link Envelope} of the
-	 * selected layer. The layer is selected by the idx, counting from front to
-	 * back, like humans would expect in a {@link JList}
-	 * 
-	 * <br>
-	 * A refresh of the map is not done automatically
-	 * 
-	 * 
-	 * 
-	 * @param index
-	 *            Reverse index of the {@link MapLayer} in the
-	 *            {@link MapContext}
-	 * 
-	 * @author <a href="mailto:skpublic at wikisquare.de">Stefan Alfons
-	 *         Kr&uuml;ger</a>
-	 */
-	public void zoomToLayerIdxReverse(int index) {
-		zoomToLayer(getMapContext().getLayerCount() - 1 - index);
-	}
-
-	/**
 	 * Liefert die Anzahl der Einheiten, die ein Bildschirm-Pixel darstellt. Die
 	 * Einheit ist die Grundeinheit des CRS
 	 */
@@ -656,7 +497,7 @@
 	 *         Kr&uuml;ger</a>
 	 */
 	@Override
-	public boolean setMapArea(Envelope newMapArea) {
+	public boolean setMapArea(ReferencedEnvelope newMapArea) {
 		double oldScale = getScale();
 
 		boolean b = super.setMapArea(newMapArea);

Modified: branches/2.0-RC1/src/schmitzm/geotools/io/GeoExportUtil.java
===================================================================
--- branches/2.0-RC1/src/schmitzm/geotools/io/GeoExportUtil.java	2009-12-09 14:46:29 UTC (rev 606)
+++ branches/2.0-RC1/src/schmitzm/geotools/io/GeoExportUtil.java	2009-12-09 15:13:42 UTC (rev 607)
@@ -58,18 +58,19 @@
 /**
  * In dieser Klasse sind Funktionen zum Datenexport von Geo-Daten
  * zusammengefasst.
- * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
+ * 
+ * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a>
+ *         (University of Bonn/Germany)
  * @version 1.0
  */
 public class GeoExportUtil {
-  /**
-   * Diese Methode exportiert eine {@link org.geotools.feature.FeatureCollection}
-   * in das ShapeFile-Format
-   * (<code><i>name</i>.shp <i>name</i>.shx <i>name</i>.dbf</code>).<br>
-   * Baut auf folgenden Geotools-Klassen auf:
-   * <code>
-   * <ul>
-   * <li>{@link ShapefileDataStore       org.geotools.data.shapefile.ShapefileDataStore}</li>
+	/**
+	 * Diese Methode exportiert eine
+	 * {@link org.geotools.feature.FeatureCollection} in das ShapeFile-Format (
+	 * <code><i>name</i>.shp <i>name</i>.shx <i>name</i>.dbf</code>).<br>
+	 * Baut auf folgenden Geotools-Klassen auf: <code>
+	 * <ul>
+	 * <li>{@link ShapefileDataStore       org.geotools.data.shapefile.ShapefileDataStore}</li>
    * <li>{@link FeatureSource            org.geotools.data.FeatureSource}</li>
    * <li>{@link FeatureStore             org.geotools.data.FeatureStore}</li>
    * <li>{@link Transaction              org.geotools.data.Transaction}</li>
@@ -77,171 +78,206 @@
    * <li>{@link FeatureCollectionReader  schmitzm.geotools.feature.FeatureCollectionReader}</li>
    * </ul>
    * </code>
-   * @param  fc      zu exportierende FeatureCollection
-   * @param  outFile Dateiname (Basisname)
-   * @throws java.lang.Exception bei irgendeinem Fehler
-   */
-  public static void writeFeaturesToShapeFile(FeatureCollection<SimpleFeatureType, SimpleFeature> fc, File outFile) throws Exception {
-//      FeatureCollectionReader featureReader = new FeatureCollectionReader(fc);
+	 * 
+	 * @param fc
+	 *            zu exportierende FeatureCollection
+	 * @param outFile
+	 *            Dateiname (Basisname)
+	 * @throws java.lang.Exception
+	 *             bei irgendeinem Fehler
+	 */
+	public static void writeFeaturesToShapeFile(
+			FeatureCollection<SimpleFeatureType, SimpleFeature> fc, File outFile)
+			throws Exception {
+		// FeatureCollectionReader featureReader = new
+		// FeatureCollectionReader(fc);
 
-      // DataStore fuer Ausgabe-Datei oeffnen
-      ShapefileDataStore shpStore = new ShapefileDataStore(outFile.toURI().toURL());
-//      shpStore.createSchema(featureReader.getFeatureType());
-      shpStore.createSchema(fc.getSchema());
-      // FeatureStore aus dem ShapeFile-DataStore ermitteln
-      FeatureSource<SimpleFeatureType, SimpleFeature> source       = shpStore.getFeatureSource();
-      
-      // TODO 26 @Martin?! Du hattest hier gecastet... ob das so noch geht?! 
-      // FeatureStore  featureStore = (FeatureStore)source;
-      FeatureStore<SimpleFeatureType, SimpleFeature>  featureStore = (FeatureStore<SimpleFeatureType, SimpleFeature>)source;
-      
-      
-      // Features schreiben
-      Transaction transaction = featureStore.getTransaction();
-      featureStore.addFeatures( fc );
-      transaction.commit();
-      transaction.close();
-  }
+		// DataStore fuer Ausgabe-Datei oeffnen
+		ShapefileDataStore shpStore = new ShapefileDataStore(outFile.toURI()
+				.toURL());
+		// shpStore.createSchema(featureReader.getFeatureType());
+		shpStore.createSchema(fc.getSchema());
+		// FeatureStore aus dem ShapeFile-DataStore ermitteln
+		FeatureSource<SimpleFeatureType, SimpleFeature> source = shpStore
+				.getFeatureSource();
 
+		// TODO 26 @Martin?! Du hattest hier gecastet... ob das so noch geht?!
+		// FeatureStore featureStore = (FeatureStore)source;
+		FeatureStore<SimpleFeatureType, SimpleFeature> featureStore = (FeatureStore<SimpleFeatureType, SimpleFeature>) source;
 
-  /**
-   * Diese Methode exportiert ein Raster in eine Datei im ArcInfoASCII-Grid-Format.<br>
-   * Baut auf folgenden Geotools-Klassen auf:
-   * <code>
-   * <ul>
-   *   <li>{@link org.geotools.coverage.grid.GridCoverage2D}</li>
+		// Features schreiben
+		Transaction transaction = featureStore.getTransaction();
+		featureStore.addFeatures(fc);
+		transaction.commit();
+		transaction.close();
+	}
+
+	/**
+	 * Diese Methode exportiert ein Raster in eine Datei im
+	 * ArcInfoASCII-Grid-Format.<br>
+	 * Baut auf folgenden Geotools-Klassen auf: <code>
+	 * <ul>
+	 *   <li>{@link org.geotools.coverage.grid.GridCoverage2D}</li>
    *   <li>{@link org.geotools.gce.arcgrid.ArcGridWriter}</li>
    * </ul>
    * </code>
-   * @param grid    zu exportierendes Grid
-   * @param outFile Ausgabe-Datei
-   * @throws java.lang.Exception bei irgendeinem Fehler
-   */
-  public static void writeGridToArcInfoASCII(GridCoverage2D grid, File outFile) throws Exception {
-	  
-	ArcGridWriter arcGridWriter = new ArcGridWriter(outFile);
-	GeneralParameterValue[] parameters = new GeneralParameterValue[] {};
-	arcGridWriter.write(grid, parameters);
-	arcGridWriter.dispose();
-	
-//    Raster raster = grid.getRenderedImage().getData();
-//    Rectangle2D rect = grid.getEnvelope2D();
-//    // Geo-Koordinaten
-//    double x = rect.getX();
-//    double y = rect.getY();
-//    // Zellenbreite
-//    double cellsize = rect.getWidth() / raster.getWidth();
-//    // Exportieren
-////    throw new UnsupportedOperationException("GeoExportUtil.writeGridToArcInfoASCII(.) has still to be breaked from ArcGridRaster dependency!");
-//    ArcGridRaster writer = new ArcGridRaster(new PrintWriter( new FileOutputStream(outFile) ));
-//    writer.writeRaster(raster, x, y, cellsize, false);
-	
-	
-	
-	// Die peojektion wird vom ArcGridWriter automaitsch mit-geschrieben!
-//    // Projektion schreiben
-//    writeProjectionFile( grid.getCoordinateReferenceSystem(),
-//                         IOUtil.changeFileExt(outFile,"prj"));
-  }
+	 * 
+	 * @param grid
+	 *            zu exportierendes Grid
+	 * @param outFile
+	 *            Ausgabe-Datei
+	 * @throws java.lang.Exception
+	 *             bei irgendeinem Fehler
+	 */
+	public static void writeGridToArcInfoASCII(GridCoverage2D grid, File outFile)
+			throws Exception {
 
-  /**
-   * Diese Methode exportiert ein Raster in eine Datei im GeoTiff-Format.
-   * Daneben wird ein entsprechendes World-File (.tfw) erstellt, in dem die
-   * Georeferenz und Aufloesung des TIF hinterlegt wird.
-   * @param grid   zu exportierendes Grid
-   * @param output Ausgabe-Datei
-   * @throws java.lang.Exception bei irgendeinem Fehler
-   */
-  public static void writeGridToGeoTiff(GridCoverage2D grid, File output) throws Exception {
-//    for (int i=0; i<ImageIO.getWriterFormatNames().length;i++)
-//      System.out.println(ImageIO.getWriterFormatNames()[i]);
+		ArcGridWriter arcGridWriter = new ArcGridWriter(outFile);
+		GeneralParameterValue[] parameters = new GeneralParameterValue[] {};
+		arcGridWriter.write(grid, parameters);
+		arcGridWriter.dispose();
 
-    // GeoTiff-File schreiben
-    ImageIO.write( grid.getRenderedImage(), "tif", output );
-    // World-File schreiben
-    writeWorldFile( grid.getRenderedImage().getWidth(),
-                    grid.getRenderedImage().getHeight(),
-                    grid.getEnvelope2D(),
-                    IOUtil.changeFileExt(output,"tfw"));
-    // Projektion schreiben
-    writeProjectionFile( grid.getCoordinateReferenceSystem(),
-                         IOUtil.changeFileExt(output,"prj"));
-  }
+		// Raster raster = grid.getRenderedImage().getData();
+		// Rectangle2D rect = grid.getEnvelope2D();
+		// // Geo-Koordinaten
+		// double x = rect.getX();
+		// double y = rect.getY();
+		// // Zellenbreite
+		// double cellsize = rect.getWidth() / raster.getWidth();
+		// // Exportieren
+		// // throw new
+		// UnsupportedOperationException("GeoExportUtil.writeGridToArcInfoASCII(.) has still to be breaked from ArcGridRaster dependency!");
+		// ArcGridRaster writer = new ArcGridRaster(new PrintWriter( new
+		// FileOutputStream(outFile) ));
+		// writer.writeRaster(raster, x, y, cellsize, false);
 
-  /**
-   * Diese Methode exportiert ein Raster in eine Datei im ArcInfoASCII-Grid-Format.
-   * @param grid    zu exportierendes Grid
-   * @param outFile Ausgabe-Datei
-   * @throws java.lang.Exception bei irgendeinem Fehler
-   */
-  public static void writeGridRasterToArcInfoASCII(WritableGridRaster grid, File outFile) throws Exception {
-    writeGridToArcInfoASCII(
-        GridUtil.convertToGridCoverage2D(grid),
-        outFile
-    );
-  }
+		// Die peojektion wird vom ArcGridWriter automaitsch mit-geschrieben!
+		// // Projektion schreiben
+		// writeProjectionFile( grid.getCoordinateReferenceSystem(),
+		// IOUtil.changeFileExt(outFile,"prj"));
+	}
 
-  /**
-   * Diese Methode exportiert ein Raster in eine Datei im GeoTiff-Format.
-   * Daneben wird ein entsprechendes World-File (.tfw) erstellt, in dem die
-   * Georeferenz und Aufloesung des TIF hinterlegt wird.
-   * @param grid   zu exportierendes Grid
-   * @param output Ausgabe-Datei
-   * @throws java.lang.Exception bei irgendeinem Fehler
-   */
-  public static void writeGridRasterToGeoTiff(WritableGridRaster grid, File output) throws Exception {
-//    for (int i=0; i<ImageIO.getWriterFormatNames().length;i++)
-//      System.out.println(ImageIO.getWriterFormatNames()[i]);
+	/**
+	 * Diese Methode exportiert ein Raster in eine Datei im GeoTiff-Format.
+	 * Daneben wird ein entsprechendes World-File (.tfw) erstellt, in dem die
+	 * Georeferenz und Aufloesung des TIF hinterlegt wird.
+	 * 
+	 * @param grid
+	 *            zu exportierendes Grid
+	 * @param output
+	 *            Ausgabe-Datei
+	 * @throws java.lang.Exception
+	 *             bei irgendeinem Fehler
+	 */
+	public static void writeGridToGeoTiff(GridCoverage2D grid, File output)
+			throws Exception {
+		// for (int i=0; i<ImageIO.getWriterFormatNames().length;i++)
+		// System.out.println(ImageIO.getWriterFormatNames()[i]);
 
-    // GeoTiff-File schreiben
-    BufferedImage im = new BufferedImage(grid.getWidth(), grid.getHeight(),BufferedImage.TYPE_INT_RGB);
-    im.setData(grid);
-    ImageIO.write( im, "tif", output );
-    // World-File schreiben
-    writeWorldFile(grid.getWidth(), grid.getHeight(), grid.getEnvelope(),IOUtil.changeFileExt(output,"tfw"));
-    // Projektion schreiben
-    writeProjectionFile( grid.getCoordinateReferenceSystem(),
-                         IOUtil.changeFileExt(output,"prj"));
-  }
+		// GeoTiff-File schreiben
+		ImageIO.write(grid.getRenderedImage(), "tif", output);
+		// World-File schreiben
+		writeWorldFile(grid.getRenderedImage().getWidth(), grid
+				.getRenderedImage().getHeight(), grid.getEnvelope2D(), IOUtil
+				.changeFileExt(output, "tfw"));
+		// Projektion schreiben
+		writeProjectionFile(grid.getCoordinateReferenceSystem(), IOUtil
+				.changeFileExt(output, "prj"));
+	}
 
-  /**
-   * Schreibt ein World-File (.tfw) fuer ein Grid. Dabei handelt es sich um
-   * eine zeilenweise ASCII-Datei:<br>
-   * <ol>
-   *    <li>Zellengroesse in X-Richtung (in Meter)</li>
-    *   <li>Koeffizient fuer Rotation in Y-Richtung (<b>wird mit 0.0 befuellt</b>!)</li>
-    *   <li>Koeffizient fuer Rotation in X-Richtung (<b>wird mit 0.0 befuellt</b>!)</li>
-    *   <li>negative Zellengroesse in Y-Richtung (in Meter)</li>
-    *   <li>Horizontale Geo-Referenz (Longitude) der nord-westlichen Ecke</li>
-    *   <li>Vertikale Geo-Referenz (Latitude) der nord-westlichen Ecke</li>
-   * </ol>
-   * @param rasterWidth Breite des Rasters (in Zellen)
-   * @param rasterHeight Hoehe des Rasters (in Zellen)
-   * @param envelope Geo-Referenz des Rasters (Position und Ausdehnung)
-   * @param output Datei in die das World-File geschrieben wird
-   * @exception IOException falls die Datei nicht geschrieben werden kann
-   */
-  public static void writeWorldFile(int rasterWidth, int rasterHeight, Rectangle2D envelope, File output) throws IOException {
-    PrintWriter out = new PrintWriter(output);
+	/**
+	 * Diese Methode exportiert ein Raster in eine Datei im
+	 * ArcInfoASCII-Grid-Format.
+	 * 
+	 * @param grid
+	 *            zu exportierendes Grid
+	 * @param outFile
+	 *            Ausgabe-Datei
+	 * @throws java.lang.Exception
+	 *             bei irgendeinem Fehler
+	 */
+	public static void writeGridRasterToArcInfoASCII(WritableGridRaster grid,
+			File outFile) throws Exception {
+		writeGridToArcInfoASCII(GridUtil.convertToGridCoverage2D(grid), outFile);
+	}
 
-    // Zeile 1: Zellengroesse in Meter
-    out.println( envelope.getWidth() / rasterWidth );
-    // Zeile 2: Rotation in Y-Richtung
-    out.println( "0.0" );
-    // Zeile 3: Rotation in X-Richtung
-    out.println( "0.0" );
-    // Zeile 4: ?
-    out.println( - envelope.getHeight() / rasterHeight );
-    // Zeile 5: X-Georeferenz (Longitude) WESTEN
-    out.println( envelope.getX() );
-    // Zeile 6: Y-Georeferenz (Latitude) NORDEN (Im Envelope steht SUEDEN!!)
-    out.println( envelope.getY() + envelope.getHeight() );
+	/**
+	 * Diese Methode exportiert ein Raster in eine Datei im GeoTiff-Format.
+	 * Daneben wird ein entsprechendes World-File (.tfw) erstellt, in dem die
+	 * Georeferenz und Aufloesung des TIF hinterlegt wird.
+	 * 
+	 * @param grid
+	 *            zu exportierendes Grid
+	 * @param output
+	 *            Ausgabe-Datei
+	 * @throws java.lang.Exception
+	 *             bei irgendeinem Fehler
+	 */
+	public static void writeGridRasterToGeoTiff(WritableGridRaster grid,
+			File output) throws Exception {
+		// for (int i=0; i<ImageIO.getWriterFormatNames().length;i++)
+		// System.out.println(ImageIO.getWriterFormatNames()[i]);
 
-    out.flush();
-    out.close();
-  }
+		// GeoTiff-File schreiben
+		BufferedImage im = new BufferedImage(grid.getWidth(), grid.getHeight(),
+				BufferedImage.TYPE_INT_RGB);
+		im.setData(grid);
+		ImageIO.write(im, "tif", output);
+		// World-File schreiben
+		writeWorldFile(grid.getWidth(), grid.getHeight(), grid.getEnvelope(),
+				IOUtil.changeFileExt(output, "tfw"));
+		// Projektion schreiben
+		writeProjectionFile(grid.getCoordinateReferenceSystem(), IOUtil
+				.changeFileExt(output, "prj"));
+	}
 
-  /**
+	/**
+	 * Schreibt ein World-File (.tfw) fuer ein Grid. Dabei handelt es sich um
+	 * eine zeilenweise ASCII-Datei:<br>
+	 * <ol>
+	 * <li>Zellengroesse in X-Richtung (in Meter)</li>
+	 * <li>Koeffizient fuer Rotation in Y-Richtung (<b>wird mit 0.0
+	 * befuellt</b>!)</li>
+	 * <li>Koeffizient fuer Rotation in X-Richtung (<b>wird mit 0.0
+	 * befuellt</b>!)</li>
+	 * <li>negative Zellengroesse in Y-Richtung (in Meter)</li>
+	 * <li>Horizontale Geo-Referenz (Longitude) der nord-westlichen Ecke</li>
+	 * <li>Vertikale Geo-Referenz (Latitude) der nord-westlichen Ecke</li>
+	 * </ol>
+	 * 
+	 * @param rasterWidth
+	 *            Breite des Rasters (in Zellen)
+	 * @param rasterHeight
+	 *            Hoehe des Rasters (in Zellen)
+	 * @param envelope
+	 *            Geo-Referenz des Rasters (Position und Ausdehnung)
+	 * @param output
+	 *            Datei in die das World-File geschrieben wird
+	 * @exception IOException
+	 *                falls die Datei nicht geschrieben werden kann
+	 */
+	public static void writeWorldFile(int rasterWidth, int rasterHeight,
+			Rectangle2D envelope, File output) throws IOException {
+		PrintWriter out = new PrintWriter(output);
+
+		// Zeile 1: Zellengroesse in Meter
+		out.println(envelope.getWidth() / rasterWidth);
+		// Zeile 2: Rotation in Y-Richtung
+		out.println("0.0");
+		// Zeile 3: Rotation in X-Richtung
+		out.println("0.0");
+		// Zeile 4: ?
+		out.println(-envelope.getHeight() / rasterHeight);
+		// Zeile 5: X-Georeferenz (Longitude) WESTEN
+		out.println(envelope.getX());
+		// Zeile 6: Y-Georeferenz (Latitude) NORDEN (Im Envelope steht SUEDEN!!)
+		out.println(envelope.getY() + envelope.getHeight());
+
+		out.flush();
+		out.close();
+	}
+
+	/**
 	 * Schreibt ein Projektions-File (.prj) fuer ein
 	 * {@link CoordinateReferenceSystem}.
 	 * 
@@ -259,17 +295,19 @@
 		out.flush();
 		out.close();
 	}
-  
 
-  /**
+	/**
 	 * Schreibt ein Projektions-File (.prj) fuer ein
 	 * {@link CoordinateReferenceSystem}. Wenn möglich wird die Schreibweise
-	 * "EPSG:12345" anstelle von WKT verwendet.
+	 * "EPSG:12345" anstelle von WKT verwendet. Wenn die Zieldatei existiert und
+	 * bereits den gleichen Inahlt hat, wird Sie nicht verändert (SVN
+	 * freundlich).
 	 * 
 	 * @param crs
 	 *            Koordinaten-System
 	 * @param outputFile
 	 *            Datei in die die Projektion geschrieben wird
+	 *            
 	 * @exception IOException
 	 *                falls die Datei nicht geschrieben werden kann
 	 */
@@ -278,36 +316,41 @@
 
 		// Directories will be created if needed.
 		outputFile.getParentFile().mkdirs();
-		
-		PrintWriter out = new PrintWriter(outputFile);
 
-		try {
+		String whatToWrite = null;
 
-			String whatToWrite = null;
-
-			/**
-			 * LetIf we can determine the EPSG code for this, let's save it as
-			 * "EPSG:12345" to the file.
-			 */
-			if (!crs.getIdentifiers().isEmpty()) {
-				Object next = crs.getIdentifiers().iterator().next();
-				if (next instanceof Identifier) {
-					Identifier identifier = (Identifier) next;
-					if (identifier.getAuthority().getTitle().toString().equals(
-							"European Petroleum Survey Group")
-							|| identifier.toString().startsWith("EPSG:")) {
-						whatToWrite = "EPSG:" + identifier.getCode();
-					}
+		/**
+		 * LetIf we can determine the EPSG code for this, let's save it as
+		 * "EPSG:12345" to the file.
+		 */
+		if (!crs.getIdentifiers().isEmpty()) {
+			Object next = crs.getIdentifiers().iterator().next();
+			if (next instanceof Identifier) {
+				Identifier identifier = (Identifier) next;
+				if (identifier.getAuthority().getTitle().toString().equals(
+						"European Petroleum Survey Group")
+						|| identifier.toString().startsWith("EPSG:")) {
+					whatToWrite = "EPSG:" + identifier.getCode();
 				}
 			}
+		}
 
-			if (whatToWrite == null) {
-				/*
-				 * If we don't know the EPSG code for the CRS, save it as WKT
-				 */
-				whatToWrite = crs.toWKT();
+		if (whatToWrite == null) {
+			// If we don't know the EPSG code for the CRS, save it as WKT
+			whatToWrite = crs.toWKT();
+		}
+
+		if (outputFile.exists()) {
+			String origCont = IOUtil.readFileAsString(outputFile);
+			if (origCont.equals(whatToWrite)) {
+				// Not writing anything because the file already contains the
+				// same stuff.
+				return;
 			}
+		}
 
+		PrintWriter out = new PrintWriter(outputFile);
+		try {
 			out.println(whatToWrite);
 			out.flush();
 		} finally {
@@ -315,6 +358,4 @@
 		}
 	}
 
-
 }
-

Modified: branches/2.0-RC1/src/schmitzm/geotools/styling/StylingUtil.java
===================================================================
--- branches/2.0-RC1/src/schmitzm/geotools/styling/StylingUtil.java	2009-12-09 14:46:29 UTC (rev 606)
+++ branches/2.0-RC1/src/schmitzm/geotools/styling/StylingUtil.java	2009-12-09 15:13:42 UTC (rev 607)
@@ -66,7 +66,12 @@
 import org.geotools.factory.GeoTools;
 import org.geotools.feature.FeatureCollection;
 import org.geotools.feature.GeometryAttributeType;
+import org.geotools.filter.AttributeExpression;
+import org.geotools.filter.AttributeExpressionImpl;
+import org.geotools.filter.AttributeExpressionImpl2;
+import org.geotools.filter.BinaryComparisonAbstract;
 import org.geotools.filter.ConstantExpression;
+import org.geotools.filter.FilterAttributeExtractor;
 import org.geotools.geometry.jts.ReferencedEnvelope;
 import org.geotools.renderer.lite.RendererUtilities;
 import org.geotools.resources.i18n.Vocabulary;
@@ -104,15 +109,18 @@
 import org.opengis.coverage.grid.GridCoverage;
 import org.opengis.feature.simple.SimpleFeature;
 import org.opengis.feature.simple.SimpleFeatureType;
+import org.opengis.feature.type.Name;
 import org.opengis.filter.And;
 import org.opengis.filter.Filter;
 import org.opengis.filter.FilterFactory;
 import org.opengis.filter.FilterFactory2;
 import org.opengis.filter.PropertyIsEqualTo;
 import org.opengis.filter.expression.Expression;
+import org.opengis.filter.expression.Function;
 import org.opengis.filter.expression.Literal;
 import org.opengis.filter.expression.PropertyName;
 
+import schmitzm.geotools.FilterUtil;
 import schmitzm.geotools.feature.FeatureUtil;
 import schmitzm.geotools.feature.FeatureUtil.GeometryForm;
 import schmitzm.geotools.grid.GridUtil;
@@ -1337,7 +1345,7 @@
 								}
 							} else if ((geom instanceof MultiPolygon)
 									|| (geom instanceof Polygon)) {
-								
+
 								if (symb instanceof PolygonSymbolizer) {
 									if (((PolygonSymbolizer) symb).getFill() != null)
 										passt = true;
@@ -2415,8 +2423,8 @@
 		// Der "scaleDenominator" der aktuellen JMapPane
 		Double scaleDenominator = RendererUtilities.calculateOGCScale(
 				new ReferencedEnvelope(xMapPane.getMapArea(), xMapPane
-						.getMapContext().getCoordinateReferenceSystem()), xMapPane
-						.getBounds().width, null);
+						.getMapContext().getCoordinateReferenceSystem()),
+				xMapPane.getBounds().width, null);
 
 		return filterSLDVisibleOnly(fc, style, scaleDenominator);
 	}
@@ -2489,6 +2497,39 @@
 				super.visit(sym);
 			}
 
+			@Override
+			public Expression copy(Expression expression) {
+				if (expression instanceof PropertyName) {
+					PropertyName pName = (PropertyName) expression;
+
+					Name correctedName = FeatureUtil
+							.findBestMatchingAttributeFallBackFirst(schema,
+									pName.getPropertyName());
+
+					return ff.property(correctedName);
+				}
+//				if (expression instanceof AttributeExpression) {
+//					AttributeExpression aExpression = (AttributeExpression) expression;
+//					Name correctedName = FeatureUtil
+//							.findBestMatchingAttributeFallBackFirst(schema,
+//									aExpression.getPropertyName());
+//
+//					return new AttributeExpressionImpl(correctedName
+//							.getLocalPart());
+//				}
+				return super.copy(expression);
+			}
+			
+			@Override
+			protected Filter copy(Filter filter) {
+				
+				if (filter instanceof BinaryComparisonAbstract) {
+					BinaryComparisonAbstract binFilter = (BinaryComparisonAbstract)filter;
+					binFilter.setExpression1(copy(binFilter.getExpression1()));
+					binFilter.setExpression2(copy(binFilter.getExpression2()));
+				}
+				return (Filter)super.copy(filter);
+			}
 		};
 
 		dsv.visit(style);
@@ -2496,4 +2537,148 @@
 		return (Style) dsv.getCopy();
 	}
 
+	/**
+	 * Geopublisher allows to use one or two attributes for labelling, like
+	 * 
+	 * <code>
+	 
+	    <sld:Label>
+          <ogc:PropertyName>ORTSRATSBE</ogc:PropertyName>: <ogc:PropertyName>ORB_SCHLUE</ogc:PropertyName>
+        </sld:Label>
+
+        </code>
+	 * 
+	 * Returns the second attribute found in the label expression of the given
+	 * {@link TextSymbolizer} or <code>null</code>.
+	 */
+	public static PropertyName getSecondPropertyName(
+			final SimpleFeatureType ft, final TextSymbolizer textSymbolizer) {
+		try {
+
+			final Expression labelExpression = textSymbolizer.getLabel();
+			if (labelExpression instanceof PropertyName) {
+				// There is no second property
+				return null;
+			} else if (labelExpression instanceof Function) {
+				final Function filterExpression = (Function) labelExpression;
+				final FilterAttributeExtractor attExVid = new FilterAttributeExtractor(
+						ft);
+
+				attExVid.visit(filterExpression, null);
+
+				final String[] attributeNames = attExVid.getAttributeNames();
+				if (attributeNames.length <= 1)
+					return null;
+
+				String prop2 = null;
+				if (filterExpression.toString().indexOf(attributeNames[0]) < filterExpression
+						.toString().indexOf(attributeNames[1])) {
+					prop2 = attributeNames[1];
+				} else {
+					prop2 = attributeNames[0];
+				}
+
+				LOGGER.debug("Thie second for \n" + filterExpression + "\n is "
+						+ prop2);
+
+				return FilterUtil.FILTER_FAC2.property(prop2);
+			}
+		}
+
+		catch (final Exception e) {
+			LOGGER.error("Reading the seconf property for labelling failed", e);
+		}
+
+		return null;
+	}
+
+	/**
+	 * Geopublisher allows to use one or two attributes for labelling, like
+	 * 
+	 * <code>
+	 
+	    <sld:Label>
+          <ogc:PropertyName>ORTSRATSBE</ogc:PropertyName>: <ogc:PropertyName>ORB_SCHLUE</ogc:PropertyName>
+        </sld:Label>
+
+        </code>
+	 * 
+	 * Returns the first attribute found in the label expression of the given
+	 * {@link TextSymbolizer}. If non is found for some reason, the method tries
+	 * to return the first attribute from the schema. We expect the layer to
+	 * have some attributes, because otherwise AS shouldn't even create the
+	 * LabellingTab.
+	 */
+	public static PropertyName getFirstPropertyName(final SimpleFeatureType ft,
+			final TextSymbolizer textSymbolizer) {
+		final Expression labelExpression = textSymbolizer.getLabel();
+		try {
+			if (labelExpression instanceof PropertyName) {
+				// There is no second property
+				return (PropertyName) labelExpression;
+			} else if (labelExpression instanceof Function) {
+				final Function filterExpression = (Function) labelExpression;
+				final FilterAttributeExtractor attExVid = new FilterAttributeExtractor(
+						ft);
+
+				attExVid.visit(filterExpression, null);
+
+				final String[] attributeNames = attExVid.getAttributeNames();
+				String prop1 = null;
+				if (attributeNames.length == 1) {
+					// Easy
+					prop1 = attributeNames[0];
+				} else {
+
+					if (filterExpression.toString().indexOf(attributeNames[0]) < filterExpression
+							.toString().indexOf(attributeNames[1])) {
+						prop1 = attributeNames[0];
+						// prop2 = attributeNames[1];
+					} else {
+						prop1 = attributeNames[1];
+						// prop2 = attributeNames[0];
+					}
+
+				}
+				return FilterUtil.FILTER_FAC2.property(prop1);
+			}
+		} catch (final Exception e) {
+			LOGGER.error("Reading the second property for labelling failed", e);
+			return null;
+		}
+
+		// TODO this is not rockhard.. could NPE
+		return FilterUtil.FILTER_FAC2.property(ft.getAttributeDescriptors()
+				.get(1).getLocalName());
+	}
+
+	/**
+	 * AtlasStyler has a fixed system that allows to use one or two label
+	 * attributes. If two are used, the are seperated by ": ". This mehtod stes
+	 * one or two ProperybaName fields.
+	 * 
+	 * @param symbolizer
+	 *            the {@link TextSymbolizer} to call setLabel(Expression) on.
+	 * @param literalLabelField1
+	 *            may not be null!
+	 * @param literalLabelField2
+	 *            may be <code>null</code>
+	 */
+	public static void setDoublePropertyName(final TextSymbolizer symbolizer,
+			final PropertyName literalLabelField1,
+			final PropertyName literalLabelField2) {
+		if (literalLabelField2 != null
+				&& !literalLabelField2.toString().equalsIgnoreCase("-")) {
+			final Literal trenner = FilterUtil.FILTER_FAC2.literal(": ");
+			final Function f3 = FilterUtil.FILTER_FAC2.function("strConcat",
+					trenner, literalLabelField2);
+			final Function bothExpression = FilterUtil.FILTER_FAC2.function(
+					"strConcat", literalLabelField1, f3);
+			LOGGER.debug("Extended label expression is now: " + bothExpression);
+			symbolizer.setLabel(bothExpression);
+		} else {
+			symbolizer.setLabel(literalLabelField1);
+		}
+	}
+
 }

Modified: branches/2.0-RC1/src/schmitzm/io/IOUtil.java
===================================================================
--- branches/2.0-RC1/src/schmitzm/io/IOUtil.java	2009-12-09 14:46:29 UTC (rev 606)
+++ branches/2.0-RC1/src/schmitzm/io/IOUtil.java	2009-12-09 15:13:42 UTC (rev 607)
@@ -29,10 +29,12 @@
  ******************************************************************************/
 package schmitzm.io;
 
+import java.io.BufferedReader;
 import java.io.File;
 import java.io.FileFilter;
 import java.io.IOException;
 import java.io.InputStream;
+import java.io.InputStreamReader;
 import java.io.OutputStream;
 import java.net.MalformedURLException;
 import java.net.URL;
@@ -41,157 +43,190 @@
 
 /**
  * Diese Klasse stellt statische Methoden fuer die Ein/Ausgabe zur Verfuegung.
- *
- * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
- *
+ * 
+ * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a>
+ *         (University of Bonn/Germany)
+ * 
  * @version 1.0
  */
 public class IOUtil {
 
-  private static Logger LOGGER = Logger.getLogger( IOUtil.class.getName() );
+	private static Logger LOGGER = Logger.getLogger(IOUtil.class.getName());
 
-  /** {@link FileFilter}, der alle Dateien akzeptiert, aber keine Verzeichnisse. */
-  public static final FileFilter ALL_FILES_FILTER = createSimpleFileFilter("*", FilterMode.FILES_ONLY);
-  /** {@link FileFilter}, der alle Verzeichnisse akzeptiert, aber keine "normalen" Dateien. */
-  public static final FileFilter ALL_DIRS_FILTER = createSimpleFileFilter("*", FilterMode.DIR_ONLY);
-  /** {@link FileFilter}, der alle Dateien und Verzeichnisse akzeptiert. */
-  public static final FileFilter ALL_FILTER = createSimpleFileFilter("*", FilterMode.ALL);
+	/**
+	 * {@link FileFilter}, der alle Dateien akzeptiert, aber keine Verzeichnisse.
+	 */
+	public static final FileFilter ALL_FILES_FILTER = createSimpleFileFilter(
+			"*", FilterMode.FILES_ONLY);
+	/**
+	 * {@link FileFilter}, der alle Verzeichnisse akzeptiert, aber keine
+	 * "normalen" Dateien.
+	 */
+	public static final FileFilter ALL_DIRS_FILTER = createSimpleFileFilter(
+			"*", FilterMode.DIR_ONLY);
+	/** {@link FileFilter}, der alle Dateien und Verzeichnisse akzeptiert. */
+	public static final FileFilter ALL_FILTER = createSimpleFileFilter("*",
+			FilterMode.ALL);
 
-  /**
-   * Modi fuer Filter.
-   * @see IOUtil#createSimpleFileFilter(String, FilterMode)
-   * @see IOUtil#createRegExFileFilter(String, FilterMode)
-   * @author mojays
-   *
-   */
-  public static enum FilterMode {
-    /** Der Filter liefert nur Dateien, aber keine Verzeichnisse. */
-    FILES_ONLY,
-    /** Der Filter liefert nur Verzeichnisse, aber keine Dateien. */
-    DIR_ONLY,
-    /** Der Filter liefert Dateien und Verzeichnisse. */
-    ALL
-  }
+	/**
+	 * Modi fuer Filter.
+	 * 
+	 * @see IOUtil#createSimpleFileFilter(String, FilterMode)
+	 * @see IOUtil#createRegExFileFilter(String, FilterMode)
+	 * @author mojays
+	 * 
+	 */
+	public static enum FilterMode {
+		/** Der Filter liefert nur Dateien, aber keine Verzeichnisse. */
+		FILES_ONLY,
+		/** Der Filter liefert nur Verzeichnisse, aber keine Dateien. */
+		DIR_ONLY,
+		/** Der Filter liefert Dateien und Verzeichnisse. */
+		ALL
+	}
 
-  /**
-   * Prueft, ob ein {@link File} einen angegebenen {@link FilterMode}
-   * erfuellt.
-   * @param file eine Datei oder ein Verzeichnis
-   * @param mode Filter-Modus (wenn {@code null} wird {@link FilterMode#ALL}
-   *             angenommen
-   * @return {@code false} wenn die angegebenen Datei {@code null} ist
-   */
-  public static boolean fileFitsFilterMode(File file, FilterMode mode) {
-    if ( mode == null )
-      mode = FilterMode.ALL;
-    final boolean acceptFiles = FilterMode.ALL.equals(mode) || FilterMode.FILES_ONLY.equals(mode);
-    final boolean acceptDirs  = FilterMode.ALL.equals(mode) || FilterMode.DIR_ONLY.equals(mode);
+	/**
+	 * Prueft, ob ein {@link File} einen angegebenen {@link FilterMode}
+	 * erfuellt.
+	 * 
+	 * @param file
+	 *            eine Datei oder ein Verzeichnis
+	 * @param mode
+	 *            Filter-Modus (wenn {@code null} wird {@link FilterMode#ALL}
+	 *            angenommen
+	 * @return {@code false} wenn die angegebenen Datei {@code null} ist
+	 */
+	public static boolean fileFitsFilterMode(File file, FilterMode mode) {
+		if (mode == null)
+			mode = FilterMode.ALL;
+		final boolean acceptFiles = FilterMode.ALL.equals(mode)
+				|| FilterMode.FILES_ONLY.equals(mode);
+		final boolean acceptDirs = FilterMode.ALL.equals(mode)
+				|| FilterMode.DIR_ONLY.equals(mode);
 
-    return file != null && ( file.isDirectory() && acceptDirs || acceptFiles );
-  }
+		return file != null
+				&& (file.isDirectory() && acceptDirs || acceptFiles);
+	}
 
+	/**
+	 * Liefert den Index des Dateinames, an der die Dateinamen-Erweiterung
+	 * (inkl. Punkt) beginnt.
+	 * 
+	 * @param file
+	 *            Datei
+	 */
+	public static int getFileExtIdx(File file) {
+		return getFileExtIdx(file.getAbsolutePath());
+	}
 
-  /**
-   * Liefert den Index des Dateinames, an der die Dateinamen-Erweiterung
-   * (inkl. Punkt) beginnt.
-   * @param file Datei
-   */
-  public static int getFileExtIdx(File file) {
-    return getFileExtIdx(file.getAbsolutePath());
-  }
+	/**
+	 * Liefert den Index des Dateinames, an der die Dateinamen-Erweiterung
+	 * (inkl. Punkt) beginnt.
+	 * 
+	 * @param file
+	 *            Datei
+	 */
+	public static int getFileExtIdx(String pathOrName) {
+		int lastPointIdx = pathOrName.lastIndexOf('.');
+		int lastSepIdx = pathOrName.lastIndexOf(File.separatorChar);
+		if (lastPointIdx < lastSepIdx)
+			return -1;
+		return lastPointIdx;
+	}
 
-  /**
-   * Liefert den Index des Dateinames, an der die Dateinamen-Erweiterung
-   * (inkl. Punkt) beginnt.
-   * @param file Datei
-   */
-  public static int getFileExtIdx(String pathOrName) {
-	  int lastPointIdx = pathOrName.lastIndexOf('.');
-	  int lastSepIdx   = pathOrName.lastIndexOf(File.separatorChar);
-	  if ( lastPointIdx < lastSepIdx )
-		  return -1;
-	  return lastPointIdx;
-  }
+	/**
+	 * Liefert die Dateinamen-Erweiterung (z.B. ".exe") einer Datei.
+	 * 
+	 * @param file
+	 *            Datei
+	 * @return Leerstring, falls die Datei keine Erweiterung hat
+	 */
+	public static String getFileExt(File file) {
+		return getFileExt(file, true);
+	}
 
-  /**
-   * Liefert die Dateinamen-Erweiterung (z.B. ".exe") einer Datei.
-   * @param file Datei
-   * @return Leerstring, falls die Datei keine Erweiterung hat
-   */
-  public static String getFileExt(File file) {
-    return getFileExt(file, true);
-  }
+	/**
+	 * Liefert die Dateinamen-Erweiterung (z.B. ".exe") einer Datei.
+	 * 
+	 * @param file
+	 *            Datei
+	 * @param withDot
+	 *            wenn {@code false} wird die Dateinamen-Erweiterung ohne den
+	 *            fuehrenden Punkt zurueckgegeben (z.B. "exe" statt ".exe")
+	 * @return Leerstring, falls die Datei keine Erweiterung hat
+	 */
+	public static String getFileExt(File file, boolean withDot) {
+		int extIdx = getFileExtIdx(file);
+		if (extIdx < 0)
+			return "";
+		if (!withDot)
+			extIdx++;
+		return file.getAbsolutePath().substring(extIdx);
+	}
 
-  /**
-   * Liefert die Dateinamen-Erweiterung (z.B. ".exe") einer Datei.
-   * @param file Datei
-   * @param withDot wenn {@code false} wird die Dateinamen-Erweiterung ohne
-   *                den fuehrenden Punkt zurueckgegeben (z.B. "exe" statt ".exe")
-   * @return Leerstring, falls die Datei keine Erweiterung hat
-   */
-  public static String getFileExt(File file, boolean withDot) {
-    int extIdx = getFileExtIdx(file);
-    if ( extIdx < 0 )
-      return "";
-    if ( !withDot )
-      extIdx++;
-    return file.getAbsolutePath().substring(extIdx);
-  }
+	/**
+	 * Haengt an einen Dateinamen-Erweiterung eine Erweiterung an, sofern diese
+	 * noch nicht angehaengt ist.
+	 * 
+	 * @param file
+	 *            Datei
+	 * @param newExt
+	 *            neue Dateinamen-Erweiterung (mit oder ohne ".")
+	 * @return neues {@link File}-Objekt
+	 */
+	public static File appendFileExt(File file, String newExt) {
+		if (!newExt.startsWith("."))
+			newExt = "." + newExt;
+		String oldExt = getFileExt(file, true);
+		if (!oldExt.equalsIgnoreCase(newExt))
+			file = new File(file.getAbsolutePath() + newExt);
+		return file;
+	}
 
-  /**
-   * Haengt an einen Dateinamen-Erweiterung eine Erweiterung an, sofern diese
-   * noch nicht angehaengt ist.
-   * @param file Datei
-   * @param newExt neue Dateinamen-Erweiterung (mit oder ohne ".")
-   * @return neues {@link File}-Objekt
-   */
-  public static File appendFileExt(File file, String newExt) {
-    if (!newExt.startsWith("."))
-      newExt = "."+newExt;
-    String oldExt = getFileExt(file,true);
-    if ( !oldExt.equalsIgnoreCase(newExt) )
-      file = new File( file.getAbsolutePath() + newExt );
-    return file;
-  }
+	/**
+	 * Aendert die Dateinamen-Erweiterung (z.B. ".exe") einer Datei.
+	 * 
+	 * @param file
+	 *            Datei
+	 * @param newExt
+	 *            neue Dateinamen-Erweiterung (ohne ".")
+	 * @return neues {@link File}-Objekt
+	 */
+	public static File changeFileExt(File file, String newExt) {
+		String baseName = getBaseFilePath(file);
+		return new File(baseName + "." + newExt);
+	}
 
-  /**
-   * Aendert die Dateinamen-Erweiterung (z.B. ".exe") einer Datei.
-   * @param file Datei
-   * @param newExt neue Dateinamen-Erweiterung (ohne ".")
-   * @return neues {@link File}-Objekt
-   */
-  public static File changeFileExt(File file, String newExt) {
-    String baseName = getBaseFilePath(file);
-    return new File( baseName+"."+newExt );
-  }
-
-
 	/**
 	 * Changes the ending (e.g. ".sld") of a {@link URL}
-	 *
-	 * @param url {@link URL} like <code>file:/sds/a.bmp</code>
-	 * @param postfix New file extension for the {@link URL} without <code>.</code>
-	 *
+	 * 
+	 * @param url
+	 *            {@link URL} like <code>file:/sds/a.bmp</code>
+	 * @param postfix
+	 *            New file extension for the {@link URL} without <code>.</code>
+	 * 
 	 * @return A new {@link URL} with new extension.
-	 *
-	 * @author <a href="mailto:skpublic at wikisquare.de">Stefan Alfons Kr&uuml;ger</a>
 	 * 
+	 * @author <a href="mailto:skpublic at wikisquare.de">Stefan Alfons
+	 *         Kr&uuml;ger</a>
+	 * 
 	 */
-	public static URL changeUrlExt(final URL url, final String postfix) throws IllegalArgumentException{
+	public static URL changeUrlExt(final URL url, final String postfix)
+			throws IllegalArgumentException {
 		String a = url.toExternalForm();
-                final int lastDotPos = a.lastIndexOf('.');
-                if ( lastDotPos >= 0 )
-                  a = a.substring(0, lastDotPos);
-                a = a + "." + postfix;
+		final int lastDotPos = a.lastIndexOf('.');
+		if (lastDotPos >= 0)
+			a = a.substring(0, lastDotPos);
+		a = a + "." + postfix;
 		try {
 			return new URL(a);
 		} catch (final MalformedURLException e) {
-			throw new IllegalArgumentException("can't create a new URL for "+url+" with new extension "+postfix, e);
+			throw new IllegalArgumentException("can't create a new URL for "
+					+ url + " with new extension " + postfix, e);
 		}
 	}
-	
 
-	  /**
+	/**
 	 * Die Funktion soll der Funktion File.getParent() fuer URLs entsprechen.
 	 * Die URL wird in einen Sting konvertiert und dann (kuerzer) neu
 	 * zusammengesetzt. Falls eine Verkuerzung nicht moeglich ist, wird eine
@@ -199,8 +234,8 @@
 	 * 
 	 * @author <a href="mailto:skpublic at wikisquare.de">Stefan Alfons
 	 *         Kr&uuml;ger</a>
-	 *         
-	 *         
+	 * 
+	 * 
 	 */
 	public static URL getParentUrl(final URL url) throws MalformedURLException {
 		String a = url.toExternalForm();
@@ -209,16 +244,16 @@
 			a = a.substring(0, lastDotPos);
 
 		/**
-		 * The parent of jar:file:some!/bar.file is jar:file:some!/, not jar:file:some!  
+		 * The parent of jar:file:some!/bar.file is jar:file:some!/, not
+		 * jar:file:some!
 		 */
-		if (a.endsWith("!")) a+="/";
+		if (a.endsWith("!"))
+			a += "/";
 
 		return new URL(a);
 	}
 
-
-
-  /**
+	/**
 	 * @deprecated use getParentUrl()
 	 */
 	public static URL getParentURL(URL url) throws MalformedURLException {
@@ -226,285 +261,329 @@
 	}
 
 	/**
-	 * Erweitert eine {@link URL}. Bei der uebergebenen URL muss es sich um ein Verzeichnis handeln, sonst
-	 * wird eine {@link MalformedURLException} geschmissen
+	 * Erweitert eine {@link URL}. Bei der uebergebenen URL muss es sich um ein
+	 * Verzeichnis handeln, sonst wird eine {@link MalformedURLException}
+	 * geschmissen
+	 * 
 	 * @param base
 	 * @param string
-	 *
+	 * 
 	 * @throws MalformedURLException
 	 */
-	public static URL extendURL(URL base, String string) throws MalformedURLException {
+	public static URL extendURL(URL base, String string)
+			throws MalformedURLException {
 		String a = base.toExternalForm();
-		if (!a.endsWith("/")) a+= "/";
-		a+= string;
+		if (!a.endsWith("/"))
+			a += "/";
+		a += string;
 		return new URL(a);
 	}
 
+	/**
+	 * Liefert den Pfad ohne Erweiterung (z.B. ohne ".exe") einer Datei.
+	 * 
+	 * @param file
+	 *            Datei
+	 * 
+	 * @see #getBaseFileName(File)
+	 */
+	public static String getBaseFilePath(File file) {
+		int extIdx = getFileExtIdx(file);
+		if (extIdx < 0)
+			return file.getAbsolutePath();
+		return file.getAbsolutePath().substring(0, extIdx);
+	}
 
+	/**
+	 * Liefert den Dateinamen ohne Erweiterung (z.B. ohne ".exe") einer Datei.
+	 * 
+	 * @param file
+	 *            Datei
+	 * 
+	 * @see #getBaseFilePath(File)
+	 */
+	public static String getBaseFileName(File file) {
+		int extIdx = getFileExtIdx(file.getName());
+		if (extIdx < 0)
+			return file.getName();
+		return file.getName().substring(0, extIdx);
+	}
 
-  /**
-   * Liefert den Pfad ohne Erweiterung (z.B. ohne ".exe") einer Datei.
-   * 
-   * @param file Datei
-   * 
-   * @see #getBaseFileName(File)
-   */
-  public static String getBaseFilePath(File file) {
-    int extIdx = getFileExtIdx(file);
-    if ( extIdx < 0 )
-      return file.getAbsolutePath();
-    return file.getAbsolutePath().substring(0,extIdx);
-  }
+	/**
+	 * Liefert das oberste Verzeichnis zu einer Datei (Haupt-Verzeichnis).
+	 * 
+	 * @param file
+	 *            Datei
+	 */
+	public static File getRootDir(File file) {
+		File temp = new File(file.getAbsolutePath());
+		while (temp.getParentFile() != null)
+			temp = temp.getParentFile();
+		return temp;
+	}
 
-  /**
-   * Liefert den Dateinamen ohne Erweiterung (z.B. ohne ".exe") einer Datei.
-   * 
-   * @param file Datei
-   * 
-   * @see #getBaseFilePath(File)
-   */
-  public static String getBaseFileName(File file) {
-	  int extIdx = getFileExtIdx( file.getName() );
-	  if ( extIdx < 0 )
-		  return file.getName();
-	  return file.getName().substring(0,extIdx);
-  }
-  
-  /**
-   * Liefert das oberste Verzeichnis zu einer Datei (Haupt-Verzeichnis).
-   * @param file Datei
-   */
-  public static File getRootDir(File file) {
-    File temp = new File(file.getAbsolutePath());
-    while( temp.getParentFile() != null )
-      temp = temp.getParentFile();
-    return temp;
-  }
+	/**
+	 * Erzeugt ein neues File-Objekt relativ zu einer Pfad-Angabe.<br>
+	 * Im Normalfall setzt sich der neue Datei-Pfad aus <code>baseDir</code> und
+	 * <code>path</code> zusammen, also <i>newFile = <code>baseDir</code> +
+	 * <code>path<code></i>.<br>
+	 * <b>Ausnahme 1:</b><br>
+	 * Beginnt <code>path</code> mit einem Slash (bzw. Backslash bei Windows),
+	 * ist <i>newFile = ROOT(<code>baseDir</code>) + <code>path<code></i>,
+	 * wobei <i>ROOT(<code>baseDir</code>)</i></center> das Hauptverzeichnis
+	 * (Laufwerk) des Basis-Verzeichnisses bezeichnet.<br>
+	 * <b>Ausnahme 2:</b><br>
+	 * Stellt <code>path</code> bereits eine absolute Pfadangabe dar (inkl.
+	 * Laufwerksbezeichnung), ist <i>newFile = <code>path<code></i>.
+	 * 
+	 * @param baseDir
+	 *            Basis-Verzeichnis
+	 * @param path
+	 *            Pfad/Datei-Angabe relativ zu <code>baseDir</code>
+	 * @see #getRootDir(File)
+	 */
+	public static File createRelativeFile(File baseDir, String path) {
+		File file = new File(path);
 
-  /**
-   * Erzeugt ein neues File-Objekt relativ zu einer Pfad-Angabe.<br>
-   * Im Normalfall setzt sich der neue Datei-Pfad aus <code>baseDir</code> und
-   * <code>path</code> zusammen, also <i>newFile = <code>baseDir</code> + <code>path<code></i>.<br>
-   * <b>Ausnahme 1:</b><br>
-   * Beginnt <code>path</code> mit einem Slash (bzw. Backslash bei Windows), ist
-   * <i>newFile = ROOT(<code>baseDir</code>) + <code>path<code></i>,
-   * wobei <i>ROOT(<code>baseDir</code>)</i></center> das Hauptverzeichnis
-   * (Laufwerk) des Basis-Verzeichnisses bezeichnet.<br>
-   * <b>Ausnahme 2:</b><br>
-   * Stellt <code>path</code> bereits eine absolute Pfadangabe dar (inkl.
-   * Laufwerksbezeichnung), ist <i>newFile = <code>path<code></i>.
-   * @param baseDir Basis-Verzeichnis
-   * @param path Pfad/Datei-Angabe relativ zu <code>baseDir</code>
-   * @see #getRootDir(File)
-   */
-  public static File createRelativeFile(File baseDir, String path) {
-    File file = new File( path );
+		// In relPath steht absolute Pfadangabe -> BaseDir ignorieren
+		if (path.equalsIgnoreCase(file.getAbsolutePath()))
+			return file;
 
-    // In relPath steht absolute Pfadangabe -> BaseDir ignorieren
-    if ( path.equalsIgnoreCase( file.getAbsolutePath() ) )
-      return file;
+		// Source-Tag beginnt mit '\' -> Source-Angabe relativ zum
+		// Haupt-Verzeichnis
+		if (path.startsWith(File.separator))
+			return new File(IOUtil.getRootDir(baseDir), path);
 
-    // Source-Tag beginnt mit '\' -> Source-Angabe relativ zum Haupt-Verzeichnis
-    if ( path.startsWith( File.separator ) )
-      return new File(IOUtil.getRootDir(baseDir),path );
+		// Sonst: BaseDir als Basis fuer Source verwenden
+		return new File(baseDir, path);
+	}
 
-    // Sonst: BaseDir als Basis fuer Source verwenden
-    return new File(baseDir, path);
-  }
+	/**
+	 * Versucht einen Eingabe-Stream zu schliessen.<br>
+	 * Dabei werden bei Misserfolg keine Exceptions geworfen! SK: bei
+	 * <code>null</code> wird true zurueckgegeben
+	 * 
+	 * @param in
+	 *            zu schliessender Stream
+	 * @return <code>false</code> falls das Schliessen nicht erfolgreich war
+	 */
+	public static boolean closeInputStream(InputStream in) {
+		if (in == null)
+			return true;
+		try {
+			in.close();
+		} catch (Exception err) {
+			return false;
+		}
+		return true;
+	}
 
-  /**
-   * Versucht einen Eingabe-Stream zu schliessen.<br>
-   * Dabei werden bei Misserfolg keine Exceptions geworfen!
-   * SK: bei <code>null</code> wird true zurueckgegeben
-   *
-   * @param in zu schliessender Stream
-   * @return <code>false</code> falls das Schliessen nicht erfolgreich war
-   */
-  public static boolean closeInputStream(InputStream in) {
-	if (in == null) return true;
-    try {
-      in.close();
-    } catch (Exception err) {
-      return false;
-    }
-    return true;
-  }
+	/**
+	 * Versucht alle gegebenen Eingabe-Streams zu schliessen.<br>
+	 * Dabei werden bei Misserfolg keine Exceptions geworfen!
+	 * 
+	 * @param in
+	 *            zu schliessende Streams
+	 * @return <code>true</code> falls das Schliessen aller Streams erfolgreich
+	 *         war
+	 */
+	public static boolean closeInputStream(InputStream[] in) {
+		boolean result = true;
+		for (int i = 0; i < in.length; i++)
+			result &= closeInputStream(in[i]);
+		return result;
+	}
 
-  /**
-   * Versucht alle gegebenen Eingabe-Streams zu schliessen.<br>
-   * Dabei werden bei Misserfolg keine Exceptions geworfen!
-   * @param in zu schliessende Streams
-   * @return <code>true</code> falls das Schliessen aller Streams erfolgreich war
-   */
-  public static boolean closeInputStream(InputStream[] in) {
-    boolean result = true;
-    for (int i=0; i<in.length; i++)
-      result &= closeInputStream(in[i]);
-    return result;
-  }
+	/**
+	 * Versucht einen Ausgabe-Stream zu schliessen. Zuvor wird ein
+	 * {@link OutputStream#flush() flush()} auf den Stream getaetigt.<br>
+	 * Bei Misserfolg werden keine Exceptions geworfen! SK: bei
+	 * <code>null</code> wird true zurueckgegeben *
+	 * 
+	 * @param out
+	 *            zu schliessender Stream
+	 * @return <code>false</code> falls das Schliessen nicht erfolgreich war
+	 */
+	public static boolean closeOutputStream(OutputStream out) {
+		if (out == null)
+			return true;
+		try {
+			out.flush();
+			out.close();
+		} catch (Exception err) {
+			return false;
+		}
+		return true;
+	}
 
-  /**
-   * Versucht einen Ausgabe-Stream zu schliessen. Zuvor wird ein
-   * {@link OutputStream#flush() flush()} auf den Stream getaetigt.<br>
-   * Bei Misserfolg werden keine Exceptions geworfen!
-   * SK: bei <code>null</code> wird true zurueckgegeben   *
-   * @param out zu schliessender Stream
-   * @return <code>false</code> falls das Schliessen nicht erfolgreich war
-   */
-  public static boolean closeOutputStream(OutputStream out) {
-	  if (out == null) return true;
-    try {
-      out.flush();
-      out.close();
-    } catch (Exception err) {
-      return false;
-    }
-    return true;
-  }
+	/**
+	 * Prueft, ob eine (Datei-)Zeile mit einem Kommentarkennzeichen beginnt und
+	 * deshalb ignoriert werden muss. Kommentar-Kennzeichen sind <code>//</code>
+	 * , <code>#</code> und <code>|</code>.
+	 * 
+	 * @param line
+	 *            Eingabe-Zeile
+	 */
+	public static boolean isCommentLine(String line) {
+		return line.startsWith("//") || line.startsWith("#")
+				|| line.startsWith("|");
+	}
 
-  /**
-   * Prueft, ob eine (Datei-)Zeile mit einem Kommentarkennzeichen beginnt
-   * und deshalb ignoriert werden muss. Kommentar-Kennzeichen sind
-   * <code>//</code>, <code>#</code> und <code>|</code>.
-   * @param line Eingabe-Zeile
-   */
-  public static boolean isCommentLine(String line) {
-    return line.startsWith("//") ||
-           line.startsWith("#")  ||
-           line.startsWith("|");
-  }
+	/**
+	 * Schreibt einen Eingabe-Stream in eine Datei.
+	 * 
+	 * @param file
+	 *            Dateipfad fuer die Zieldatei
+	 * @exception java.io.IOException
+	 *                falls das Lesen aus dem Stream oder das Schreiben in die
+	 *                Ausgabedatei scheitert
+	 */
+	public static void writeStreamToFile(InputStream input, String file)
+			throws IOException {
+		OutputStream output = new FileOutputStream(file);
+		while (input.available() > 0)
+			output.write(input.read());
+		output.flush();
+		output.close();
+	}
 
-  /**
-   * Schreibt einen Eingabe-Stream in eine Datei.
-   * @param file      Dateipfad fuer die Zieldatei
-   * @exception java.io.IOException falls das Lesen aus dem Stream oder
-   *            das Schreiben in die Ausgabedatei scheitert
-   */
-  public static void writeStreamToFile(InputStream input, String file) throws IOException {
-    OutputStream output = new FileOutputStream(file);
-    while (input.available() > 0) output.write(input.read());
-    output.flush();
-    output.close();
-  }
+	/**
+	 * Erstellt einen Filter fuer einen regulaeren Ausdruck.
+	 * 
+	 * @param filterStr
+	 *            definiert den Filter
+	 */
+	public static FileFilter createRegExFileFilter(final String regEx,
+			final FilterMode mode) {
+		return new FileFilter() {
+			public boolean accept(File file) {
+				return fileFitsFilterMode(file, mode)
+						&& file.getName().matches(regEx);
+			}
+		};
+	}
 
-  /**
-   * Erstellt einen Filter fuer einen regulaeren Ausdruck.
-   * @param filterStr definiert den Filter
-   */
-  public static FileFilter createRegExFileFilter(final String regEx, final FilterMode mode) {
-    return new FileFilter() {
-      public boolean accept(File file) {
-        return fileFitsFilterMode(file,mode) && file.getName().matches(regEx);
-      }
-    };
-  }
+	/**
+	 * Erstellt einen Filter fuer einen Filter-String. Dieser kann als Wildcard
+	 * das Zeichen "*" enthalten. Alle anderen Zeichen werden direkt als Filter
+	 * verwendet.
+	 * 
+	 * @param filterStr
+	 *            definiert den Filter
+	 */
+	public static FileFilter createSimpleFileFilter(String filterStr,
+			final FilterMode mode) {
+		// Gross/Klein-Schreibung ignorieren
+		filterStr = filterStr.toLowerCase();
 
+		// ##### Filter definiert den "inneren" Teil eines Dateinames #####
+		if (filterStr.startsWith("*") && filterStr.endsWith("*")) {
+			// Filter besteht nur aus "*" --> alle Dateien akzeptieren
+			if (filterStr.length() <= 2)
+				return new FileFilter() {
+					public boolean accept(File file) {
+						return fileFitsFilterMode(file, mode);
+					}
+				};
+			// "inneren" Teil des Filters extrahieren
+			final String condStr = filterStr.substring(1,
+					filterStr.length() - 1);
+			return new FileFilter() {
+				public boolean accept(File file) {
+					return fileFitsFilterMode(file, mode)
+							&& file.getName().toLowerCase().contains(condStr);
+				}
+			};
+		}
 
-  /**
-   * Erstellt einen Filter fuer einen Filter-String. Dieser kann
-   * als Wildcard das Zeichen "*" enthalten. Alle anderen Zeichen
-   * werden direkt als Filter verwendet.
-   * @param filterStr definiert den Filter
-   */
-  public static FileFilter createSimpleFileFilter(String filterStr, final FilterMode mode) {
-    // Gross/Klein-Schreibung ignorieren
-    filterStr = filterStr.toLowerCase();
+		// ##### Filter definiert den Anfang eines Dateinames #####
+		if (filterStr.endsWith("*")) {
+			// Anfang des Filters extrahieren
+			final String condStr = filterStr.substring(0,
+					filterStr.length() - 1);
+			return new FileFilter() {
+				public boolean accept(File file) {
+					return fileFitsFilterMode(file, mode)
+							&& file.getName().toLowerCase().startsWith(condStr);
+				}
+			};
+		}
+		// ##### Filter definiert das Ende eines Dateinames #####
+		if (filterStr.startsWith("*")) {
+			// Ende des Filters extrahieren
+			final String condStr = filterStr.substring(1);
+			return new FileFilter() {
+				public boolean accept(File file) {
+					return fileFitsFilterMode(file, mode)
+							&& file.getName().toLowerCase().endsWith(condStr);
+				}
+			};
+		}
+		// ##### Filter definiert den genauen Dateinamen #####
+		final String condStr = filterStr;
+		return new FileFilter() {
+			public boolean accept(File file) {
+				return fileFitsFilterMode(file, mode)
+						&& file.getName().equalsIgnoreCase(condStr);
+			}
+		};
+	}
 
-    //##### Filter definiert den "inneren" Teil eines Dateinames #####
-    if ( filterStr.startsWith("*") && filterStr.endsWith("*") ) {
-      // Filter besteht nur aus "*" --> alle Dateien akzeptieren
-      if ( filterStr.length() <= 2 )
-        return new FileFilter() {
-          public boolean accept(File file) {
-            return fileFitsFilterMode(file,mode);
-          }
-        };
-      // "inneren" Teil des Filters extrahieren
-      final String condStr = filterStr.substring(1,filterStr.length()-1);
-      return new FileFilter() {
-        public boolean accept(File file) {
-          return fileFitsFilterMode(file,mode) && file.getName().toLowerCase().contains(condStr) ;
-        }
-      };
-    }
+	/**
+	 * Loescht Dateien oder Verzeichnisse in einem Verzeichnis. Das Verzeichnis
+	 * selbst wird dabei NICHT geloescht, auch wenn es am Ende leer ist!
+	 * 
+	 * @param dir
+	 *            Verzeichnis in dem Dateien/Verzeichnisse geloescht werden
+	 * @param filter
+	 *            bestimmt, welche Dateien/Verzeichnisse geloescht werden
+	 * @param recursive
+	 *            wenn {@code true} werden auch alle Dateien/Verzeichnisse in
+	 *            Unterverzeichnissen geloescht, die dem Filter entsprechen
+	 * @param showFiles
+	 *            wenn {@code true} werden die geloeschten Dateien auf der
+	 *            Console ausgegeben
+	 * @return Anzahl geloeschter Dateien und Verzeichnisse
+	 */
+	public static int deleteFiles(File dir, FileFilter filter,
+			boolean recursive, boolean showFiles) {
+		if (!dir.isDirectory())
+			return 0;
 
-    //##### Filter definiert den Anfang eines Dateinames #####
-    if ( filterStr.endsWith("*") ) {
-      // Anfang des Filters extrahieren
-      final String condStr = filterStr.substring(0,filterStr.length()-1);
-      return new FileFilter() {
-        public boolean accept(File file) {
-          return fileFitsFilterMode(file,mode) && file.getName().toLowerCase().startsWith(condStr) ;
-        }
-      };
-    }
-    //##### Filter definiert das Ende eines Dateinames #####
-    if ( filterStr.startsWith("*") ) {
-      // Ende des Filters extrahieren
-      final String condStr = filterStr.substring(1);
-      return new FileFilter() {
-        public boolean accept(File file) {
-          return fileFitsFilterMode(file,mode) && file.getName().toLowerCase().endsWith(condStr) ;
-        }
-      };
-    }
-    //##### Filter definiert den genauen Dateinamen #####
-    final String condStr = filterStr;
-    return new FileFilter() {
-      public boolean accept(File file) {
-        return fileFitsFilterMode(file,mode) && file.getName().equalsIgnoreCase(condStr) ;
-      }
-    };
-  }
+		int delCount = 0;
+		// Dateien im aktuellen Verzeichnis loeschen
+		File[] files = filter != null ? dir.listFiles(filter) : dir.listFiles();
+		for (File file : files) {
+			// Verzeichnis zunaechst leeren
+			if (file.isDirectory())
+				delCount += deleteFiles(file, null, true, showFiles);
+			boolean success = file.delete();
+			if (success)
+				delCount++;
+			if (showFiles) {
+				StringBuffer message = new StringBuffer(success ? "Deleted: "
+						: "Error: ");
+				try {
+					message.append(file.getCanonicalPath());
+				} catch (Exception err) {
+					message.append(file.getAbsolutePath());
+				}
+			}
+		}
+		// Wenn rekusiv geloescht werden soll, alle Verzeichnisse im Verzeichnis
+		// durchsuchen
+		if (recursive) {
+			File[] directories = dir.listFiles(ALL_DIRS_FILTER);
+			for (File directory : directories)
+				delCount += deleteFiles(directory, filter, recursive, showFiles);
+		}
+		return delCount;
+	}
 
-  /**
-   * Loescht Dateien oder Verzeichnisse in einem Verzeichnis. Das Verzeichnis selbst
-   * wird dabei NICHT geloescht, auch wenn es am Ende leer ist!
-   * @param dir       Verzeichnis in dem Dateien/Verzeichnisse geloescht werden
-   * @param filter    bestimmt, welche Dateien/Verzeichnisse geloescht werden
-   * @param recursive wenn {@code true} werden auch alle Dateien/Verzeichnisse
-   *                  in Unterverzeichnissen geloescht, die dem Filter entsprechen
-   * @param showFiles wenn {@code true} werden die geloeschten Dateien auf der
-   *                  Console ausgegeben
-   * @return Anzahl geloeschter Dateien und Verzeichnisse
-   */
-  public static int deleteFiles(File dir, FileFilter filter, boolean recursive, boolean showFiles) {
-    if ( !dir.isDirectory() )
-      return 0;
-
-    int delCount = 0;
-    // Dateien im aktuellen Verzeichnis loeschen
-    File[] files = filter != null ? dir.listFiles( filter ) : dir.listFiles();
-    for (File file : files) {
-      // Verzeichnis zunaechst leeren
-      if ( file.isDirectory() )
-        delCount += deleteFiles(file, null, true, showFiles);
-      boolean success = file.delete();
-      if ( success )
-        delCount++;
-      if ( showFiles ) {
-        StringBuffer message = new StringBuffer(success ? "Deleted: " : "Error: ");
-        try {
-          message.append( file.getCanonicalPath() );
-        } catch (Exception err) {
-          message.append( file.getAbsolutePath() );
-        }
-      }
-    }
-    // Wenn rekusiv geloescht werden soll, alle Verzeichnisse im Verzeichnis
-    // durchsuchen
-    if ( recursive ) {
-      File[] directories = dir.listFiles(ALL_DIRS_FILTER);
-      for (File directory : directories)
-        delCount += deleteFiles(directory, filter, recursive, showFiles);
-    }
-    return delCount;
-  }
-
-  /**
+	/**
 	 * Die Umwandlung einer URL in ein File-Objekt ist leider nicht trivial.
 	 * 
-	 * @see http
+	 * @see http 
 	 *      ://weblogs.java.net/blog/kohsuke/archive/2007/04/how_to_convert.html
 	 * 
 	 * @param url
@@ -513,7 +592,7 @@
 	 *         Kr&uuml;ger</a>
 	 */
 	public static File urlToFile(URL url) {
-//		LOGGER.debug("\nconverting " + url.toString() + " to ");
+		// LOGGER.debug("\nconverting " + url.toString() + " to ");
 		File f;
 		try {
 			f = new File(url.toURI());
@@ -521,40 +600,40 @@
 			// TODO Here we probably need more cases...
 			f = new File(url.getPath().replace("%20", " "));
 		}
-//		LOGGER.debug("        to " + f.toString());
+		// LOGGER.debug("        to " + f.toString());
 		return f;
 	}
-	
 
-	  /**
-	   * Fuehrt verschiedene Funktionen aus.
-	   * <ul>
-	   *   <li>{@code DELDIR name}<br>
-	   *       Loescht ein Verzeichnis aus allen Unterverzeichnissen.</li>
-	   * </ul>
-	   * @param arg
-	   */
-	  public static void main(final String[] arg) {
-	    if ( arg.length == 0 ) {
-	      System.err.println("Missing arguments.");
-	      return;
-	    }
+	/**
+	 * Fuehrt verschiedene Funktionen aus.
+	 * <ul>
+	 * <li>{@code DELDIR name}<br>
+	 * Loescht ein Verzeichnis aus allen Unterverzeichnissen.</li>
+	 * </ul>
+	 * 
+	 * @param arg
+	 */
+	public static void main(final String[] arg) {
+		if (arg.length == 0) {
+			System.err.println("Missing arguments.");
+			return;
+		}
 
-	    String func = arg[0].toUpperCase();
-	    if ( func.equals("DELDIR") ) {
-	      if ( arg.length < 2 ) {
-	        System.err.println("Missing arguments for DELDIR.");
-	      }
-	      File currDir        = new File(".");
-	      FileFilter filter   = createSimpleFileFilter(arg[1],FilterMode.DIR_ONLY);
-	      int        delCount = deleteFiles(currDir, filter, true, true);
-	    }
-	    else {
-	      LOGGER.error("Unknown function: "+func);
-	    }
-	  }
+		String func = arg[0].toUpperCase();
+		if (func.equals("DELDIR")) {
+			if (arg.length < 2) {
+				System.err.println("Missing arguments for DELDIR.");
+			}
+			File currDir = new File(".");
+			FileFilter filter = createSimpleFileFilter(arg[1],
+					FilterMode.DIR_ONLY);
+			int delCount = deleteFiles(currDir, filter, true, true);
+		} else {
+			LOGGER.error("Unknown function: " + func);
+		}
+	}
 
-	  /**
+	/**
 	 * The method File getTempDir() caches the system's temp direcotry here.
 	 * 
 	 * @see #getTempDir()
@@ -568,7 +647,8 @@
 	 * The folder is cached in a static {@link File} field.
 	 * 
 	 * @return A {@link File} object pointing to the system's temp directory.
-	 *         This method does some extra checks and returns a valid {@link File}
+	 *         This method does some extra checks and returns a valid
+	 *         {@link File}
 	 * 
 	 * @see
 	 *      <code>http://rationalpi.wordpress.com/2007/01/26/javaiotmpdir-inconsitency/</code>
@@ -579,7 +659,8 @@
 			String tempPath = System.getProperty("java.io.tmpdir", System
 					.getenv("TEMP"));
 
-			if (tempPath == null || tempPath.isEmpty() || !new File(tempPath).exists()) {
+			if (tempPath == null || tempPath.isEmpty()
+					|| !new File(tempPath).exists()) {
 				LOGGER.warn("Temporary directory can't be found. Using /tmp");
 				tempPath = "/tmp";
 			}
@@ -588,16 +669,17 @@
 				tempPath = tempPath.substring(0, tempPath.length() - 1);
 
 			tempDir = new File(tempPath);
-			
-			if (!tempDir.exists()) throw new IllegalStateException("Temp direcotory can't be determined."); 
+
+			if (!tempDir.exists())
+				throw new IllegalStateException(
+						"Temp direcotory can't be determined.");
 		}
 
 		return tempDir;
 	}
 
-
 	/**
-	 * Test whether it is possible to access the given URL. 
+	 * Test whether it is possible to access the given URL.
 	 */
 	public static boolean urlExists(final URL url) {
 		try {
@@ -608,4 +690,57 @@
 		return true;
 	}
 
+	/**
+	 * Reads the contents of a File into one String. Watch the size!
+	 * 
+	 * @param file
+	 *            a File to read
+	 * @return as String the content of the file.
+	 * 
+	 * @throws java.io.IOException
+	 */
+	public static String readFileAsString(File file) throws java.io.IOException {
+		byte[] buffer = new byte[(int) file.length()];
+		FileInputStream f = new FileInputStream(file);
+		try {
+			f.read(buffer);
+			return new String(buffer);
+		} finally {
+			f.close();
+		}
+	}
+
+	/**
+	 * @return a {@link String} with the content of the {@link URL}. Do not use
+	 *         this on long files! Returns <code>null</code> if an erro occured.
+	 */
+	public static String readURLasString(URL url) {
+		try {
+
+			InputStream openStream = url.openStream();
+			try {
+
+				InputStreamReader inStream = new InputStreamReader(openStream);
+				try {
+
+					BufferedReader inReader = new BufferedReader(inStream);
+					try {
+						String content = inReader.readLine();
+						return content;
+					} finally {
+						inReader.close();
+					}
+
+				} finally {
+					inStream.close();
+				}
+			} finally {
+				openStream.close();
+			}
+		} catch (IOException e) {
+			LOGGER.error("getURLasString " + url, e);
+		}
+		return null;
+	}
+
 }

Modified: branches/2.0-RC1/src/schmitzm/lang/tree/OperationTreeParser.java
===================================================================
--- branches/2.0-RC1/src/schmitzm/lang/tree/OperationTreeParser.java	2009-12-09 14:46:29 UTC (rev 606)
+++ branches/2.0-RC1/src/schmitzm/lang/tree/OperationTreeParser.java	2009-12-09 15:13:42 UTC (rev 607)
@@ -29,7 +29,10 @@
  ******************************************************************************/
 package schmitzm.lang.tree;
 
+import java.util.HashMap;
+import java.util.Map;
 import java.util.NoSuchElementException;
+import java.util.Vector;
 
 import org.apache.log4j.Logger;
 
@@ -41,6 +44,8 @@
 import schmitzm.lang.tree.OperationTree.MultiParamOperatorNode;
 import schmitzm.lang.tree.OperationTree.OperatorNode;
 import schmitzm.lang.tree.OperationTree.UnaryOperatorNode;
+import schmitzm.swing.ParserOperatorsHints;
+import schmitzm.swing.SwingUtil;
 
 /**
  * Diese Klasse stellt einen Parser fuer einen {@linkplain OperationTree Operator-Baum}
@@ -133,7 +138,7 @@
  * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
  * @version 1.0
  */
-public class OperationTreeParser {
+public class OperationTreeParser implements ParserOperatorsHints {
   private Logger LOG = Logger.getLogger(this.getClass());
 
   /** Ergebnis-Typ von {@link #checkRuleClosing(String)}. */
@@ -162,6 +167,16 @@
    */
   protected String delimiter    = null;
 
+  /** Contains the operators available to create a valid rule.<br>
+   *  <b>Note: These operators do not effect the parsing process, but
+   *     only used for user/GUI interaction. */
+  protected Vector<String>  avOperators = new Vector<String>();
+
+  /** Contains a resource key postfix for each operator in {@link #avOperators},
+   *  because not all operators (e.g. "=") can be used as resource key in
+   *  property files. */
+  protected Map<String,String>  avOperatorsKeys = new HashMap<String,String>();
+
   /**
    * Erzeugt eine neue Instanz des Parsers.
    */
@@ -171,6 +186,7 @@
                 getStringEncapsulationChars() +
                 getParameterSeperatorChars() +
                 getOperatorChars() + "\n";
+    initOperatorList();
   }
 
   ///////////////////////////////////////////////////////////////////
@@ -1136,4 +1152,156 @@
     while ( tok.pushback().trim().equals("") );
   }
 
+  ////////////////////////////////////////////////////////////////
+  /////////////////   ParserOperatorsHints   /////////////////////
+  ////////////////////////////////////////////////////////////////
+  /**
+   * Initialises the list of available operators.
+   * @see #getOperators()
+   * @see #avOperators
+   */
+  protected void initOperatorList() {
+    // Zur Verfuegung stehende Operatoren
+    avOperators.clear();
+    avOperators.add("&");           
+    avOperators.add("|");           
+    avOperators.add("!");           
+    avOperators.add("abs");         
+    avOperators.add("sqrt");        
+    avOperators.add("round");       
+    avOperators.add("trunc");       
+    avOperators.add("isNaN");       
+    avOperators.add("NaN");         
+    avOperators.add("random");      
+    avOperators.add("sin");         
+    avOperators.add("cos");         
+    avOperators.add("tan");         
+    avOperators.add("asin");        
+    avOperators.add("acos");        
+    avOperators.add("atan");        
+    avOperators.add("exp");         
+    avOperators.add("ln");          
+    avOperators.add("log");         
+    avOperators.add("str");         
+    avOperators.add("val");         
+    avOperators.add("len");         
+    avOperators.add("toupper");     
+    avOperators.add("tolower");     
+    avOperators.add("ITE");         
+    avOperators.add("REGEX");       
+    avOperators.add("SUBSTR");      
+    // Die "einfachen Operatoren" and Ende setzen, da diese eigentlich
+    // menuell eingegeben werden und nicht so oft gebraucht werden
+    avOperators.add("+"); 
+    avOperators.add("-"); 
+    avOperators.add("*"); 
+    avOperators.add("/"); 
+    avOperators.add("^"); 
+    avOperators.add("="); 
+    avOperators.add("<>");
+    avOperators.add("<"); 
+    avOperators.add("<=");
+    avOperators.add(">"); 
+    avOperators.add(">=");
+    
+    initOperatorKeys();
+  }
+  
+  /**
+   * Initialises the localisation key list for the available operators.
+   * @see #avOperatorsKeys
+   */
+  protected void initOperatorKeys() {
+    avOperatorsKeys.clear();
+    // Usually the operator can be uses as key for localization...
+    for (String op : avOperators)
+      avOperatorsKeys.put(op,op);
+    // ... but some operators can not be used as keys, so they are replaced
+    // with special keys
+    avOperatorsKeys.put("&","and");
+    avOperatorsKeys.put("|","or");
+    avOperatorsKeys.put("!","not");
+    avOperatorsKeys.put("+","plus");
+    avOperatorsKeys.put("-","minus");
+    avOperatorsKeys.put("*","multiply");
+    avOperatorsKeys.put("/","divide");
+    avOperatorsKeys.put("^","pow");
+    avOperatorsKeys.put("=","eq");
+    avOperatorsKeys.put("<>","ne");
+    avOperatorsKeys.put("<","lt");
+    avOperatorsKeys.put("<=","le");
+    avOperatorsKeys.put(">","gt");
+    avOperatorsKeys.put(">=","ge");
+  }
+  
+  /**
+   * Returns the operators, which are available for creating a
+   * valid rule.<br> 
+   * <b>This method is not used for the parsing process, but only
+   * for GUI/User interaction!</b>  
+   */
+  @Override
+  public Vector<String> getOperators() {
+    return avOperators;
+  }
+
+  /**
+   * Returns a short (internationalised) title for an operator. 
+   * @param operator an operator
+   * @return {@code null} if operator is undefined
+   */
+  @Override
+  public String getOperatorTitle(String operator) {
+    String opKey = avOperatorsKeys.get(operator);
+    if ( opKey == null )
+      return null;
+    return SwingUtil.RESOURCE.getString("OperationTreePanel.OpDesc."+opKey);
+  }
+
+  /**
+   * Returns an (internationalised) description for an operator. 
+   * @param operator an operator
+   * @return {@code null} if operator is undefined
+   */
+  @Override
+  public String getOperatorDescription(String operator) {
+    String opKey = avOperatorsKeys.get(operator);
+    if ( opKey == null )
+      return null;
+    return SwingUtil.RESOURCE.getString("OperationTreePanel.OpTooltip."+opKey);
+  }
+
+  /**
+   * Returns the number of bracked-enclosed parameters for an operator.
+   * @param op an operator
+   * @return {@code 0} if operator is undefined
+   */
+  @Override
+  public int getOperatorParameterCount(String op) {
+    // Funktionen mit einem geklammerten Parameter
+    if (op.equalsIgnoreCase("abs") || op.equalsIgnoreCase("sqrt") ||
+        op.equalsIgnoreCase("round") || op.equalsIgnoreCase("trunc") ||
+        op.equalsIgnoreCase("isNaN") || op.equalsIgnoreCase("sin") ||
+        op.equalsIgnoreCase("cos") || op.equalsIgnoreCase("tan") ||
+        op.equalsIgnoreCase("asin") || op.equalsIgnoreCase("acos") ||
+        op.equalsIgnoreCase("atan") || op.equalsIgnoreCase("exp") ||
+        op.equalsIgnoreCase("ln") || op.equalsIgnoreCase("log") ||
+        op.equalsIgnoreCase("val") || op.equalsIgnoreCase("str") ||
+        op.equalsIgnoreCase("toupper") || op.equalsIgnoreCase("tolower") ||
+        op.equalsIgnoreCase("!") )
+      return 1;
+
+    // Funktionen mit zwei geklammerten Parameter
+    if (op.equalsIgnoreCase("REGEX") )
+      return 2;
+
+    // Funktionen mit drei geklammerten Parameter
+    if (op.equalsIgnoreCase("ITE") || op.equalsIgnoreCase("SUBSTR") )
+      return 3;
+
+    // sonst: Konstante/Alias angenommen
+    return 0;
+  }
+
+
 }

Modified: branches/2.0-RC1/src/schmitzm/swing/ExceptionDialog.java
===================================================================
--- branches/2.0-RC1/src/schmitzm/swing/ExceptionDialog.java	2009-12-09 14:46:29 UTC (rev 606)
+++ branches/2.0-RC1/src/schmitzm/swing/ExceptionDialog.java	2009-12-09 15:13:42 UTC (rev 607)
@@ -32,8 +32,6 @@
 import java.awt.BorderLayout;
 import java.awt.Component;
 import java.awt.Frame;
-import java.awt.Toolkit;
-import java.awt.datatransfer.StringSelection;
 import java.awt.event.ActionEvent;
 import java.awt.event.ActionListener;
 

Modified: branches/2.0-RC1/src/schmitzm/swing/OperationTreePanel.java
===================================================================
--- branches/2.0-RC1/src/schmitzm/swing/OperationTreePanel.java	2009-12-09 14:46:29 UTC (rev 606)
+++ branches/2.0-RC1/src/schmitzm/swing/OperationTreePanel.java	2009-12-09 15:13:42 UTC (rev 607)
@@ -93,32 +93,40 @@
   protected JButton startButton = null;
   /** Auswahl-Liste der zur Verfuegung stehenden Operatoren und Konstanzen. */
   protected SelectionInputOption.Combo<String> operators = null;
+  /** Liefert Informationen ueber die Operatoren, die dem Nutzer in der
+   *  ComboBox zur Verfuegung gestellt werden. */
+  protected ParserOperatorsHints opHints = null;
   /** Enthaelt die in der Operator-Auswahl zur Verfuegung gestellten Operatoren
    *  Konstanten */
-  protected Vector<String>         avOperators     = new Vector<String>();
+  private Vector<String> avOperators     = new Vector<String>();
   /** Enthaelt die in der Operator-Auswahl angezeigen Operatoren Konstanten */
-  protected HashMap<String,String> avOperatorsDesc = new HashMap<String,String>();
+  private HashMap<String,String> avOperatorsTitle = new HashMap<String,String>();
   /** Enthaelt die in der Operator-Auswahl angezeigen Tooltips der Operatoren. */
-  protected HashMap<Object,String> avOperatorsToolTip = new HashMap<Object,String>();
-
+  private HashMap<Object,String> avOperatorsToolTip = new HashMap<Object,String>();
+ 
   private JTextField ruleTextField = null;
   private JComboBox  operatorsComboBox = null;
 
   /**
    * Erzeugt eine neue Eingabe-GUI fuer den {@link OperationTree}.
+   * @param opHints Liefert Informationen ueber die Operatoren, die dem Nutzer in der
+   *                ComboBox zur Verfuegung gestellt werden.
    */
-  public OperationTreePanel() {
-    this(true);
+  public OperationTreePanel(ParserOperatorsHints opHints) {
+    this(opHints,true);
   }
 
   /**
    * Erzeugt eine neue Eingabe-GUI fuer den {@link OperationTree}.
+   * @param opHints Liefert Informationen ueber die Operatoren, die dem Nutzer in der
+   *                ComboBox zur Verfuegung gestellt werden.
    * @param initGUI Flag, ob {@link #initGUI()} am Ende des Konstruktor
    *        aufgerufen werden soll (wenn {@code false} muss die explizit
    *        durch die Unterklasse erfolgen!)
    */
-  protected OperationTreePanel(boolean initGUI) {
+  protected OperationTreePanel(ParserOperatorsHints opHints, boolean initGUI) {
     super();
+    this.opHints = opHints;
     this.setPreferredSize( new Dimension(500,400) );
     this.setLayout( new GridBagLayout() );
 
@@ -127,53 +135,16 @@
     layoutConstraints.put(OPERATOR_COMBOBOX, new GridBagConstraints(1,0,1,1,0.0,0.0,GridBagConstraints.SOUTHEAST, GridBagConstraints.NONE, new Insets(0,10,5,10),0,0));
     layoutConstraints.put(START_BUTTON,      new GridBagConstraints(0,1,1,1,0.0,0.0,GridBagConstraints.WEST, GridBagConstraints.NONE, new Insets(0,10,5,10),0,0));
 
-    // Zur Verfuegung stehende Operatoren
-    avOperators.add("&");            fillOperatorDescMaps("&",       "and");
-    avOperators.add("|");            fillOperatorDescMaps("|",       "or");
-    avOperators.add("!");            fillOperatorDescMaps("!",       "not");
-    avOperators.add("abs");          fillOperatorDescMaps("abs",     "abs");
-    avOperators.add("sqrt");         fillOperatorDescMaps("sqrt",    "sqrt");
-    avOperators.add("round");        fillOperatorDescMaps("round",   "round");
-    avOperators.add("trunc");        fillOperatorDescMaps("trunc",   "trunc");
-    avOperators.add("isNaN");        fillOperatorDescMaps("isNaN",   "isNaN");
-    avOperators.add("NaN");          fillOperatorDescMaps("NaN",     "NaN");
-    avOperators.add("random");       fillOperatorDescMaps("random",  "random");
-    avOperators.add("sin");          fillOperatorDescMaps("sin",     "sin");
-    avOperators.add("cos");          fillOperatorDescMaps("cos",     "cos");
-    avOperators.add("tan");          fillOperatorDescMaps("tan",     "tan");
-    avOperators.add("asin");         fillOperatorDescMaps("asin",    "asin");
-    avOperators.add("acos");         fillOperatorDescMaps("acos",    "acos");
-    avOperators.add("atan");         fillOperatorDescMaps("atan",    "atan");
-    avOperators.add("exp");          fillOperatorDescMaps("exp",     "exp");
-    avOperators.add("ln");           fillOperatorDescMaps("ln",      "ln");
-    avOperators.add("log");          fillOperatorDescMaps("log",     "log");
-    avOperators.add("str");          fillOperatorDescMaps("str",     "str");
-    avOperators.add("val");          fillOperatorDescMaps("val",     "val");
-    avOperators.add("len");          fillOperatorDescMaps("len",     "len");
-    avOperators.add("toupper");      fillOperatorDescMaps("toupper", "toupper");
-    avOperators.add("tolower");      fillOperatorDescMaps("tolower", "tolower");
-    avOperators.add("ITE");          fillOperatorDescMaps("ITE",     "ite");
-    avOperators.add("REGEX");        fillOperatorDescMaps("REGEX",   "regex");
-    avOperators.add("SUBSTR");       fillOperatorDescMaps("SUBSTR",  "substr");
-    // Die "einfachen Operatoren" and Ende setzen, da diese eigentlich
-    // menuell eingegeben werden und nicht so oft gebraucht werden
-    avOperators.add("+");            fillOperatorDescMaps("+",  "plus");
-    avOperators.add("-");            fillOperatorDescMaps("-",  "minus");
-    avOperators.add("*");            fillOperatorDescMaps("*",  "multiply");
-    avOperators.add("/");            fillOperatorDescMaps("/",  "divide");
-    avOperators.add("^");            fillOperatorDescMaps("^",  "pow");
-    avOperators.add("=");            fillOperatorDescMaps("=",  "eq");
-    avOperators.add("<>");           fillOperatorDescMaps("<>", "ne");
-    avOperators.add("<");            fillOperatorDescMaps("<",  "lt");
-    avOperators.add("<=");           fillOperatorDescMaps("<=", "le");
-    avOperators.add(">");            fillOperatorDescMaps(">",  "gt");
-    avOperators.add(">=");           fillOperatorDescMaps(">=", "ge");
     
     // Operatoren filtern
-    for (String op : new Vector<String>(avOperators))
-      if ( !acceptOperator(op) )
-        avOperators.remove(op);
-
+    if ( this.opHints != null )
+      for (String op : opHints.getOperators() )
+        if ( acceptOperator(op) ) {
+          avOperators.add(op);
+          avOperatorsTitle.put(op, opHints.getOperatorTitle(op));
+          avOperatorsToolTip.put(opHints.getOperatorTitle(op), opHints.getOperatorDescription(op));
+        }
+    
     if (initGUI)
       initGUI();
   }
@@ -202,7 +173,7 @@
     String[] opArr  = (String[])avOperators.toArray(new String[0]);
     String[] opDesc = new String[opArr.length];
     for (int i=0; i<opArr.length; i++) {
-      String desc = avOperatorsDesc.get(opArr[i]);
+      String desc = avOperatorsTitle.get(opArr[i]);
       opDesc[i] = (desc == null) ? opArr[i] : desc;
     }
     operators = new SelectionInputOption.Combo<String>(
@@ -245,21 +216,6 @@
   }
 
   /**
-   * Befuellt die Maps fuer Beschreibung und Tooltip der Operatoren
-   * @param op    Operator 
-   * @param opKey key fuer den Operator in der Lokalisation
-   */
-  private void fillOperatorDescMaps(String op, String opKey) {
-    // Operator-Bezeichnung, die in ComboBox angezeigt wird.
-    String desc = SwingUtil.RESOURCE.getString("OperationTreePanel.OpDesc."+opKey);
-    avOperatorsDesc.put(op, desc );
-    // Tooltip zum Operator
-    // --> Map fuer ComboBox-Tooltip muss ueber die in der ComboBox
-    //     angezeigten Werte (also "desc") erstellt werden!
-    avOperatorsToolTip.put(desc, desc+": "+SwingUtil.RESOURCE.getString("OperationTreePanel.OpTooltip."+opKey) );
-  }
-
-  /**
    * Setzt die Labels des Panels neu. Die Beschriftungen werden in einer
    * Map hinterlegt und ueber die Konstanten {@link #RULE_LABEL}, {@link #RULE_TOOLTIP},
    * {@link #OPERATOR_LABEL} und {@link #START_BUTTON} angesprochen.
@@ -361,7 +317,7 @@
     String selection = textField.getSelectedText();
 
     // Anzahl an geklammerten Parametern fuer den Operator ermitteln
-    int parameterCount = getParameterCount(op);
+    int parameterCount = opHints.getOperatorParameterCount(op);
 
     // Bei mehr-stelligen Funktionen, erhaelt die Funktion den selektierten
     // Bereich als ersten Operand
@@ -388,34 +344,4 @@
       textField.setSelectionEnd( selStart + op.length() );
     }
   }
-
-  /**
-   * Liefert die Anzahl an geklammerten Parametern, die ein Operator hat.
-   * @param op Operator
-   */
-  protected int getParameterCount(String op) {
-    // Funktionen mit einem geklammerten Parameter
-    if (op.equalsIgnoreCase("abs") || op.equalsIgnoreCase("sqrt") ||
-        op.equalsIgnoreCase("round") || op.equalsIgnoreCase("trunc") ||
-        op.equalsIgnoreCase("isNaN") || op.equalsIgnoreCase("sin") ||
-        op.equalsIgnoreCase("cos") || op.equalsIgnoreCase("tan") ||
-        op.equalsIgnoreCase("asin") || op.equalsIgnoreCase("acos") ||
-        op.equalsIgnoreCase("atan") || op.equalsIgnoreCase("exp") ||
-        op.equalsIgnoreCase("ln") || op.equalsIgnoreCase("log") ||
-        op.equalsIgnoreCase("val") || op.equalsIgnoreCase("str") ||
-        op.equalsIgnoreCase("toupper") || op.equalsIgnoreCase("tolower") ||
-        op.equalsIgnoreCase("!") )
-      return 1;
-
-    // Funktionen mit zwei geklammerten Parameter
-    if (op.equalsIgnoreCase("REGEX") )
-      return 2;
-
-    // Funktionen mit drei geklammerten Parameter
-    if (op.equalsIgnoreCase("ITE") || op.equalsIgnoreCase("SUBSTR") )
-      return 3;
-
-    // sonst: Konstante/Alias angenommen
-    return 0;
-  }
 }

Modified: branches/2.0-RC1/src/schmitzm/swing/StatusDialog.java
===================================================================
--- branches/2.0-RC1/src/schmitzm/swing/StatusDialog.java	2009-12-09 14:46:29 UTC (rev 606)
+++ branches/2.0-RC1/src/schmitzm/swing/StatusDialog.java	2009-12-09 15:13:42 UTC (rev 607)
@@ -31,7 +31,6 @@
 
 import java.awt.BorderLayout;
 import java.awt.Component;
-import java.awt.Frame;
 import java.awt.event.ActionEvent;
 import java.awt.event.ActionListener;
 import java.util.Vector;

Modified: branches/2.0-RC1/src/schmitzm/swing/SwingUtil.java
===================================================================
--- branches/2.0-RC1/src/schmitzm/swing/SwingUtil.java	2009-12-09 14:46:29 UTC (rev 606)
+++ branches/2.0-RC1/src/schmitzm/swing/SwingUtil.java	2009-12-09 15:13:42 UTC (rev 607)
@@ -29,11 +29,9 @@
  ******************************************************************************/
 package schmitzm.swing;
 
-import java.awt.AlphaComposite;
 import java.awt.BorderLayout;
 import java.awt.Color;
 import java.awt.Component;
-import java.awt.Composite;
 import java.awt.Container;
 import java.awt.Cursor;
 import java.awt.Dimension;
@@ -45,7 +43,6 @@
 import java.awt.Rectangle;
 import java.awt.Toolkit;
 import java.awt.Window;
-import java.awt.geom.Rectangle2D;
 import java.awt.image.BufferedImage;
 import java.text.NumberFormat;
 import java.util.Enumeration;
@@ -1078,12 +1075,13 @@
 		Graphics2D graphics = image.createGraphics();
 		if (bgColor != null)
 			graphics.setBackground(bgColor);
-		Composite composite = graphics.getComposite();
-		graphics.setComposite(AlphaComposite.Clear);
-		Rectangle2D.Double rect = new Rectangle2D.Double(0, 0,
-				image.getWidth(), image.getHeight());
-		graphics.fill(rect);
-		graphics.setComposite(composite);
+		graphics.clearRect(0, 0, image.getWidth(), image.getHeight());
+//		Composite composite = graphics.getComposite();
+//		graphics.setComposite(AlphaComposite.Clear);
+//		Rectangle2D.Double rect = new Rectangle2D.Double(0, 0,
+//				image.getWidth(), image.getHeight());
+//		graphics.fill(rect);
+//		graphics.setComposite(composite);
 	}
 
 	/**
@@ -1097,7 +1095,10 @@
 	 *            it intersects with the paintArea.
 	 */
 	public static void clearAround(Graphics2D graphics, Rectangle paintArea,
-			Rectangle clearArea) {
+			Rectangle clearArea, Color bgColor) {
+		
+		if (bgColor != null)
+			graphics.setBackground(bgColor);
 
 		// Clear left of the painted area if needed
 		if (clearArea.getMinX() < paintArea.getMinX()) {

Modified: branches/2.0-RC1/src/schmitzm/swing/resource/locales/SwingResourceBundle.properties
===================================================================
--- branches/2.0-RC1/src/schmitzm/swing/resource/locales/SwingResourceBundle.properties	2009-12-09 14:46:29 UTC (rev 606)
+++ branches/2.0-RC1/src/schmitzm/swing/resource/locales/SwingResourceBundle.properties	2009-12-09 15:13:42 UTC (rev 607)
@@ -116,9 +116,9 @@
 OperationTreePanel.OpDesc.len=len($TEXT)
 OperationTreePanel.OpDesc.toupper=toupper($TEXT)
 OperationTreePanel.OpDesc.tolower=tolower($TEXT)
-OperationTreePanel.OpDesc.ite=IF .. THEN .. ELSE
-OperationTreePanel.OpDesc.regex=REGEX( $TEXT , REGEX)
-OperationTreePanel.OpDesc.substr=SUBSTRING( $TEXT , $NUMBER , $NUMBER)
+OperationTreePanel.OpDesc.ITE=IF .. THEN .. ELSE
+OperationTreePanel.OpDesc.REGEX=REGEX( $TEXT , REGEX)
+OperationTreePanel.OpDesc.SUBSTR=SUBSTRING( $TEXT , $NUMBER , $NUMBER)
 OperationTreePanel.OpDesc.plus=+
 OperationTreePanel.OpDesc.minus=-
 OperationTreePanel.OpDesc.multiply=*
@@ -130,6 +130,10 @@
 OperationTreePanel.OpDesc.le=<=
 OperationTreePanel.OpDesc.gt=>
 OperationTreePanel.OpDesc.ge=>=
+OperationTreePanel.OpDesc.X=Raster cell X
+OperationTreePanel.OpDesc.Y=Raster cell Y
+OperationTreePanel.OpDesc.NoData=NoData value
+OperationTreePanel.OpDesc.isNoData=isNoData(.)
 
 OperationTreePanel.OpTooltip.and=Returns TRUE only if both arguments is TRUE.
 OperationTreePanel.OpTooltip.or=Returns TRUE is any argument is TRUE.
@@ -169,6 +173,10 @@
 OperationTreePanel.OpTooltip.le=Lesser or equal
 OperationTreePanel.OpTooltip.gt=Greater
 OperationTreePanel.OpTooltip.ge=Greater or equal
+OperationTreePanel.OpTooltip.X=Returns the raster cells X coordinate
+OperationTreePanel.OpTooltip.Y=Returns the raster cells Y coordinate
+OperationTreePanel.OpTooltip.NoData=Constant for the NoData value
+OperationTreePanel.OpTooltip.isNoData=Returns TRUE if cell contains no data.
 
 TranslationAskJDialog.Title=Please translate
 TranslationAskJDialog.ErrorMsg.InvalidCharacterInTranslation = Sorry, but you must not use characters { and } in any text label.

Modified: branches/2.0-RC1/src/schmitzm/swing/resource/locales/SwingResourceBundle_de.properties
===================================================================
--- branches/2.0-RC1/src/schmitzm/swing/resource/locales/SwingResourceBundle_de.properties	2009-12-09 14:46:29 UTC (rev 606)
+++ branches/2.0-RC1/src/schmitzm/swing/resource/locales/SwingResourceBundle_de.properties	2009-12-09 15:13:42 UTC (rev 607)
@@ -115,6 +115,10 @@
 OperationTreePanel.OpDesc.le=<=
 OperationTreePanel.OpDesc.gt=>
 OperationTreePanel.OpDesc.ge=>=
+OperationTreePanel.OpDesc.X=X-Koordinate
+OperationTreePanel.OpDesc.Y=Y-Koordinate
+OperationTreePanel.OpDesc.NoData=NoData
+OperationTreePanel.OpDesc.isNoData=isNoData(.)
 
 OperationTreePanel.OpTooltip.and=Liefert WAHR, wenn beide Argumente WAHR sind. 
 OperationTreePanel.OpTooltip.or=Liefert WAHR, sobald ein Argument WAHR ist.
@@ -140,9 +144,9 @@
 OperationTreePanel.OpTooltip.len=Berechnet die L\u00e4nge eines Texts.
 OperationTreePanel.OpTooltip.toupper=Konvertiert Text in Gro\u00dfbuchstaben.
 OperationTreePanel.OpTooltip.tolower=Konvertiert Text in Kleinbuchstaben.
-OperationTreePanel.OpTooltip.ite=Spezifiziert einen logischen Test.
-OperationTreePanel.OpTooltip.regex=Wertet einen regul\u00e4ren Ausdruck auf einem Text aus.
-OperationTreePanel.OpTooltip.substr=Liefert einen Teil-String.
+OperationTreePanel.OpTooltip.ITE=Spezifiziert einen logischen Test.
+OperationTreePanel.OpTooltip.REGEX=Wertet einen regul\u00e4ren Ausdruck auf einem Text aus.
+OperationTreePanel.OpTooltip.SUBSTR=Liefert einen Teil-String.
 OperationTreePanel.OpTooltip.plus=Addition
 OperationTreePanel.OpTooltip.minus=Subtraktion
 OperationTreePanel.OpTooltip.multiply=Multiplikation
@@ -154,6 +158,10 @@
 OperationTreePanel.OpTooltip.le=Kleiner oder gleich
 OperationTreePanel.OpTooltip.gt=Gr\u00f6\u00dfer als 
 OperationTreePanel.OpTooltip.ge=Gr\u00f6\u00dfer oder gleich
+OperationTreePanel.OpTooltip.X=Liefert die X-Koordinate einer Zelle (in Raster-Koordinaten)
+OperationTreePanel.OpTooltip.Y=Liefert die Y-Koordinate einer Zelle (in Raster-Koordinaten)
+OperationTreePanel.OpTooltip.NoData=Liefert den "NoData"-Wert
+OperationTreePanel.OpTooltip.isNoData=Liefert WAHR, wenn die Zelle keinen Wert beinhaltet
 
 TranslationAskJDialog.Title=Bitte \u00fcbersetzen
 TranslationAskJDialog.ErrorMsg.InvalidCharacterInTranslation = Die Zeichen { und } d\u00fcrfen Sie leider nicht benutzen.

Modified: branches/2.0-RC1/src/schmitzm/swing/resource/locales/SwingResourceBundle_fr.properties
===================================================================
--- branches/2.0-RC1/src/schmitzm/swing/resource/locales/SwingResourceBundle_fr.properties	2009-12-09 14:46:29 UTC (rev 606)
+++ branches/2.0-RC1/src/schmitzm/swing/resource/locales/SwingResourceBundle_fr.properties	2009-12-09 15:13:42 UTC (rev 607)
@@ -101,9 +101,9 @@
 OperationTreePanel.OpTooltip.len=Calcule la longueur d'un texte.
 OperationTreePanel.OpTooltip.toupper=Convertit texte en majuscules.
 OperationTreePanel.OpTooltip.tolower=Convertit texte en minuscules.
-OperationTreePanel.OpTooltip.ite=Sp\u00e9cifie un texte logique.
-OperationTreePanel.OpTooltip.regex=utilise une expression r\u00e9guli\u00e8re sur un texte.
-OperationTreePanel.OpTooltip.substr= Fournit une partie du string.
+OperationTreePanel.OpTooltip.ITE=Sp\u00e9cifie un texte logique.
+OperationTreePanel.OpTooltip.REGEX=utilise une expression r\u00e9guli\u00e8re sur un texte.
+OperationTreePanel.OpTooltip.SUBSTR= Fournit une partie du string.
 OperationTreePanel.OpTooltip.plus=Addition
 OperationTreePanel.OpTooltip.minus=Soustractio
 OperationTreePanel.OpTooltip.multiply=Multiplication

Modified: branches/2.0-RC1/src/skrueger/RasterLegendData.java
===================================================================
--- branches/2.0-RC1/src/skrueger/RasterLegendData.java	2009-12-09 14:46:29 UTC (rev 606)
+++ branches/2.0-RC1/src/skrueger/RasterLegendData.java	2009-12-09 15:13:42 UTC (rev 607)
@@ -28,11 +28,13 @@
  *     Stefan A. Krüger - additional utility classes
  ******************************************************************************/
 package skrueger;
+
 import java.util.Arrays;
 import java.util.HashMap;
 import java.util.LinkedList;
 import java.util.List;
 import java.util.Map;
+import java.util.TreeMap;
 
 import org.apache.log4j.Logger;
 import org.geotools.coverage.grid.GridCoverage2D;
@@ -45,17 +47,23 @@
 import skrueger.i8n.Translation;
 
 /**
- * Holds all the additional information needed to paint a Legend for a RasterLayer.
- * So far, only Legends for one-band raster layers are supported.
- *
+ * Holds all the additional information needed to paint a Legend for a
+ * RasterLayer. So far, only Legends for one-band raster layers are supported.
+ * 
  * @author <a href="mailto:skpublic at wikisquare.de">Stefan Alfons Kr&uuml;ger</a>
- *
- * TODO implements {@link Copyable}
+ * 
+ *         TODO implements {@link Copyable}
  */
-public class RasterLegendData extends HashMap<Double, Translation> {
-	static private final Logger LOGGER = Logger.getLogger(RasterLegendData.class);
+public class RasterLegendData extends TreeMap<Double, Translation> implements
+		Copyable<RasterLegendData> {
+	static private final Logger LOGGER = Logger
+			.getLogger(RasterLegendData.class);
+
 	private Boolean paintGaps = false;
 
+	/**
+	 * Shall bigger gaps be painted between the raster images
+	 */
 	public Boolean isPaintGaps() {
 		return paintGaps;
 	}
@@ -65,49 +73,71 @@
 	}
 
 	/**
-	 * {@link #paintGaps} defines, if gaps should be painted between the legends colors,
-	 * indicating nominal values in the raster (e.g. classifications)
+	 * {@link #paintGaps} defines, if gaps should be painted between the legends
+	 * colors, indicating nominal values in the raster (e.g. classifications)
 	 */
 	public RasterLegendData(boolean paintGaps) {
 		this.paintGaps = paintGaps;
 	}
 
-	public boolean getPaintGaps() {
-		return paintGaps ;
-	}
+	/**
+	 * Returns a new list containing all {@link Double} values that shall apear
+	 * in the legend.
+	 */
+	public List<Double> getSortedKeys() {
+		Double[] array = keySet().toArray(new Double[] {});
 
-	public List<Double> getSortedKeys(){
-		Object[] array = keySet().toArray();
-
 		Arrays.sort(array);
 
 		final LinkedList<Double> linkedList = new LinkedList<Double>();
-		for (Object o : array){
-			linkedList.add( (Double)o);
+		for (Double o : array) {
+			linkedList.add(o);
 		}
 
 		return linkedList;
+	}
 
+	/**
+	 * Creates a sample {@link GridCoverage2D} (size 1x1, WGS84) for each legend
+	 * value. These rasters can be used to do visualize the legend item in the
+	 * corresponding color via {@link GridCoverageRenderer}.
+	 */
+	public Map<Double, GridCoverage2D> createSampleRasters() {
+		Map<Double, GridCoverage2D> sampleRaster = new HashMap<Double, GridCoverage2D>();
+
+		for (Double rasterValue : keySet()) {
+			GridCoverage2D grid = GridUtil.GRID_FAC.create("Legend_"
+					+ rasterValue,
+					new float[][] { { rasterValue.floatValue() } },
+					new Envelope2D(GTUtil.WGS84, 0, 0, 1, 1));
+			sampleRaster.put(rasterValue, grid);
+		}
+		return sampleRaster;
 	}
 
-    /**
-     * Creates a sample {@link GridCoverage2D} (size 1x1, WGS84) for each
-     * legend value.  These rasters can be used to do visualize the
-     * legend item in the corresponding color via {@link GridCoverageRenderer}.
-     */
-    public Map<Double, GridCoverage2D> createSampleRasters() {
-      Map<Double, GridCoverage2D> sampleRaster = new HashMap<Double, GridCoverage2D>();
-      
-      for (Double rasterValue : keySet()) {
-        GridCoverage2D grid = GridUtil.GRID_FAC.create(
-            "Legend_"+rasterValue,
-            new float[][] { { rasterValue.floatValue() } },
-            new Envelope2D(GTUtil.WGS84, 0,0,1,1)
-        );
-        sampleRaster.put(rasterValue, grid);
-      }
-      
-      
-      return sampleRaster;
-    }
+	/**
+	 * Creates a new {@link RasterLegendData} object with identical values
+	 */
+	@Override
+	public RasterLegendData copy() {
+		RasterLegendData copy = (RasterLegendData) super.clone();
+		return copyTo(copy);
+	}
+
+	/**
+	 * Deep-copies all values of this {@link RasterLegendData} to another
+	 * {@link RasterLegendData}
+	 */
+	@Override
+	public RasterLegendData copyTo(RasterLegendData target) {
+		target.clear();
+		
+		target.setPaintGaps(isPaintGaps());
+
+		for (Double o : keySet()) {
+			target.put(new Double(o), get(o).copy());
+		}
+
+		return target;
+	}
 }

Modified: branches/2.0-RC1/src/skrueger/geotools/GeomFilterGenerator.java
===================================================================
--- branches/2.0-RC1/src/skrueger/geotools/GeomFilterGenerator.java	2009-12-09 14:46:29 UTC (rev 606)
+++ branches/2.0-RC1/src/skrueger/geotools/GeomFilterGenerator.java	2009-12-09 15:13:42 UTC (rev 607)
@@ -1,9 +1,8 @@
 package skrueger.geotools;
 
 import java.awt.geom.Point2D;
-import java.util.HashMap;
-import java.util.Map;
 
+import org.apache.log4j.Logger;
 import org.geotools.data.FeatureSource;
 import org.geotools.filter.AbstractFilter;
 import org.geotools.filter.GeometryFilterImpl;
@@ -18,10 +17,13 @@
 
 import schmitzm.geotools.FilterUtil;
 import schmitzm.geotools.JTSUtil;
+import schmitzm.geotools.io.GeoImportUtil;
 
 import com.vividsolutions.jts.geom.Coordinate;
 import com.vividsolutions.jts.geom.Envelope;
+import com.vividsolutions.jts.geom.GeometryFactory;
 import com.vividsolutions.jts.geom.MultiPolygon;
+import com.vividsolutions.jts.geom.Point;
 import com.vividsolutions.jts.geom.Polygon;
 
 /**
@@ -38,17 +40,23 @@
  * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a>
  */
 public abstract class GeomFilterGenerator {
+	private final static Logger LOGGER = Logger
+			.getLogger(GeomFilterGenerator.class);
+
 	/**
 	 * 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>();
 
+	// /**
+	// * Caches the base filter constraint for several
+	// * {@link CoordinateReferenceSystem CoordinateReferenceSystems} and the
+	// Geometry-Type of
+	// */
+	// protected Map<Integer, GeometryFilterImpl> filterCache = new
+	// HashMap<Integer, GeometryFilterImpl>();
+
 	/**
 	 * Creates a new filter generator
 	 * 
@@ -62,11 +70,17 @@
 
 	/**
 	 * Creates a filter containing the base constraint ("right" argument)
-	 * transformed to the given {@link CoordinateReferenceSystem}.
+	 * transformed to the given {@link CoordinateReferenceSystem}.<br>
+	 * Depending on the Geometry type of the targeted layer, the filter may look
+	 * different. For example checking POINT INTERSECTS POLYGON is easy, where
+	 * POINT INTERSECTS LINE will hardly ever hit, so we do
+	 * SMALLBBOXARROUND(POINT) INTERSECTS POLYGON.
 	 * 
 	 * @param crs
 	 *            the {@link CoordinateReferenceSystem} the base constraint is
 	 *            transformed to
+	 * @param Geometry
+	 *            class of the features we want to filter against.
 	 * @param Class
 	 *            the geometry class we are testing against. For point against
 	 *            polygon for example, an intersects is much faster that the
@@ -91,11 +105,16 @@
 		GeometryDescriptor geomDescr = fs.getSchema().getGeometryDescriptor();
 		CoordinateReferenceSystem fsCRS = geomDescr
 				.getCoordinateReferenceSystem();
-		GeometryFilterImpl filter = filterCache.get(fsCRS);
-		if (filter == null) {
-			filter = prepareFilter(fsCRS, geomDescr.getType().getBinding());
-			filterCache.put(fsCRS, filter);
-		}
+		if (fsCRS == null)
+			fsCRS = GeoImportUtil.getDefaultCRS();
+		Class<?> binding = geomDescr.getType().getBinding();
+
+		GeometryFilterImpl filter;
+		// = filterCache.get(fsCRS.hashCode()+binding.hashCode());
+		// if (filter == null) {
+		filter = prepareFilter(fsCRS, binding);
+		// filterCache.put(fsCRS.hashCode()+binding.hashCode(), filter);
+		// }
 		Expression geometry = FilterUtil.FILTER_FAC2.property(geomDescr
 				.getLocalName());
 		filter.setExpression1(geometry);
@@ -108,6 +127,9 @@
 	 * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a>
 	 */
 	public static class BoundingBoxFilterGenerator extends GeomFilterGenerator {
+		private final static Logger LOGGER = Logger
+				.getLogger(BoundingBoxFilterGenerator.class);
+
 		/**
 		 * Holds the base constraint (bounding box {@link Envelope}) relative to
 		 * the {@linkplain GeomFilterGenerator#baseCRS base CRS}.
@@ -157,11 +179,24 @@
 	 * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a>
 	 */
 	public static class PointFilterGenerator extends GeomFilterGenerator {
+		private final static Logger LOGGER = Logger
+				.getLogger(PointFilterGenerator.class);
+
+		private static final GeometryFactory GF = new GeometryFactory(); // TODO
+		// do
+		// we
+		// have
+		// a
+		// application
+		// wide
+		// one?
+
 		/**
 		 * Holds the base constraint (coordinate) relative to the
 		 * {@linkplain GeomFilterGenerator#baseCRS base CRS}.
 		 */
-		protected Coordinate basePoint = null;
+		protected Point basePoint = null;
+
 		private ReferencedEnvelope baseEnv;
 
 		/**
@@ -175,13 +210,13 @@
 		 * @param crs
 		 *            defines the CRS of base point
 		 */
-		public PointFilterGenerator(Coordinate basePoint, double radius,
+		public PointFilterGenerator(Point basePoint, double radius,
 				CoordinateReferenceSystem crs) {
 			super(crs);
 			this.basePoint = basePoint;
-			this.baseEnv = new ReferencedEnvelope(basePoint.x - radius,
-					basePoint.x + radius, basePoint.y - radius, basePoint.y
-							+ radius, crs);
+			this.baseEnv = new ReferencedEnvelope(basePoint.getX() - radius,
+					basePoint.getX() + radius, basePoint.getY() - radius,
+					basePoint.getY() + radius, crs);
 
 		}
 
@@ -191,13 +226,15 @@
 		 * @param basePoint
 		 *            defines the point for the "near point" constraint
 		 * @param dist
-		 *            defines the distance around the base point in base point CRS
+		 *            defines the distance around the base point in base point
+		 *            CRS
 		 * @param crs
 		 *            defines the CRS of base point
 		 */
 		public PointFilterGenerator(Point2D basePoint, double dist,
 				CoordinateReferenceSystem crs) {
-			this(new Coordinate(basePoint.getX(), basePoint.getY()), dist, crs);
+			this(GF.createPoint(new Coordinate(basePoint.getX(), basePoint
+					.getY())), dist, crs);
 		}
 
 		/**
@@ -210,44 +247,37 @@
 		 */
 		protected GeometryFilterImpl prepareFilter(
 				CoordinateReferenceSystem crs, Class<?> geomClass) {
-			Coordinate localCrsPoint = basePoint;
+			Point localCrsPoint = basePoint;
 
 			boolean isPolygonGeometry = (Polygon.class
 					.isAssignableFrom(geomClass) || MultiPolygon.class
 					.isAssignableFrom(geomClass));
 
+			LOGGER.debug("is polygon = " + isPolygonGeometry);
+
 			GeometryFilterImpl filter = (GeometryFilterImpl) FilterUtil.FILTER_FAC
-			.createGeometryFilter(AbstractFilter.GEOMETRY_INTERSECTS);
+					.createGeometryFilter(AbstractFilter.GEOMETRY_INTERSECTS);
 
 			if (isPolygonGeometry) {
-				// we chanck against a polygon with instersects
 
-				if (!CRS.equalsIgnoreMetadata(baseCRS, crs))
-					localCrsPoint = JTSUtil.transformCoordinate(basePoint,
-							baseCRS, crs);
-//
-//				GeometryFilterImpl intersectsFilter = (GeometryFilterImpl) FilterUtil.FILTER_FAC
-//						.createGeometryFilter(AbstractFilter.GEOMETRY_INTERSECTS);
+				localCrsPoint = (Point) JTSUtil.transformGeometry(
+						localCrsPoint, baseCRS, crs);
+
 				filter.setExpression2(FilterUtil.FILTER_FAC2
 						.literal(localCrsPoint));
-//
-//				return intersectsFilter;
 
 			} else {
 				// we check against lines and points with a bbox
-//				GeometryFilterImpl filter = (GeometryFilterImpl) FilterUtil.FILTER_FAC
-//				.createGeometryFilter(AbstractFilter.GEOMETRY_BBOX);
 
-				Envelope bbEnv = baseEnv;
-				if (!CRS.equalsIgnoreMetadata(baseCRS, crs))
-					bbEnv = JTSUtil.transformEnvelope(baseEnv, baseCRS, crs);
+				Envelope bbEnv = JTSUtil.transformEnvelope(baseEnv, baseCRS,
+						crs);
 
 				// Filter fuer Envelope zusammenstellen
 				Expression bbox = FilterUtil.FILTER_FAC
 						.createBBoxExpression(bbEnv);
 				filter.setExpression2(bbox);
 			}
-			
+
 			return filter;
 
 		}

Modified: branches/2.0-RC1/src/skrueger/geotools/MapContextManagerInterface.java
===================================================================
--- branches/2.0-RC1/src/skrueger/geotools/MapContextManagerInterface.java	2009-12-09 14:46:29 UTC (rev 606)
+++ branches/2.0-RC1/src/skrueger/geotools/MapContextManagerInterface.java	2009-12-09 15:13:42 UTC (rev 607)
@@ -33,7 +33,6 @@
 import org.geotools.map.MapContext;
 import org.geotools.map.MapLayer;
 import org.geotools.map.event.MapLayerListListener;
-import org.geotools.map.event.MapLayerListener;
 
 import skrueger.AttributeMetadata;
 import skrueger.RasterLegendData;

Modified: branches/2.0-RC1/src/skrueger/geotools/MapPaneToolBar.java
===================================================================
--- branches/2.0-RC1/src/skrueger/geotools/MapPaneToolBar.java	2009-12-09 14:46:29 UTC (rev 606)
+++ branches/2.0-RC1/src/skrueger/geotools/MapPaneToolBar.java	2009-12-09 15:13:42 UTC (rev 607)
@@ -53,13 +53,12 @@
 import org.apache.log4j.Logger;
 
 import schmitzm.geotools.gui.SelectableXMapPane;
-import schmitzm.geotools.map.event.MapPaneEvent;
 import schmitzm.geotools.map.event.JMapPaneListener;
 import schmitzm.geotools.map.event.MapAreaChangedEvent;
+import schmitzm.geotools.map.event.MapPaneEvent;
 import schmitzm.lang.LangUtil;
 import schmitzm.lang.ResourceProvider;
 import schmitzm.swing.ButtonGroup;
-import schmitzm.swing.SwingUtil;
 import skrueger.swing.SmallButton;
 import skrueger.swing.SmallToggleButton;
 

Modified: branches/2.0-RC1/src/skrueger/geotools/RenderingExecutor.java
===================================================================
--- branches/2.0-RC1/src/skrueger/geotools/RenderingExecutor.java	2009-12-09 14:46:29 UTC (rev 606)
+++ branches/2.0-RC1/src/skrueger/geotools/RenderingExecutor.java	2009-12-09 15:13:42 UTC (rev 607)
@@ -121,9 +121,10 @@
 
 		@Override
 		public void run() {
+			long startT = System.currentTimeMillis();
 			try {
 				renderer.addRenderListener(this);
-				LOGGER.debug("start rendering...");
+//				LOGGER.debug("start rendering...");
 
 				// Clear the graphics context
 				graphics.setBackground(mapPane.getMapBackgroundColor());
@@ -135,7 +136,7 @@
 				// Kill the reference to this Thread so #isRunning will say
 				// false directly
 				renderThread = null;
-				mapPane.onRenderingCompleted();
+				mapPane.onRenderingCompleted(System.currentTimeMillis()-startT);
 			} catch (Exception e) {
 				mapPane.onRenderingFailed(e);
 			} finally {

Modified: branches/2.0-RC1/src/skrueger/geotools/SelectXMapPaneMouseListener.java
===================================================================
--- branches/2.0-RC1/src/skrueger/geotools/SelectXMapPaneMouseListener.java	2009-12-09 14:46:29 UTC (rev 606)
+++ branches/2.0-RC1/src/skrueger/geotools/SelectXMapPaneMouseListener.java	2009-12-09 15:13:42 UTC (rev 607)
@@ -13,7 +13,6 @@
 import org.apache.log4j.Logger;
 import org.geotools.data.memory.MemoryFeatureCollection;
 import org.geotools.feature.FeatureCollection;
-import org.geotools.geometry.jts.ReferencedEnvelope;
 import org.geotools.map.MapLayer;
 import org.opengis.feature.simple.SimpleFeature;
 import org.opengis.feature.simple.SimpleFeatureType;
@@ -28,6 +27,8 @@
 import com.vividsolutions.jts.geom.GeometryFactory;
 
 public class SelectXMapPaneMouseListener extends MouseAdapter {
+	private static Logger LOGGER = Logger
+	.getLogger(SelectXMapPaneMouseListener.class);
 
 	private final SelectableXMapPane xMapPane;
 	private boolean enabled;
@@ -251,7 +252,5 @@
 		this.enabled = enabled;
 	}
 
-	private static Logger LOGGER = Logger
-			.getLogger(SelectXMapPaneMouseListener.class);
 
 }

Modified: branches/2.0-RC1/src/skrueger/geotools/StyledFS.java
===================================================================
--- branches/2.0-RC1/src/skrueger/geotools/StyledFS.java	2009-12-09 14:46:29 UTC (rev 606)
+++ branches/2.0-RC1/src/skrueger/geotools/StyledFS.java	2009-12-09 15:13:42 UTC (rev 607)
@@ -41,7 +41,6 @@
 
 import org.apache.log4j.Logger;
 import org.geotools.data.FeatureSource;
-import org.geotools.data.store.EmptyFeatureCollection;
 import org.geotools.feature.FeatureCollection;
 import org.geotools.styling.Style;
 import org.opengis.feature.simple.SimpleFeature;
@@ -303,12 +302,18 @@
 
 	@Override
 	public FeatureCollection<SimpleFeatureType, SimpleFeature> getFeatureCollectionFiltered() {
-		final FeatureCollection<SimpleFeatureType, SimpleFeature> fc = getFeatureCollection();
-		if (filter == Filter.EXCLUDE)
-			return new EmptyFeatureCollection(fc.getSchema());
-		if (filter == Filter.INCLUDE)
-			return fc;
-		return fc.subCollection(filter);
+//		final FeatureCollection<SimpleFeatureType, SimpleFeature> fc = getFeatureCollection();
+//		if (filter == Filter.EXCLUDE)
+//			return new EmptyFeatureCollection(fc.getSchema());
+//		if (filter == Filter.INCLUDE)
+//			return fc;
+//		return fc.subCollection(filter);
+		
+		try {
+			return getFeatureSource().getFeatures(filter);
+		} catch (IOException e) {
+			throw new RuntimeException(e);
+		}
 	}
 
 	@Override

Modified: branches/2.0-RC1/src/skrueger/geotools/StyledFeatureCollectionTableModel.java
===================================================================
--- branches/2.0-RC1/src/skrueger/geotools/StyledFeatureCollectionTableModel.java	2009-12-09 14:46:29 UTC (rev 606)
+++ branches/2.0-RC1/src/skrueger/geotools/StyledFeatureCollectionTableModel.java	2009-12-09 15:13:42 UTC (rev 607)
@@ -120,7 +120,7 @@
 			if (amdm != null) {
 				Vector<String> visibleAttrNames = new Vector<String>();
 
-				// Add the column with the geometry (usually "the_geom")
+				// Add the column with the geometry (usually "the_geom") always
 				visibleAttrNames.add(schema.getGeometryDescriptor()
 						.getLocalName());
 
@@ -129,37 +129,16 @@
 					visibleAttrNames.add(a.getLocalName());
 				}
 
-				// for (AttributeDescriptor aDesc :
-				// schema.getAttributeDescriptors()) {
-				//					
-				// // Always add the geometry
-				// if (schema.getGeometryDescriptor()
-				// .getName().equals(aDesc.getName())) {
-				// visibleAttrNames.add(schema.getGeometryDescriptor()
-				// .getLocalName());
-				// continue;
-				// }
-				//					
-				// if (amd.get(aDesc.getName()).isVisible())
-				// visibleAttrNames.add(aDesc.getName().getLocalPart());
-				// }
-				//
-				// // create a query for the visible attributes
-				String[] properties = visibleAttrNames.toArray(new String[] {});
-				//
-				// LOGGER.debug("Query contains the following attributes: "
-				// + visibleAttrNames);
-
-				/**
-				 * I got NPEs when properties contained only [the_geom] ?!??!!??
-				 * TODO Try again one day... Not today... 20.11.2009, SK
-				 */
-				if (properties.length > 1) {
+//			Tested with 2.6.x trunk from 2009-11-26 and it now works. So we only request the properties we need!			
+// 				/**
+//				 * I got NPEs when properties contained only [the_geom] ?!??!!??
+//				 */
+//				if (properties.length > 1) {
 					query = new DefaultQuery(schema.getTypeName(), filter,
-							properties);
-				} else {
-					query = new DefaultQuery(schema.getTypeName(), filter);
-				}
+							visibleAttrNames.toArray(new String[] {}));
+//				} else {
+//					query = new DefaultQuery(schema.getTypeName(), filter);
+//				}
 			}
 			fc = fs.getFeatures(query);
 		}

Modified: branches/2.0-RC1/src/skrueger/geotools/StyledLayerUtil.java
===================================================================
--- branches/2.0-RC1/src/skrueger/geotools/StyledLayerUtil.java	2009-12-09 14:46:29 UTC (rev 606)
+++ branches/2.0-RC1/src/skrueger/geotools/StyledLayerUtil.java	2009-12-09 15:13:42 UTC (rev 607)
@@ -43,6 +43,7 @@
 import java.io.FileWriter;
 import java.net.URL;
 import java.text.DecimalFormat;
+import java.util.ArrayList;
 import java.util.List;
 import java.util.Map;
 
@@ -78,6 +79,8 @@
 import org.jdom.output.XMLOutputter;
 import org.opengis.feature.simple.SimpleFeature;
 import org.opengis.feature.simple.SimpleFeatureType;
+import org.opengis.feature.type.AttributeDescriptor;
+import org.opengis.feature.type.GeometryDescriptor;
 import org.opengis.feature.type.Name;
 import org.opengis.parameter.GeneralParameterValue;
 
@@ -245,13 +248,15 @@
 	 * @param visible
 	 *            indicated whether the visible or invisible entries are
 	 *            returned
-	 *            
-	 * TODO replace with {@link AttributeMetadataMap#sortedValuesVisibleOnly()}
+	 * 
+	 *            TODO replace with
+	 *            {@link AttributeMetadataMap#sortedValuesVisibleOnly()}
 	 */
 	public static AttributeMetadataMap getVisibleAttributeMetaData(
 			final AttributeMetadataMap amdMap, final boolean visible) {
 
-		final AttributeMetadataMap filteredMap = new AttributeMetadataMap(amdMap.getLanguages());
+		final AttributeMetadataMap filteredMap = new AttributeMetadataMap(
+				amdMap.getLanguages());
 		for (final AttributeMetadata amd : amdMap.values())
 			if (amd.isVisible() == visible)
 				filteredMap.put(amd.getName(), amd);
@@ -993,7 +998,7 @@
 		final Map<Double, GridCoverage2D> sampleRasters = rasterLegendData
 				.createSampleRasters();
 
-		final JPanel panel = new JPanel(new MigLayout("wrap 2"));
+		final JPanel panel = new JPanel(new MigLayout("wrap 2, gapy 0"));
 
 		for (final Double rValue : legendRasterValues) {
 
@@ -1082,19 +1087,16 @@
 			}
 
 			final JLabel iconLabel = new JLabel(new ImageIcon(buffImage));
-			// hbox.setAlignmentX(0f);
 			panel.add(iconLabel, "sgx1");
-			// hbox.add(Box.createHorizontalStrut(3));
 
 			final Translation labelT = rasterLegendData.get(rValue);
 			final JLabel classTitleLabel = new JLabel(labelT.toString());
 			panel.add(classTitleLabel, "sgx2"
-					+ (rasterLegendData.getPaintGaps() ? ", gapy 0 3" : ""));
+					+ (rasterLegendData.isPaintGaps() ? ", gapy 0:0:0 5:5:5"
+							: ""));
 			classTitleLabel.setLabelFor(iconLabel);
 
-			// box.add(hbox);
-
-			if (rasterLegendData.getPaintGaps()) {
+			if (rasterLegendData.isPaintGaps()) {
 				iconLabel
 						.setBorder(BorderFactory.createLineBorder(Color.black));
 			}
@@ -1152,10 +1154,11 @@
 	public static boolean isStyleable(
 			final StyledRasterInterface<?> styledRaster) {
 		final ColorModel colorModel = getColorModel(styledRaster);
-		
-//		LOGGER.info("The colormodel of " + styledRaster.getTitle() + " is "
-//				+ colorModel != null ? colorModel.getClass().getSimpleName() : "NULL");
 
+		// LOGGER.info("The colormodel of " + styledRaster.getTitle() + " is "
+		// + colorModel != null ? colorModel.getClass().getSimpleName() :
+		// "NULL");
+
 		if (colorModel == null)
 			return true;
 		if (colorModel instanceof ComponentColorModel)
@@ -1170,35 +1173,95 @@
 	 * Remember {@link MapLayer#setStyle(Style)} triggers an event leading to a
 	 * repaint, so only use it when needed.
 	 * 
-	 * @return <code>true</code> if the {@link MapLayer}'s {@link Style} has been changed.
+	 * @return <code>true</code> if the {@link MapLayer}'s {@link Style} has
+	 *         been changed.
 	 */
-	public static boolean updateMapLayerStyleIfChangedAndKeepSelection(MapLayer mapLayer,
-			Style style2) {
+	public static boolean updateMapLayerStyleIfChangedAndKeepSelection(
+			MapLayer mapLayer, Style style2) {
 
 		Style mapLayerStyleCleaned = StylingUtil
-						.removeSelectionFeatureTypeStyle(mapLayer.getStyle());
-		
-		Style newStyleCleaned = StylingUtil.removeSelectionFeatureTypeStyle(style2);
-		
-		if (StylingUtil.isStyleDifferent(mapLayerStyleCleaned,
-				newStyleCleaned)) {
-			
+				.removeSelectionFeatureTypeStyle(mapLayer.getStyle());
+
+		Style newStyleCleaned = StylingUtil
+				.removeSelectionFeatureTypeStyle(style2);
+
+		if (StylingUtil.isStyleDifferent(mapLayerStyleCleaned, newStyleCleaned)) {
+
 			// They are different when compared without SELECTION FTS!
-			
+
 			// Now let's copy any SELECTION FTS to the now style
-			FeatureTypeStyle selectionFeatureTypeStyle = StylingUtil.getSelectionFeatureTypeStyle( mapLayer.getStyle() );
+			FeatureTypeStyle selectionFeatureTypeStyle = StylingUtil
+					.getSelectionFeatureTypeStyle(mapLayer.getStyle());
 			if (selectionFeatureTypeStyle != null) {
-				newStyleCleaned.featureTypeStyles().add(selectionFeatureTypeStyle);
-				// newStyleCleaned is not so clean anymore... We just alled a selcetion FTS
-			}  
-			
+				newStyleCleaned.featureTypeStyles().add(
+						selectionFeatureTypeStyle);
+				// newStyleCleaned is not so clean anymore... We just alled a
+				// selcetion FTS
+			}
+
 			mapLayer.setStyle(newStyleCleaned);
-			
+
 			return true;
-			
+
 		} else {
 			return false;
 		}
 	}
 
+	/**
+	 * After loading an atlas, the AttribteMetaData contains whatever is written
+	 * in the XML. But the DBF may have changed! This method checks an
+	 * {@link AttributeMetadataMap} against a schema and also corrects
+	 * upperCase/lowerCase problems. It will also remove any geometry column
+	 * attribute metadata.
+	 */
+	/**
+	 * After loading an atlas, the AttribteMetaData contains whatever is written
+	 * in the XML. But the DBF may have changed!
+	 */
+	public static void checkAttribMetaData(AttributeMetadataMap attributeMetaDataMap,
+			SimpleFeatureType schema) {
+
+		ArrayList<Name> willRemove = new ArrayList<Name>();
+
+		// 1. Check.. all attributes in the atm should be in the schema as well.
+		// maybe correct some upperCase/loweCase stuff
+
+		for (AttributeMetadata atm : attributeMetaDataMap.values()) {
+
+			AttributeDescriptor foundDescr = schema
+					.getDescriptor(atm.getName());
+			if (foundDescr == null) {
+				Name bestMatch = FeatureUtil.findBestMatchingAttribute(schema,
+						atm.getLocalName());
+				if (bestMatch == null)
+					willRemove.add(atm.getName());
+				else
+					atm.setName(bestMatch);
+			} else if (foundDescr instanceof GeometryDescriptor) {
+				// We don't want GeometryColumns in here
+				willRemove.add(atm.getName());
+			}
+		}
+
+		// Remove the ones that were not findable in the schema
+		for (Name removeName : willRemove) {
+			if (attributeMetaDataMap.remove(removeName) == null){
+				LOGGER.warn("removing the AMData didn't work");
+			}
+		}
+
+		// 2. check... all attributes from the schema must have an ATM
+		for (AttributeDescriptor ad : schema.getAttributeDescriptors()) {
+			if (ad instanceof GeometryDescriptor)
+				continue;
+			if (!attributeMetaDataMap.containsKey(ad.getName())) {
+				attributeMetaDataMap.put(ad.getName(), new AttributeMetadata(
+						ad, schema.getAttributeDescriptors().indexOf(ad), attributeMetaDataMap
+								.getLanguages()));
+			}
+		}
+
+	}
+
 }

Modified: branches/2.0-RC1/src/skrueger/geotools/XMapPane.java
===================================================================
--- branches/2.0-RC1/src/skrueger/geotools/XMapPane.java	2009-12-09 14:46:29 UTC (rev 606)
+++ branches/2.0-RC1/src/skrueger/geotools/XMapPane.java	2009-12-09 15:13:42 UTC (rev 607)
@@ -26,11 +26,12 @@
 import java.util.Map;
 import java.util.Vector;
 
-import javax.jws.soap.SOAPBinding.Style;
+import javax.swing.JList;
 import javax.swing.Timer;
 import javax.swing.border.Border;
 
 import org.apache.log4j.Logger;
+import org.geotools.factory.GeoTools;
 import org.geotools.feature.FeatureCollection;
 import org.geotools.geometry.jts.JTS;
 import org.geotools.geometry.jts.ReferencedEnvelope;
@@ -97,8 +98,11 @@
  */
 public class XMapPane extends JPanel {
 
-	private static final int IMAGETYPE = BufferedImage.TYPE_INT_RGB;
-	private static final int IMAGETYPE_withAlpha = BufferedImage.TYPE_INT_ARGB;
+	// private static final int IMAGETYPE = BufferedImage.TYPE_INT_RGB;
+	// private static final int IMAGETYPE_withAlpha =
+	// BufferedImage.TYPE_INT_ARGB;
+	private static final int IMAGETYPE = BufferedImage.TYPE_3BYTE_BGR;
+	private static final int IMAGETYPE_withAlpha = BufferedImage.TYPE_4BYTE_ABGR;
 
 	private final static Logger LOGGER = Logger.getLogger(XMapPane.class);
 
@@ -217,7 +221,7 @@
 	 * 
 	 * @see #addGadgets(Graphics2D, boolean)
 	 */
-	final static Font waitFont = new Font("Arial", Font.BOLD, 30);
+	final static Font waitFont = new Font("Arial", Font.BOLD, 28);
 
 	/**
 	 * {@link Font} used to paint error messages into the map
@@ -227,6 +231,12 @@
 	final static Font errorFont = new Font("Arial", Font.BOLD, 13);
 
 	/**
+	 * If last average last two renderings took more than that many ms, show the
+	 * user a scaled preview
+	 **/
+	private static final long PRESCALE_MINTIME = 230;
+
+	/**
 	 * The wait message painted into the map while rendering is going on on
 	 * another thread.
 	 * 
@@ -278,7 +288,7 @@
 
 		@Override
 		public void layerAdded(final MapLayerListEvent event) {
-			MapLayer layer = event.getLayer();
+			final MapLayer layer = event.getLayer();
 			layer.addMapLayerListener(bgMapLayerListener);
 			requestStartRendering();
 
@@ -404,8 +414,7 @@
 
 		@Override
 		public void layerChanged(final MapLayerListEvent event) {
-//			localRenderer = GTUtil.createGTRenderer();
-			getLocalRenderer().setContext(getMapContext());
+//			getLocalRenderer().setContext(getMapContext()); geht doch auch ohne?!?!? wow...
 			requestStartRendering();
 		}
 
@@ -426,16 +435,17 @@
 
 	/**
 	 * Listens to each layer in the local {@link MapContext} for changes and
-	 * triggers repaints.
+	 * triggers repaints. We don't have to listen layerChanged, because that is
+	 * already done in {@link #localContextListener}
 	 */
 	protected MapLayerListener localMapLayerListener = new MapLayerAdapter() {
 
-		@Override
-		public void layerChanged(final MapLayerEvent event) {
-			getLocalRenderer().setContext(getMapContext()); // betters for SLD
-			// changes?!
-			requestStartRendering();
-		}
+		// @Override
+		// public void layerChanged(final MapLayerEvent event) {
+		// // getLocalRenderer().setContext(getMapContext()); // betters for SLD
+		// // // changes?!
+		// // requestStartRendering();
+		// }
 
 		@Override
 		public void layerHidden(final MapLayerEvent event) {
@@ -518,7 +528,7 @@
 	private BufferedImage preFinalImage;
 
 	// ** if 0, no quick preview will be shown **/
-	private int quickPreviewHint = 0;
+	// private int quickPreviewHint = 0;
 
 	private Map<Object, Object> rendererHints = GTUtil
 			.getDefaultGTRendererHints(getLocalRenderer());
@@ -619,22 +629,27 @@
 						if (!isWellDefined())
 							return;
 
-						LOGGER.debug("resizeTimer performed");
+						// LOGGER.debug("resizeTimer performed");
 
-						final Rectangle bounds = getVisibleRect();
+						// final Rectangle bounds = getVisibleRect();
 						//
 						// System.out.println("\n\ntimer performs with bounds = "
 						// + bounds);
 
-						final Envelope geoMapArea = tranformWindowToGeo(
-								bounds.x, bounds.y, bounds.x + bounds.width,
-								bounds.y + bounds.height);
+						// final Envelope geoMapArea = tranformWindowToGeo(
+						// bounds.x, bounds.y, bounds.x + bounds.width,
+						// bounds.y + bounds.height);
 
-						if (setMapArea(geoMapArea)) {
-							LOGGER.debug("  maparea changed");
-							paneResized = true;
-						} else
-							LOGGER.debug("  maparea NOT changed");
+						paneResized = true;
+						if (!setMapArea(getMapArea())) {
+							// It's important to request new rendering here.
+							// setMapArea only returns true and only calls
+							// requestStartRendering if the maparea has changed.
+							// But if the component is resized, the maparea
+							// doesn't have to change.
+							requestStartRendering();
+						}
+
 					}
 				});
 		resizeTimer.setRepeats(false);
@@ -649,11 +664,11 @@
 				// Seems to be called twice with the same size..
 				if (oldVisibleRect != null
 						&& oldVisibleRect.equals(getVisibleRect())) {
-					LOGGER.debug("skipping resize.");
+					// LOGGER.debug("skipping resize.");
 					return;
 				}
 
-				LOGGER.debug("resized: " + getVisibleRect());
+				// LOGGER.debug("resized: " + getVisibleRect());
 				resizeTimer.restart();
 				oldVisibleRect = getVisibleRect();
 			}
@@ -997,25 +1012,17 @@
 	 * 
 	 * @param g
 	 *            Graphics2D to paint the preview into
-	 * 
-	 * @param state
-	 *            Max be {@link #ZOOM_IN} or {@link #ZOOM_OUT}
 	 */
 	protected boolean drawScaledPreviewImage_Zoom(final Graphics2D graphics) {
 
 		// if (1 == 1)return false;
+		// if (quickPreviewHint == 0)
+		// return false;
 
-		if (quickPreviewHint == 0)
+		if (oldMapArea == null)
 			return false;
 
-		graphics.setRenderingHint(RenderingHints.KEY_INTERPOLATION,
-				RenderingHints.VALUE_INTERPOLATION_NEAREST_NEIGHBOR);
-		graphics.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
-				RenderingHints.VALUE_ANTIALIAS_OFF);
-		graphics.setRenderingHint(RenderingHints.KEY_RENDERING,
-				RenderingHints.VALUE_RENDER_SPEED);
-
-		if (oldMapArea == null)
+		if (getPreFinalImage() == null)
 			return false;
 
 		final Rectangle visibleArea = getVisibleRect();
@@ -1030,6 +1037,13 @@
 		final int xx2 = (int) Math.round(oldMapWindow.getMaxX());
 		final int yy2 = (int) Math.round(oldMapWindow.getMaxY());
 
+		graphics.setRenderingHint(RenderingHints.KEY_INTERPOLATION,
+				RenderingHints.VALUE_INTERPOLATION_NEAREST_NEIGHBOR);
+		graphics.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
+				RenderingHints.VALUE_ANTIALIAS_OFF);
+		graphics.setRenderingHint(RenderingHints.KEY_RENDERING,
+				RenderingHints.VALUE_RENDER_SPEED);
+
 		graphics.drawImage(getPreFinalImage(), xx1, yy1, xx2, yy2,
 				(int) visibleArea.getMinX(), (int) visibleArea.getMinY(),
 				(int) visibleArea.getMaxX(), (int) visibleArea.getMaxY(),
@@ -1038,16 +1052,15 @@
 		final Rectangle painedArea = new Rectangle(xx1, yy1, xx2 - xx1, yy2
 				- yy1);
 
-		SwingUtil.clearAround(graphics, painedArea, visibleArea);
+		SwingUtil.clearAround(graphics, painedArea, visibleArea,
+				getMapBackgroundColor());
 
 		addGadgets(graphics, true);
 
-		quickPreviewHint = 0;
+		// quickPreviewHint = 0;
 
 		repaintTimer.restart();
 
-		graphics.dispose();
-
 		// Something has been drawn
 		return true;
 	}
@@ -1060,10 +1073,11 @@
 	 * Lazyly initializes a {@link BufferedImage} for the background renderer.
 	 */
 	private Image getBgImage() {
-		//
-		// if (bgImage == null) {
-		// bgImage = createImage(getBounds().width, getBounds().height);
-		// }
+		if (bgImage == null) {
+			bgImage = new BufferedImage(getVisibleRect().width,
+					getVisibleRect().height, IMAGETYPE);
+			SwingUtil.clearImage(finalImage, getMapBackgroundColor());
+		}
 
 		return bgImage;
 	}
@@ -1081,16 +1095,13 @@
 			// Rectangle curPaintArea = getVisibleRect();
 			finalImage = new BufferedImage(getVisibleRect().width,
 					getVisibleRect().height, IMAGETYPE);
+			SwingUtil.clearImage(finalImage, getMapBackgroundColor());
 
-			requestStartRendering();
+			// requestStartRendering();
 		}
 		return finalImage;
 	}
 
-	public RenderingHints getJava2dHints() {
-		return java2dHints;
-	}
-
 	/**
 	 * Lazyly initializes a {@link BufferedImage} for the background renderer.
 	 */
@@ -1099,6 +1110,7 @@
 		if (localImage == null) {
 			localImage = new BufferedImage(getVisibleRect().width,
 					getVisibleRect().height, IMAGETYPE_withAlpha);
+			SwingUtil.clearImage(localImage, getMapBackgroundColor());
 		}
 
 		return localImage;
@@ -1140,7 +1152,7 @@
 			try {
 				localContext.setCoordinateReferenceSystem(GeoImportUtil
 						.getDefaultCRS());
-			} catch (Exception e) {
+			} catch (final Exception e) {
 				throw new RuntimeException("setting context CRS:", e);
 			}
 
@@ -1186,23 +1198,26 @@
 
 	public Envelope getMaxExtend() {
 		if (maxExtend == null) {
-			// Commented-out because it takes soo much time!
-			//
+
+			// The next command may take long time!
 			// long start = System.currentTimeMillis();
-			// final ReferencedEnvelope layerBounds = GTUtil
-			// .getVisibleLayoutBounds(localContext);
+			final ReferencedEnvelope layerBounds = GTUtil
+					.getVisibleLayoutBounds(localContext);
 			//			
 			// LOGGER.info(
 			// (System.currentTimeMillis()-start)+"m to get maxExtend");
 			//			
-			// if (layerBounds == null) {
-			// // TODO Last fallback could be the CRS valid area
-			// return null;
-			// }
-			//
-			// // Kartenbereich um 10% vergroessern
+			if (layerBounds == null) {
+				// // TODO Last fallback could be the CRS valid area
+				return null;
+			}
+
+			// Vergrößerung um 10% nochmal rausgenommen
+			// // // Kartenbereich um 10% vergroessern
 			// return JTSUtil.fixAspectRatio(getVisibleRect(), JTSUtil
 			// .expandEnvelope(layerBounds, 0.1), true);
+
+			return JTSUtil.fixAspectRatio(getVisibleRect(), layerBounds, true);
 		}
 		return maxExtend;
 	}
@@ -1230,16 +1245,6 @@
 	}
 
 	private Image getPreFinalImage() {
-		// if (preFinalImage == null) {
-		//			
-		// // Rectangle curPaintArea = getVisibleRect();
-		// // preFinalImage = new BufferedImage(curPaintArea.width,
-		// // curPaintArea.height, BufferedImage.TYPE_INT_RGB);
-		//			
-		// preFinalImage = createImage(getBounds().width, getBounds().height);
-		//
-		// requestStartRendering();
-		// }
 		return preFinalImage;
 	}
 
@@ -1408,7 +1413,7 @@
 				|| (getState() == XMapPane.SELECT_TOP)) {
 
 			// Draws a rectangle
-			final Graphics graphics = getGraphics();
+			final Graphics2D graphics = (Graphics2D) getGraphics();
 			drawRectangle(graphics, startPos, event.getPoint());
 			if ((lastPos.x > 0) && (lastPos.y > 0))
 				drawRectangle(graphics, startPos, lastPos);
@@ -1420,16 +1425,22 @@
 	 * Called by the {@link RenderingExecutor} when rendering was cancelled.
 	 */
 	public void onRenderingCancelled() {
-		LOGGER.debug("Rendering cancelled");
+		// LOGGER.debug("Rendering cancelled");
 		repaintTimer.stop();
 	}
 
 	/**
 	 * Called by the {@link RenderingExecutor} when rendering has been
 	 * completed.
+	 * 
+	 * @param l
+	 *            long ms the rendering took
 	 */
-	public void onRenderingCompleted() {
-		LOGGER.debug("complete");
+	public void onRenderingCompleted(final long l) {
+		lastRenderingDuration = (lastRenderingDuration + l) / 2;
+		LOGGER
+				.debug("complete rendering after " + lastRenderingDuration
+						+ "ms");
 
 		repaintTimer.stop();
 
@@ -1481,8 +1492,15 @@
 
 		if (!isWellDefined())
 			return;
+		//
+		// if (paneResized) {
+		// // ((Graphics2D) g).setBackground(getMapBackgroundColor());
+		// // g.clearRect(0, 0, getVisibleRect().width,
+		// getVisibleRect().height);
+		// return;
+		// }
 
-//		 super.paintComponent(g); // candidate for removal
+		// super.paintComponent(g); // candidate for removal
 
 		boolean paintedSomething = false;
 
@@ -1493,19 +1511,21 @@
 			// If the new mapArea and the oldMapArea intersect, we can draw some
 			// quick scaled preview to make the user feel that something is
 			// happening.
-			if (mapAreaChanged && oldMapArea != null
+			if (lastRenderingDuration > PRESCALE_MINTIME && mapAreaChanged
+					&& oldMapArea != null
 					&& getMapArea().intersects(oldMapArea)
-					& !getMapArea().equals(oldMapArea) && !paneResized) {
+					&& !getMapArea().equals(oldMapArea) && !paneResized) {
 
 				mapAreaChanged = false;
 
-				if (getMapArea().covers(oldMapArea)) {
-					quickPreviewHint = ZOOM_OUT;
-					paintedSomething = drawScaledPreviewImage_Zoom((Graphics2D) g);
-				} else if (oldMapArea.covers(getMapArea())) {
-					quickPreviewHint = ZOOM_IN;
-					paintedSomething = drawScaledPreviewImage_Zoom((Graphics2D) g);
-				}
+				// if (getMapArea().covers(oldMapArea)) {
+				// // quickPreviewHint = ZOOM_OUT;
+				// paintedSomething = drawScaledPreviewImage_Zoom((Graphics2D)
+				// g);
+				// } else if (oldMapArea.covers(getMapArea())) {
+				// quickPreviewHint = ZOOM_IN;
+				paintedSomething = drawScaledPreviewImage_Zoom((Graphics2D) g);
+				// }
 			}
 		}
 
@@ -1513,8 +1533,6 @@
 
 			g.drawImage(getFinalImage(), 0, 0, null);
 
-			g.dispose(); // cand. for removal
-
 			paintedSomething = true; // cand. for removal
 		}
 
@@ -1570,7 +1588,7 @@
 	 */
 	public void performPan() {
 
-		Rectangle winBounds = getVisibleRect();
+		final Rectangle winBounds = getVisibleRect();
 
 		winBounds.translate(-imageOrigin.x, -imageOrigin.y);
 		final Envelope newMapArea = tranformWindowToGeo(winBounds.x,
@@ -1638,7 +1656,7 @@
 	 *            the current map pane extent (screen units)
 	 */
 	private void resetTransforms() {
-		ReferencedEnvelope refMapEnv = new ReferencedEnvelope(mapArea,
+		final ReferencedEnvelope refMapEnv = new ReferencedEnvelope(mapArea,
 				getMapContext().getCoordinateReferenceSystem());
 
 		// System.out
@@ -1652,7 +1670,7 @@
 		try {
 			screenToWorld = worldToScreen.createInverse();
 
-		} catch (NoninvertibleTransformException ex) {
+		} catch (final NoninvertibleTransformException ex) {
 			LOGGER
 					.error("can't invert worldToScreen to get screenToWorld!",
 							ex);
@@ -1721,9 +1739,9 @@
 		requestStartRendering();
 
 	}
-	
-	public void setBorder(Border b) {
-	  super.setBorder(b);
+
+	public void setBorder(final Border b) {
+		super.setBorder(b);
 	}
 
 	/**
@@ -1746,12 +1764,13 @@
 	// repaint();
 	// }
 
-    /**
-     * Set the new map area.
-     * @param newMapArea
-     * @return <code>true</code> if the mapArea has been changed and a repaint
-     *         has been triggered.
-     */
+	/**
+	 * Set the new map area.
+	 * 
+	 * @param newMapArea
+	 * @return <code>true</code> if the mapArea has been changed and a repaint
+	 *         has been triggered.
+	 */
 	public boolean setMapArea(final Envelope newMapArea) {
 		if (newMapArea == null)
 			return false;
@@ -1762,7 +1781,8 @@
 	}
 
 	/**
-     * Set the new map area.
+	 * Set the new map area.
+	 * 
 	 * @param newMapArea
 	 * @return <code>true</code> if the mapArea has been changed and a repaint
 	 *         has been triggered.
@@ -1837,7 +1857,7 @@
 	 * 
 	 * @param if <code>null</code>, white is used.
 	 */
-	public void setMapBackgroundColor(Color bgColor) {
+	public void setMapBackgroundColor(final Color bgColor) {
 		this.mapBackgroundColor = bgColor;
 	}
 
@@ -1895,7 +1915,7 @@
 	}
 
 	// /** Stored the time used for the last real rendering in ms. **/
-	// private long lastRenderingDuration = Long.MAX_VALUE;
+	private long lastRenderingDuration = 1000;
 
 	/**
 	 * Set the minimum (nearest) allowed zoom scale. This is the bigger number
@@ -2020,6 +2040,10 @@
 		updateCursor();
 	}
 
+	private RenderingHints getJava2dHints() {
+		return java2dHints;
+	}
+
 	/**
 	 * Transformiert einen Geo-Koordinaten-Bereich in Fenster-Koordinaten.
 	 * 
@@ -2159,12 +2183,12 @@
 		finalG.drawImage(getPreFinalImage(), imageOrigin.x, imageOrigin.y,
 				getMapBackgroundColor(), null);
 
-		final int finalImageHeight = getFinalImage().getHeight(null);
-		final int finalImageWidth = getFinalImage().getWidth(null);
-
+		// When panning, we have to clear the area around the image
 		final Rectangle painedArea = new Rectangle(imageOrigin.x,
-				imageOrigin.y, finalImageWidth, finalImageHeight);
-		SwingUtil.clearAround(finalG, painedArea, getVisibleRect());
+				imageOrigin.y, getFinalImage().getWidth(), getFinalImage()
+						.getHeight());
+		SwingUtil.clearAround(finalG, painedArea, getVisibleRect(),
+				getMapBackgroundColor());
 
 		addGadgets(finalG, false);
 
@@ -2183,11 +2207,11 @@
 	 *            <code>false</code>, it will only depend on
 	 *            {@link #localExecuter.isRunning} and #bgExecuter.isRunning
 	 */
-	private void addGadgets(final Graphics2D graphics, boolean forceWait) {
+	private void addGadgets(final Graphics2D graphics, final boolean forceWait) {
 
 		// Paint a logo to the bottom right if available
 		if (mapImage != null) {
-			Rectangle visibleRect = getVisibleRect();
+			final Rectangle visibleRect = getVisibleRect();
 			graphics.drawImage(mapImage, visibleRect.width
 					- mapImage.getWidth() - 10, getVisibleRect().height
 					- mapImage.getHeight() - 10, null);
@@ -2213,7 +2237,7 @@
 
 			graphics.setColor(c);
 
-			y += 24;
+			y += 21;
 		}
 
 		if (!renderingErrors.isEmpty() && isShowExceptions()) {
@@ -2221,7 +2245,7 @@
 			final Color c = graphics.getColor();
 			graphics.setFont(errorFont);
 
-			for (Exception ex : renderingErrors) {
+			for (final Exception ex : renderingErrors) {
 
 				String errStr = ex.getLocalizedMessage();
 
@@ -2258,7 +2282,7 @@
 		final CoordinateReferenceSystem mapCRS = getMapContext()
 				.getCoordinateReferenceSystem();
 		final CoordinateReferenceSystem fCRS = features.getSchema()
-				.getGeometryDescriptor().getCoordinateReferenceSystem();
+				.getCoordinateReferenceSystem();
 
 		ReferencedEnvelope _mapArea;
 		if (mapArea == null)
@@ -2376,11 +2400,12 @@
 				.getWidth()) / 2., (mapArea.getHeight() * zoomFaktor - mapArea
 				.getHeight()) / 2.);
 
-		// TODO we actually want that
-		// // Move the newMapArea above the new center
-		// newMapArea.translate(gcenter.getX() - mapArea.centre().x, gcenter
-		// .getY()
-		// - mapArea.centre().y);
+		// // Move the newMapArea above the new center if we zoom in:
+		if (zoomFaktor >= 1) {
+			newMapArea.translate(gcenter.getX() - mapArea.centre().x, gcenter
+					.getY()
+					- mapArea.centre().y);
+		}
 
 		setMapArea(newMapArea);
 	}
@@ -2389,7 +2414,7 @@
 	 * Shall non-fatal rendering exceptions be reported in the mappane or be
 	 * dropped quitely.
 	 */
-	public void setShowExceptions(boolean showExceptions) {
+	public void setShowExceptions(final boolean showExceptions) {
 		this.showExceptions = showExceptions;
 	}
 
@@ -2404,4 +2429,166 @@
 		return localRenderer;
 	}
 
+
+
+	/**
+	 * Setzt den Kartenausschnitt auf die Ausdehnung eines bestimmten Layers.
+	 * Macht nichts, wenn {@code null} uebergeben wird.
+	 * 
+	 * <br>
+	 * 
+	 * @param layer
+	 *            ein Layer
+	 */
+	public void zoomToLayer(MapLayer layer) {
+		if (layer == null)
+			return;
+		try {
+
+			// BB umrechnen von Layer-CRS in Map-CRS
+			final CoordinateReferenceSystem targetCRS = getMapContext()
+					.getCoordinateReferenceSystem();
+			final CoordinateReferenceSystem sourceCRS = layer
+					.getFeatureSource().getSchema()
+					.getCoordinateReferenceSystem();
+
+			Envelope mapAreaNew;
+			if (!CRS.equalsIgnoreMetadata(sourceCRS, targetCRS)) {
+				mapAreaNew = JTSUtil.transformEnvelope(layer.getFeatureSource()
+						.getBounds(), sourceCRS, targetCRS);
+			} else {
+				try {
+					mapAreaNew = layer.getFeatureSource().getBounds();
+				} catch (java.lang.IllegalArgumentException e) {
+					LOGGER.error("Can't calc layers bounds...", e);
+					mapAreaNew = null;
+
+					/**
+					 * 
+					 23.10.2009 11:20:50
+					 * org.geotools.data.shapefile.shp.PolygonHandler read
+					 * WARNUNG: only one hole in this polygon record ERROR
+					 * JMapPane zoomToLayer Zoom to layer did not terminate
+					 * correctly java.lang.IllegalArgumentException: Points of
+					 * LinearRing do not form a closed linestring at
+					 * com.vividsolutions
+					 * .jts.geom.LinearRing.validateConstruction
+					 * (LinearRing.java:105) at
+					 * com.vividsolutions.jts.geom.LinearRing
+					 * .<init>(LinearRing.java:100) at
+					 * com.vividsolutions.jts.geom
+					 * .GeometryFactory.createLinearRing
+					 * (GeometryFactory.java:339) at
+					 * org.geotools.data.shapefile.
+					 * shp.PolygonHandler.read(PolygonHandler.java:188) at
+					 * org.geotools
+					 * .data.shapefile.shp.ShapefileReader$Record.shape
+					 * (ShapefileReader.java:106) at
+					 * org.geotools.data.shapefile.
+					 * ShapefileAttributeReader.next(
+					 * ShapefileAttributeReader.java:157) at
+					 * org.geotools.data.shapefile
+					 * .indexed.IndexedShapefileAttributeReader
+					 * .next(IndexedShapefileAttributeReader.java:122) at
+					 * org.geotools
+					 * .data.FIDFeatureReader.next(FIDFeatureReader.java:96) at
+					 * org.geotools.data.FIDFeatureReader.next(FIDFeatureReader.
+					 * java:55) at org.geotools.data.MaxFeatureReader.next(
+					 * MaxFeatureReader.java:61) at
+					 * org.geotools.data.MaxFeatureReader
+					 * .next(MaxFeatureReader.java:61)
+					 **/
+				}
+			}
+
+			// Kartenbereich um 10% vergroessern, damit z.B. auch ein
+			// Punkt-Layer,
+			// welches nur aus 2 Punnkten besteht, sichtbar ist (Punkte liegen
+			// sonst
+			// genau auf dem Rand der angezeigten Flaeche)
+
+			if (mapAreaNew != null) {
+				mapAreaNew.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.error("Zoom to layer did not terminate correctly", err);
+		}
+	}
+
+	/**
+	 * Zooms the {@link SelectableXMapPane} to the {@link Envelope} of a layer.
+	 * 
+	 * <br>
+	 * A refresh of the map is not done automatically
+	 * 
+	 * @param index
+	 *            Index of the {@link MapLayer} in the {@link MapContext} (from
+	 *            back to top)
+	 * 
+	 * @author <a href="mailto:skpublic at wikisquare.de">Stefan Alfons
+	 *         Kr&uuml;ger</a>
+	 */
+	public void zoomToLayer(int index) {
+		final MapContext context = getMapContext();
+		if (context != null)
+			zoomToLayer(context.getLayer(index));
+	}
+
+	/**
+	 * Zooms the {@link SelectableXMapPane} to the {@link Envelope} of the
+	 * selected layer. The layer is selected by the idx, counting from front to
+	 * back, like humans would expect in a {@link JList}
+	 * 
+	 * <br>
+	 * A refresh of the map is not done automatically
+	 * 
+	 * 
+	 * 
+	 * @param index
+	 *            Reverse index of the {@link MapLayer} in the
+	 *            {@link MapContext}
+	 * 
+	 * @author <a href="mailto:skpublic at wikisquare.de">Stefan Alfons
+	 *         Kr&uuml;ger</a>
+	 */
+	public void zoomToLayerIdxReverse(int index) {
+		zoomToLayer(getMapContext().getLayerCount() - 1 - index);
+	}
+
+	
+	
+
+
+	/**
+	 * Aktiviert oder deaktiviert das AntiAliasing for diese
+	 * {@link SelectableXMapPane}. AntiALiasing ist besonders fuer
+	 * Textbeschriftung sehr schoen, verbraucht aber auch mehr Performance.
+	 * 
+	 * @author <a href="mailto:skpublic at wikisquare.de">Stefan Alfons
+	 *         Kr&uuml;ger</a>
+	 */
+	public void setAntiAliasing(final boolean aa) {
+		// LOGGER.info("Setting AntiAliasing for this JMapPane to " + aa);
+		RenderingHints java2DHints = java2dHints;
+		if (java2DHints == null) {
+			java2DHints = GeoTools.getDefaultHints();
+		}
+		
+		java2DHints.put(RenderingHints.KEY_ANTIALIASING,
+				aa ? RenderingHints.VALUE_ANTIALIAS_ON
+						: RenderingHints.VALUE_ANTIALIAS_OFF);
+		java2DHints.put(RenderingHints.KEY_TEXT_ANTIALIASING,
+				aa ? RenderingHints.VALUE_TEXT_ANTIALIAS_ON
+						: RenderingHints.VALUE_TEXT_ANTIALIAS_OFF);
+		java2DHints.put(RenderingHints.KEY_RENDERING,
+				aa ? RenderingHints.VALUE_RENDER_QUALITY
+						: RenderingHints.VALUE_RENDER_SPEED);
+		
+	}
+
 }

Modified: branches/2.0-RC1/src/skrueger/geotools/ZoomXMapPaneMouseListener.java
===================================================================
--- branches/2.0-RC1/src/skrueger/geotools/ZoomXMapPaneMouseListener.java	2009-12-09 14:46:29 UTC (rev 606)
+++ branches/2.0-RC1/src/skrueger/geotools/ZoomXMapPaneMouseListener.java	2009-12-09 15:13:42 UTC (rev 607)
@@ -4,7 +4,6 @@
 import java.awt.Graphics;
 import java.awt.Point;
 import java.awt.Rectangle;
-import java.awt.event.InputEvent;
 import java.awt.event.MouseAdapter;
 import java.awt.event.MouseEvent;
 import java.awt.event.MouseWheelEvent;
@@ -21,13 +20,13 @@
 	private static Logger LOGGER = Logger
 			.getLogger(ZoomXMapPaneMouseListener.class);
 
-
 	protected final XMapPane xMapPane;
 
 	protected boolean enabled = true;
 
 	public ZoomXMapPaneMouseListener(XMapPane xMapPane) {
-		if (xMapPane == null) throw new IllegalArgumentException("xMapPane may not be null");
+		if (xMapPane == null)
+			throw new IllegalArgumentException("xMapPane may not be null");
 		this.xMapPane = xMapPane;
 	}
 
@@ -35,11 +34,11 @@
 	 * Stores beginning of a drag event in window coordinates
 	 */
 	protected Point startPos;
-	
+
 	/**
 	 * Stores last position of a drag event in window coordinates
 	 */
-	protected  Point lastPos;
+	protected Point lastPos;
 
 	/**
 	 * Draws a rectangle in XOR mode from the origin at {@link #startPos} to the
@@ -72,6 +71,21 @@
 		if (!isEnabled())
 			return;
 
+		// If this is a click, let mouseClicked handle it!
+		if ((Math.abs(startPos.x - e.getPoint().x) * Math.abs(e.getPoint().y
+				- startPos.y)) < 160) {
+			// xMapPane.zoomTo(e.getPoint(), .5);
+			return;
+		}
+
+		
+		// Not the best check.. but works
+		if (xMapPane.getCursor() == SwingUtil.PANNING_CURSOR)
+		{
+			xMapPane.performPan();
+			return;
+		}
+
 		final Rectangle bounds = xMapPane.getBounds();
 
 		Envelope mapArea = xMapPane.getMapArea();
@@ -89,20 +103,10 @@
 		final double endY = (((bounds.getHeight() - e.getPoint().y) * mapHeight) / (double) bounds.height)
 				+ mapArea.getMinY();
 
-		if ((xMapPane.getState() == XMapPane.PAN)
-				|| (e.getButton() == MouseEvent.BUTTON3)) {
-			xMapPane.performPan();
+		if (xMapPane.getState() == XMapPane.ZOOM_IN) {
 
-		} else if (xMapPane.getState() == XMapPane.ZOOM_IN) {
-
 			drawRectangle(xMapPane.getGraphics(), e.getPoint());
 
-			// Don't zoom too small areas. Handle it like a click then
-			if ((Math.abs(startPos.x - e.getPoint().x) * Math.abs(e.getPoint().y - startPos.y)) < 160) {
-				xMapPane.zoomTo(e.getPoint(), .5);
-				return;
-			}
-
 			final double left = Math.min(startX, endX);
 			final double right = Math.max(startX, endX);
 			final double bottom = Math.min(startY, endY);
@@ -116,15 +120,14 @@
 
 			// Remove the rectangle
 			drawRectangle(xMapPane.getGraphics(), e.getPoint());
-			
-			
+			//
+			// // Don't zoom too small areas
+			// if ((Math.abs(startPos.x - e.getPoint().x) * Math
+			// .abs(e.getPoint().y - startPos.y)) < 100) {
+			// xMapPane.zoomTo(e.getPoint(), 2.);
+			// return;
+			// }
 
-			// Don't zoom too small areas
-			if ((Math.abs(startPos.x - e.getPoint().x) * Math.abs(e.getPoint().y - startPos.y)) < 100) {
-				xMapPane.zoomTo(e.getPoint(), 2.);
-				return;
-			}
-
 			// make the dragged rectangle in screen coords the new map size?
 			final double left = Math.min(startX, endX);
 			final double right = Math.max(startX, endX);
@@ -148,10 +151,8 @@
 			xMapPane.setMapArea(new Envelope(ll, ur));
 		}
 
-
 	}
 
-
 	public void setEnabled(boolean enabled) {
 		this.enabled = enabled;
 	}
@@ -163,7 +164,7 @@
 	public boolean isEnabled() {
 		return enabled && xMapPane.isWellDefined();
 	}
-	
+
 	/**
 	 * Verarbeitet die Mausrad-Aktion, indem gezoomed wird.
 	 * 
@@ -171,7 +172,8 @@
 	 *            Mausrad-Event
 	 */
 	public void mouseWheelMoved(MouseWheelEvent wheelEvt) {
-		if (!isEnabled()) return;
+		if (!isEnabled())
+			return;
 
 		final int units = wheelEvt.getUnitsToScroll();
 		if (units > 0)
@@ -239,12 +241,10 @@
 	public void mouseDragged(final MouseEvent event) {
 		if (!isEnabled())
 			return;
-		
+
 		xMapPane.mouseDragged(startPos, lastPos, event);
 
-
 		lastPos = event.getPoint();
 	}
 
-
 }

Modified: branches/2.0-RC1/src/skrueger/geotools/labelsearch/LabelSearch.java
===================================================================
--- branches/2.0-RC1/src/skrueger/geotools/labelsearch/LabelSearch.java	2009-12-09 14:46:29 UTC (rev 606)
+++ branches/2.0-RC1/src/skrueger/geotools/labelsearch/LabelSearch.java	2009-12-09 15:13:42 UTC (rev 607)
@@ -40,16 +40,17 @@
 import org.geotools.data.DefaultQuery;
 import org.geotools.data.FeatureSource;
 import org.geotools.feature.FeatureCollection;
+import org.geotools.filter.text.cql2.CQL;
+import org.geotools.filter.text.cql2.CQLException;
 import org.geotools.map.MapLayer;
 import org.geotools.styling.Style;
 import org.geotools.styling.TextSymbolizer;
 import org.opengis.feature.simple.SimpleFeature;
 import org.opengis.feature.simple.SimpleFeatureType;
-import org.opengis.feature.type.AttributeDescriptor;
 import org.opengis.filter.Filter;
-import org.opengis.filter.expression.Expression;
 import org.opengis.filter.expression.PropertyName;
 
+import schmitzm.geotools.feature.FeatureUtil;
 import schmitzm.geotools.styling.StylingUtil;
 import schmitzm.lang.LangUtil;
 import schmitzm.lang.ResourceProvider;
@@ -79,32 +80,9 @@
 		this.mapPane = mapPane;
 	}
 
-	/**
-	 * The Attribute that provides the labels for this text symbolizer.
-	 */
-	private AttributeDescriptor getLabelAttribute(final TextSymbolizer ts,
-			final SimpleFeatureType schema) {
-		if (ts == null) {
-			// This layer has no labels
-			return null;
-		}
-
-		final Expression labelExp = ts.getLabel();
-		if (labelExp instanceof PropertyName) {
-			final PropertyName pn = (PropertyName) labelExp;
-			final String propertyName = pn.getPropertyName();
-			return schema.getDescriptor(propertyName);
-		} else {
-			// When does this happen
-			throw new RuntimeException("labelExp " + labelExp
-					+ " IS NOT instanceof PropertyName!");
-		}
-
-	}
-
 	public List<SearchResult> search(final String string) {
 
-		final String searchMe = string.toLowerCase();
+		final String searchMe = string.toUpperCase();
 
 		final ArrayList<SearchResult> hits = new ArrayList<SearchResult>();
 
@@ -124,96 +102,89 @@
 					continue;
 				}
 
+				// We only deal with one TextSymbolizer so far:
+				TextSymbolizer ts = allTS.get(0);
+
 				final FeatureSource<SimpleFeatureType, SimpleFeature> featureSource = (FeatureSource<SimpleFeatureType, SimpleFeature>) ml
 						.getFeatureSource();
 
-				final String typeName = featureSource.getSchema().getName()
-						.getLocalPart();
+				SimpleFeatureType schema = featureSource.getSchema();
 
-				// Expression labelExp = ts.getLabel();
-				// ff.like(labelExp, "*"+searchMe+"*");
-				// FeatureCollection features =
-				// ml.getFeatureSource().getFeatures(
-				// new DefaultQuery(typeName, ff.like(labelExp,
-				// "*"+searchMe+"*"), properties));
+				final String typeName = schema.getName().getLocalPart();
 
-				final FeatureCollection<SimpleFeatureType, SimpleFeature> features = featureSource
-						.getFeatures(new DefaultQuery(typeName, Filter.INCLUDE));
+				PropertyName prop1 = StylingUtil.getFirstPropertyName(schema,
+						ts);
+				PropertyName prop2 = StylingUtil.getSecondPropertyName(schema,
+						ts);
 
-				// new MemoryDataStore().getFeatureSource(typeName)
+				if (StylingUtil.getFirstPropertyName(schema, ts) == null) {
+					// At least one property field we need
+					continue;
+				}
 
-				/**
-				 * We do the comparison NOT with a ff.like, because that doesn't
-				 * support case insensitivity and i don't find a lower or UPPER
-				 * function.
-				 */
-				final Iterator<SimpleFeature> fi = features.iterator();
-				try {
+				Filter searchFilter;
+				String[] properties = new String[] { schema.getGeometryDescriptor().getLocalName(), prop1.getPropertyName() };
+				// Only one property used...
 
-					while (fi.hasNext()) {
-						final SimpleFeature f = fi.next();
+				searchFilter = CQL.toFilter("strToUpperCase "
+						+ prop1.getPropertyName() + " LIKE '%" + searchMe
+						+ "%'");
 
-						final TextSymbolizer ts = StylingUtil
-								.getTextSymbolizer(ml.getStyle(), f);
-						if (ts == null)
-							continue;
+				if (prop2 != null) {
+					Filter searchFilter2 = CQL.toFilter("strToUpperCase "
+							+ prop2.getPropertyName() + " LIKE '%" + searchMe
+							+ "%'");
 
-						// TODO Evaluate the Rule that belongs to the
-						// TextSymbolizer against the feature...
-						final AttributeDescriptor labelAttribute = getLabelAttribute(
-								ts, featureSource.getSchema());
+					searchFilter = FeatureUtil.FILTER_FACTORY2.or(searchFilter,
+							searchFilter2);
 
-						if (labelAttribute == null) {
-							continue;
-						}
+					properties = LangUtil.extendArray(properties, prop2
+							.getPropertyName());
+				}
 
-						// System.out.println("labelAttrib local name" +
-						// labelAttribute.getLocalName());
+				// Add the layer's filter if it exists
+				Filter layerFilter = ml.getQuery().getFilter();
+				if (layerFilter != null && layerFilter != Filter.INCLUDE) {
+					searchFilter = FeatureUtil.FILTER_FACTORY2.and(layerFilter,
+							searchFilter);
+				}
+				
+//				LOGGER.info("Searching for "+searchFilter.toString());
 
-						final Object value = f.getAttribute(labelAttribute
-								.getLocalName());
+				FeatureCollection<SimpleFeatureType, SimpleFeature> features = (FeatureCollection<SimpleFeatureType, SimpleFeature>) ml
+						.getFeatureSource().getFeatures(
+								new DefaultQuery(typeName, searchFilter,
+										properties));
 
-						// System.out.println("labelAttrib value " + value);
+				final Iterator<SimpleFeature> fi = features.iterator();
+				try {
+					while (fi.hasNext()) {
+						final SimpleFeature f = fi.next();
 
-						if (value == null) {
-							LOGGER
-									.info("Skipping f: getLocalName() is null for feature="
-											+ f);
-							continue;
-						}
+						String valueString = "";
+						valueString = f.getAttribute(prop1.getPropertyName())
+								.toString();
 
-						/**
-						 * LabelString ist z.B. "IMPETUS pluviograph". Suchwort
-						 * "plu" soll treffen. Also wird nach spaces zerlegt und
-						 * dann gesucht
-						 */
-						final String labelString = value.toString()
-								.toLowerCase();
-						if (labelString.startsWith(searchMe)) {
-							hits.add(createSearchResult(f, value.toString(), ml
-									.getTitle(), ml));
-						} else {
-							final String[] parts = labelString.trim()
-									.split(" ");
-							for (final String part : parts) {
-								if (part.startsWith(searchMe)) {
-									hits.add(createSearchResult(f, value
-											.toString(), ml.getTitle(), ml));
-									break;
-								}
-							}
+						if (prop2 != null) {
+							String valueString2 = f.getAttribute(
+									prop2.getPropertyName()).toString();
+
+							if (valueString2 != null && !valueString2.isEmpty())
+								valueString += ", " + valueString2;
 						}
 
+						hits.add(createSearchResult(f, valueString, ml
+								.getTitle(), ml));
 					}
 				} finally {
 					features.close(fi);
 				}
-
 			} catch (final IOException e) {
 				// Searching this layer failed
-				LOGGER.error(e);
+				LOGGER.error("",e);
+			} catch (CQLException e) {
+				LOGGER.error("",e);
 			}
-
 		} // next layer
 
 		// Hits from the top-most layer should appear first.

Modified: branches/2.0-RC1/src/skrueger/geotools/selection/FeatureMapLayerSelectionSynchronizer.java
===================================================================
--- branches/2.0-RC1/src/skrueger/geotools/selection/FeatureMapLayerSelectionSynchronizer.java	2009-12-09 14:46:29 UTC (rev 606)
+++ branches/2.0-RC1/src/skrueger/geotools/selection/FeatureMapLayerSelectionSynchronizer.java	2009-12-09 15:13:42 UTC (rev 607)
@@ -42,11 +42,9 @@
  **/
 package skrueger.geotools.selection;
 
-import java.awt.RenderingHints;
 import java.beans.PropertyChangeEvent;
 import java.beans.PropertyChangeListener;
 import java.io.File;
-import java.util.HashMap;
 import java.util.HashSet;
 import java.util.Iterator;
 import java.util.Set;
@@ -60,9 +58,6 @@
 import org.geotools.feature.FeatureIterator;
 import org.geotools.filter.FidFilterImpl;
 import org.geotools.map.MapLayer;
-import org.geotools.renderer.GTRenderer;
-import org.geotools.renderer.label.LabelCacheImpl;
-import org.geotools.renderer.lite.StreamingRenderer;
 import org.geotools.styling.FeatureTypeStyle;
 import org.geotools.styling.Style;
 import org.geotools.styling.visitor.DuplicatingStyleVisitor;
@@ -73,7 +68,6 @@
 import org.opengis.filter.identity.FeatureId;
 
 import schmitzm.geotools.FilterUtil;
-import schmitzm.geotools.GTUtil;
 import schmitzm.geotools.gui.SelectableXMapPane;
 import schmitzm.geotools.map.event.FeatureSelectedEvent;
 import schmitzm.geotools.map.event.JMapPaneListener;

Modified: branches/2.0-RC1/src/skrueger/i8n/SwitchLanguageDialog.java
===================================================================
--- branches/2.0-RC1/src/skrueger/i8n/SwitchLanguageDialog.java	2009-12-09 14:46:29 UTC (rev 606)
+++ branches/2.0-RC1/src/skrueger/i8n/SwitchLanguageDialog.java	2009-12-09 15:13:42 UTC (rev 607)
@@ -83,10 +83,8 @@
 	/**
 	 * A dialog to select one of the available languages. If only one language
 	 * is available, select it directly. Creating this object automatically
-	 * makes it visible.
-	 * 
-	 * @param owner
-	 * @param atlasConfig
+	 * makes it visible, unless there is only one language to choose from.. it
+	 * that case it disposes itself autmatically.
 	 */
 	public SwitchLanguageDialog(final Component owner,
 			final List<String> languages) {
@@ -98,6 +96,8 @@
 		if (languages.size() == 1) {
 			LOGGER.debug("Only language '" + languages.get(0)
 					+ "' is available. It has been selected automatically.");
+//			dispose();
+			setModal(false);
 			return;
 		}
 
@@ -111,12 +111,14 @@
 	 */
 	private void initialize() {
 		this.setContentPane(getJContentPane());
-		setModal(true);
-		SwingUtil.centerFrameOnScreenRandom(this);
 
 		setDefaultCloseOperation(JDialog.DO_NOTHING_ON_CLOSE);
 
 		pack();
+
+		SwingUtil.centerFrameOnScreenRandom(this);
+		setModal(true);
+		setVisible(true);
 	}
 
 	/**
@@ -213,7 +215,7 @@
 			gridBagConstraints.gridy = 0;
 			jLabel = new JLabel();
 			jLabel.setText("Select language: "); // i8n!?! Maybe replace with an
-													// icon of an index finger
+			// icon of an index finger
 			jPanel1 = new JPanel();
 			jPanel1.setLayout(new GridBagLayout());
 			jPanel1.add(jLabel, gridBagConstraints);
@@ -286,4 +288,4 @@
 		return jComboBox;
 	}
 
-} 
+}

Modified: branches/2.0-RC1/src/skrueger/i8n/Translation.java
===================================================================
--- branches/2.0-RC1/src/skrueger/i8n/Translation.java	2009-12-09 14:46:29 UTC (rev 606)
+++ branches/2.0-RC1/src/skrueger/i8n/Translation.java	2009-12-09 15:13:42 UTC (rev 607)
@@ -39,6 +39,7 @@
 import java.util.List;
 import java.util.Locale;
 import java.util.Random;
+import java.util.WeakHashMap;
 
 import javax.swing.JComponent;
 
@@ -64,7 +65,8 @@
 	static final Logger LOGGER = Logger.getLogger(Translation.class);
 	static String activeLang = Locale.getDefault().getLanguage();
 
-	static protected List<PropertyChangeListener> listeners = new ArrayList<PropertyChangeListener>();
+	static protected WeakHashSet<PropertyChangeListener> listeners = new WeakHashSet<PropertyChangeListener>(
+			PropertyChangeListener.class);
 
 	static {
 
@@ -143,7 +145,8 @@
 
 		fireLocaleChangeEvents();
 
-		LOGGER.info("skrueger.i8n.Translation switched ActiveLang to " + newLang);
+		LOGGER.info("skrueger.i8n.Translation switched ActiveLang to "
+				+ newLang);
 	}
 
 	/**
@@ -284,9 +287,13 @@
 
 	/**
 	 * {@link PropertyChangeListener} can be registered to be informed when the
-	 * {@link Locale} changed.
+	 * {@link Locale} changed.<br>
+	 * The listeners are kept in a {@link WeakHashMap}, so you have to keep a
+	 * reference to the listener or it will be removed!
 	 * 
 	 * @param propertyChangeListener
+	 *            A {@link PropertyChangeListener} that will be called when
+	 *            {@link #setActiveLang(String)} changes the language.
 	 */
 	public static void addLocaleChangeListener(
 			PropertyChangeListener propertyChangeListener) {
@@ -294,6 +301,21 @@
 	}
 
 	/**
+	 * {@link PropertyChangeListener} can be registered to be informed when the
+	 * {@link Locale} changed.<br>
+	 * The listeners are kept in a {@link WeakHashMap}, so you have to keep a
+	 * reference to the listener or it will be removed!
+	 * 
+	 * @param propertyChangeListener
+	 *            A {@link PropertyChangeListener} that will be called when
+	 *            {@link #setActiveLang(String)} changes the language.
+	 */
+	public static boolean removeLocaleChangeListener(
+			PropertyChangeListener propertyChangeListener) {
+		return listeners.remove(propertyChangeListener);
+	}
+
+	/**
 	 * Informs all registered {@link PropertyChangeListener}s about a change of
 	 * the the {@link Locale}.
 	 */
@@ -313,7 +335,8 @@
 	 */
 	public void addTranslationChangeListener(ActionListener actionListener) {
 		if (actionListeners.add(actionListener)) {
-			LOGGER.debug("registering a new translationChangeActionListener in the WeakHashSet");
+			LOGGER
+					.debug("registering a new translationChangeActionListener in the WeakHashSet");
 		}
 	}
 

Modified: branches/2.0-RC1/src/skrueger/swing/CancellableDialogAdapter.java
===================================================================
--- branches/2.0-RC1/src/skrueger/swing/CancellableDialogAdapter.java	2009-12-09 14:46:29 UTC (rev 606)
+++ branches/2.0-RC1/src/skrueger/swing/CancellableDialogAdapter.java	2009-12-09 15:13:42 UTC (rev 607)
@@ -7,7 +7,6 @@
 import javax.swing.JDialog;
 import javax.swing.JOptionPane;
 
-import schmitzm.geotools.gui.GeotoolsGUIUtil;
 import schmitzm.lang.LangUtil;
 import schmitzm.lang.ResourceProvider;
 import schmitzm.swing.SwingUtil;

Modified: branches/2.0-RC1/src/skrueger/swing/HeapBar.java
===================================================================
--- branches/2.0-RC1/src/skrueger/swing/HeapBar.java	2009-12-09 14:46:29 UTC (rev 606)
+++ branches/2.0-RC1/src/skrueger/swing/HeapBar.java	2009-12-09 15:13:42 UTC (rev 607)
@@ -9,11 +9,9 @@
 import java.util.TimerTask;
 
 import javax.swing.JProgressBar;
-import javax.swing.SwingUtilities;
 
 import org.apache.log4j.Logger;
 
-import schmitzm.geotools.gui.GeotoolsGUIUtil;
 import schmitzm.lang.LangUtil;
 import schmitzm.lang.ResourceProvider;
 import schmitzm.swing.SwingUtil;

Modified: branches/2.0-RC1/src_junit/skrueger/i8n/SwitchLanguageDialogTest.java
===================================================================
--- branches/2.0-RC1/src_junit/skrueger/i8n/SwitchLanguageDialogTest.java	2009-12-09 14:46:29 UTC (rev 606)
+++ branches/2.0-RC1/src_junit/skrueger/i8n/SwitchLanguageDialogTest.java	2009-12-09 15:13:42 UTC (rev 607)
@@ -39,7 +39,6 @@
 		ArrayList<String> langsa = new ArrayList<String>();
 		langsa.add("fr");
 		langsa.add("tr");
-		SwitchLanguageDialog switchLanguageDialog = new SwitchLanguageDialog(null, langsa);
-		switchLanguageDialog.setVisible(true);
+		new SwitchLanguageDialog(null, langsa);
 	}
 }



More information about the Schmitzm-commits mailing list